VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp@ 101988

最後變更 在這個檔案從101988是 101988,由 vboxsync 提交於 17 月 前

libs/xpcom: Cleanup nsComponentManager.cpp, convert from PR_LOG to IPRT's logging infrastructure, bugref:10545

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 110.2 KB
 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK *****
37 *
38 * This Original Code has been modified by IBM Corporation.
39 * Modifications made by IBM described herein are
40 * Copyright (c) International Business Machines
41 * Corporation, 2000
42 *
43 * Modifications to Mozilla code or documentation
44 * identified per MPL Section 3.3
45 *
46 * Date Modified by Description of modification
47 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
48 */
49#include <stdlib.h>
50#include "nscore.h"
51#include "nsISupports.h"
52#include "nspr.h"
53#include "nsCRT.h" // for atoll
54// Arena used by component manager for storing contractid string, dll
55// location strings and small objects
56// CAUTION: Arena align mask needs to be defined before including plarena.h
57// currently from nsComponentManager.h
58#define PL_ARENA_CONST_ALIGN_MASK 7
59#define NS_CM_BLOCK_SIZE (1024 * 8)
60
61#include "nsAutoLock.h"
62#include "nsCOMPtr.h"
63#include "nsComponentManager.h"
64#include "nsComponentManagerObsolete.h"
65#include "nsDirectoryService.h"
66#include "nsDirectoryServiceDefs.h"
67#include "nsCategoryManager.h"
68#include "nsCategoryManagerUtils.h"
69#include "nsIComponentLoader.h"
70#include "nsIEnumerator.h"
71#include "nsIInterfaceInfoManager.h"
72#include "nsIModule.h"
73#include "nsIObserverService.h"
74#include "nsISimpleEnumerator.h"
75#include "nsXPCOM.h"
76#include "nsISupportsPrimitives.h"
77#include "nsLocalFile.h"
78#include "nsNativeComponentLoader.h"
79#include "nsReadableUtils.h"
80#include "nsString.h"
81#include "nsXPIDLString.h"
82#include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself...
83
84#include "nsInt64.h"
85#include "nsManifestLineReader.h"
86
87#include NEW_H // for placement new
88
89#include <iprt/assert.h>
90#include <VBox/log.h>
91
92// Loader Types
93#define NS_LOADER_DATA_ALLOC_STEP 6
94
95// Bloated registry buffer size to improve startup performance -- needs to
96// be big enough to fit the entire file into memory or it'll thrash.
97// 512K is big enough to allow for some future growth in the registry.
98#define BIG_REGISTRY_BUFLEN (512*1024)
99
100// Common Key Names
101const char classIDKeyName[]="classID";
102const char classesKeyName[]="contractID";
103const char componentLoadersKeyName[]="componentLoaders";
104const char componentsKeyName[]="components";
105const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components";
106const char xpcomKeyName[]="software/mozilla/XPCOM";
107
108// Common Value Names
109const char classIDValueName[]="ClassID";
110const char classNameValueName[]="ClassName";
111const char componentCountValueName[]="ComponentsCount";
112const char componentTypeValueName[]="ComponentType";
113const char contractIDValueName[]="ContractID";
114const char fileSizeValueName[]="FileSize";
115const char inprocServerValueName[]="InprocServer";
116const char lastModValueName[]="LastModTimeStamp";
117const char nativeComponentType[]="application/x-mozilla-native";
118const char staticComponentType[]="application/x-mozilla-static";
119const char versionValueName[]="VersionString";
120
121const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:";
122const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:";
123const static char XPCOM_GRECOMPONENT_PREFIX[] = "gre:";
124
125static const char gIDFormat[] =
126 "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
127
128
129#define NS_EMPTY_IID \
130{ \
131 0x00000000, \
132 0x0000, \
133 0x0000, \
134 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \
135}
136
137NS_DEFINE_CID(kEmptyCID, NS_EMPTY_IID);
138NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
139
140#define UID_STRING_LENGTH 39
141
142// Set to true from NS_ShutdownXPCOM.
143extern PRBool gXPCOMShuttingDown;
144
145static void GetIDString(const nsID& aCID, char buf[UID_STRING_LENGTH])
146{
147 PR_snprintf(buf, UID_STRING_LENGTH, gIDFormat,
148 aCID.m0, (PRUint32) aCID.m1, (PRUint32) aCID.m2,
149 (PRUint32) aCID.m3[0], (PRUint32) aCID.m3[1],
150 (PRUint32) aCID.m3[2], (PRUint32) aCID.m3[3],
151 (PRUint32) aCID.m3[4], (PRUint32) aCID.m3[5],
152 (PRUint32) aCID.m3[6], (PRUint32) aCID.m3[7]);
153}
154
155nsresult
156nsCreateInstanceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
157{
158 /*
159 * If I were a real man, I would consolidate this with
160 * nsGetServiceFromContractID::operator().
161 */
162 nsresult rv;
163 nsXPIDLCString value;
164 nsCOMPtr<nsIComponentManager> compMgr;
165 nsCOMPtr<nsICategoryManager> catman =
166 do_GetService(kCategoryManagerCID, &rv);
167
168 if (NS_FAILED(rv)) goto error;
169
170 if (!mCategory || !mEntry) {
171 // when categories have defaults, use that for null mEntry
172 rv = NS_ERROR_NULL_POINTER;
173 goto error;
174 }
175
176 /* find the contractID for category.entry */
177 rv = catman->GetCategoryEntry(mCategory, mEntry,
178 getter_Copies(value));
179 if (NS_FAILED(rv)) goto error;
180 if (!value) {
181 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
182 goto error;
183 }
184 NS_GetComponentManager(getter_AddRefs(compMgr));
185 if (!compMgr)
186 return NS_ERROR_FAILURE;
187 compMgr->CreateInstanceByContractID(value,
188 mOuter,
189 aIID,
190 aInstancePtr);
191 if (NS_FAILED(rv)) {
192 error:
193 *aInstancePtr = 0;
194 }
195
196 *mErrorPtr = rv;
197 return rv;
198}
199
200
201nsresult
202nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
203{
204 nsresult rv;
205 nsXPIDLCString value;
206 nsCOMPtr<nsICategoryManager> catman =
207 do_GetService(kCategoryManagerCID, &rv);
208 if (NS_FAILED(rv)) goto error;
209 if (!mCategory || !mEntry) {
210 // when categories have defaults, use that for null mEntry
211 rv = NS_ERROR_NULL_POINTER;
212 goto error;
213 }
214 /* find the contractID for category.entry */
215 rv = catman->GetCategoryEntry(mCategory, mEntry,
216 getter_Copies(value));
217 if (NS_FAILED(rv)) goto error;
218 if (!value) {
219 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
220 goto error;
221 }
222 if (mServiceManager) {
223 rv = mServiceManager->GetServiceByContractID(value, aIID, (void**)aInstancePtr);
224 } else {
225 nsCOMPtr<nsIServiceManager> mgr;
226 NS_GetServiceManager(getter_AddRefs(mgr));
227 if (mgr)
228 rv = mgr->GetServiceByContractID(value, aIID, (void**)aInstancePtr);
229 }
230 if (NS_FAILED(rv)) {
231 error:
232 *aInstancePtr = 0;
233 }
234 *mErrorPtr = rv;
235 return rv;
236}
237
238////////////////////////////////////////////////////////////////////////////////
239// Arena helper functions
240////////////////////////////////////////////////////////////////////////////////
241char *
242ArenaStrndup(const char *s, PRUint32 len, PLArenaPool *arena)
243{
244 void *mem;
245 // Include trailing null in the len
246 PL_ARENA_ALLOCATE(mem, arena, len+1);
247 if (mem)
248 memcpy(mem, s, len+1);
249 return NS_STATIC_CAST(char *, mem);
250}
251
252char*
253ArenaStrdup(const char *s, PLArenaPool *arena)
254{
255 return ArenaStrndup(s, strlen(s), arena);
256}
257
258////////////////////////////////////////////////////////////////////////////////
259// Hashtable Callbacks
260////////////////////////////////////////////////////////////////////////////////
261
262PRBool PR_CALLBACK
263nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure);
264
265PR_STATIC_CALLBACK(const void *)
266factory_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
267{
268 nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
269
270 return &entry->mFactoryEntry->mCid;
271}
272
273PR_STATIC_CALLBACK(PLDHashNumber)
274factory_HashKey(PLDHashTable *aTable, const void *aKey)
275{
276 const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey);
277
278 return cidp->m0;
279}
280
281PR_STATIC_CALLBACK(PRBool)
282factory_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr,
283 const void *aKey)
284{
285 const nsFactoryTableEntry* entry =
286 NS_STATIC_CAST(const nsFactoryTableEntry*, aHdr);
287 const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey);
288
289 return (entry->mFactoryEntry->mCid).Equals(*cidp);
290}
291
292PR_STATIC_CALLBACK(void)
293factory_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
294{
295 nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
296 // nsFactoryEntry is arena allocated. So we dont delete it.
297 // We call the destructor by hand.
298 entry->mFactoryEntry->~nsFactoryEntry();
299 PL_DHashClearEntryStub(aTable, aHdr);
300}
301
302static const PLDHashTableOps factory_DHashTableOps = {
303 PL_DHashAllocTable,
304 PL_DHashFreeTable,
305 factory_GetKey,
306 factory_HashKey,
307 factory_MatchEntry,
308 PL_DHashMoveEntryStub,
309 factory_ClearEntry,
310 PL_DHashFinalizeStub,
311};
312
313PR_STATIC_CALLBACK(void)
314contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
315{
316 nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
317 if (entry->mFactoryEntry->mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY &&
318 entry->mFactoryEntry->mCid.Equals(kEmptyCID)) {
319 // this object is owned by the hash.
320 // nsFactoryEntry is arena allocated. So we dont delete it.
321 // We call the destructor by hand.
322 entry->mFactoryEntry->~nsFactoryEntry();
323 }
324
325 // contractIDs are arena allocated. No need to free them.
326
327 PL_DHashClearEntryStub(aTable, aHdr);
328}
329
330static const PLDHashTableOps contractID_DHashTableOps = {
331 PL_DHashAllocTable,
332 PL_DHashFreeTable,
333 PL_DHashGetKeyStub,
334 PL_DHashStringKey,
335 PL_DHashMatchStringKey,
336 PL_DHashMoveEntryStub,
337 contractID_ClearEntry,
338 PL_DHashFinalizeStub,
339};
340
341////////////////////////////////////////////////////////////////////////////////
342// nsFactoryEntry
343////////////////////////////////////////////////////////////////////////////////
344
345MOZ_DECL_CTOR_COUNTER(nsFactoryEntry)
346nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
347 const char *aLocation,
348 PRUint32 locationlen,
349 int aType,
350 class nsFactoryEntry* parent)
351: mCid(aClass), mTypeIndex(aType), mParent(parent)
352{
353 // Arena allocate the location string
354 mLocation = ArenaStrndup(aLocation, locationlen, &nsComponentManagerImpl::gComponentManager->mArena);
355}
356
357nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
358 nsIFactory *aFactory,
359 class nsFactoryEntry* parent)
360: mCid(aClass), mTypeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY), mParent(parent)
361{
362 mFactory = aFactory;
363 mLocation = nsnull;
364}
365
366// nsFactoryEntry is usually arena allocated including the strings it
367// holds. So we call destructor by hand.
368nsFactoryEntry::~nsFactoryEntry(void)
369{
370 // Release the reference to the factory
371 mFactory = nsnull;
372
373 // Release any service reference
374 mServiceObject = nsnull;
375
376 // nsFactoryEntry is arena allocated. So we dont delete it.
377 // We call the destructor by hand.
378 if (mParent)
379 mParent->~nsFactoryEntry();
380}
381
382nsresult
383nsFactoryEntry::ReInit(const nsCID &aClass, const char *aLocation, int aType)
384{
385 NS_ENSURE_TRUE(mTypeIndex != NS_COMPONENT_TYPE_FACTORY_ONLY, NS_ERROR_INVALID_ARG);
386 // cid has to match
387 // SERVICE_ONLY entries can be promoted to an entry of another type
388 NS_ENSURE_TRUE((mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || mCid.Equals(aClass)),
389 NS_ERROR_INVALID_ARG);
390
391 // Arena allocate the location string
392 mLocation = ArenaStrdup(aLocation, &nsComponentManagerImpl::gComponentManager->mArena);
393
394 mTypeIndex = aType;
395 return NS_OK;
396}
397
398////////////////////////////////////////////////////////////////////////////////
399// Hashtable Enumeration
400////////////////////////////////////////////////////////////////////////////////
401typedef NS_CALLBACK(EnumeratorConverter)(PLDHashTable *table,
402 const PLDHashEntryHdr *hdr,
403 void *data,
404 nsISupports **retval);
405
406class PLDHashTableEnumeratorImpl : public nsIBidirectionalEnumerator,
407 public nsISimpleEnumerator
408{
409public:
410 NS_DECL_ISUPPORTS
411 NS_DECL_NSIENUMERATOR
412 NS_DECL_NSIBIDIRECTIONALENUMERATOR
413 NS_DECL_NSISIMPLEENUMERATOR
414
415 PLDHashTableEnumeratorImpl(PLDHashTable *table,
416 EnumeratorConverter converter,
417 void *converterData);
418 PRInt32 Count() { return mCount; }
419private:
420 PLDHashTableEnumeratorImpl(); /* no implementation */
421
422 ~PLDHashTableEnumeratorImpl();
423 NS_IMETHODIMP ReleaseElements();
424
425 nsVoidArray mElements;
426 PRInt32 mCount, mCurrent;
427 PRMonitor* mMonitor;
428
429 struct Closure {
430 PRBool succeeded;
431 EnumeratorConverter converter;
432 void *data;
433 PLDHashTableEnumeratorImpl *impl;
434 };
435
436 static PLDHashOperator PR_CALLBACK Enumerator(PLDHashTable *table,
437 PLDHashEntryHdr *hdr,
438 PRUint32 number,
439 void *data);
440};
441
442// static
443PLDHashOperator PR_CALLBACK
444PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable *table,
445 PLDHashEntryHdr *hdr,
446 PRUint32 number,
447 void *data)
448{
449 Closure *c = NS_REINTERPRET_CAST(Closure *, data);
450 nsISupports *converted;
451 if (NS_FAILED(c->converter(table, hdr, c->data, &converted)) ||
452 !c->impl->mElements.AppendElement(converted)) {
453 c->succeeded = PR_FALSE;
454 return PL_DHASH_STOP;
455 }
456
457 c->succeeded = PR_TRUE;
458 return PL_DHASH_NEXT;
459}
460
461PLDHashTableEnumeratorImpl::PLDHashTableEnumeratorImpl(PLDHashTable *table,
462 EnumeratorConverter converter,
463 void *converterData)
464: mCurrent(0)
465{
466 mMonitor = nsAutoMonitor::NewMonitor("PLDHashTableEnumeratorImpl");
467 NS_ASSERTION(mMonitor, "NULL Monitor");
468
469 nsAutoMonitor mon(mMonitor);
470
471 Closure c = { PR_FALSE, converter, converterData, this };
472 mCount = PL_DHashTableEnumerate(table, Enumerator, &c);
473 if (!c.succeeded) {
474 ReleaseElements();
475 mCount = 0;
476 }
477}
478
479NS_IMPL_ISUPPORTS3(PLDHashTableEnumeratorImpl,
480 nsIBidirectionalEnumerator,
481 nsIEnumerator,
482 nsISimpleEnumerator)
483
484PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl()
485{
486 (void) ReleaseElements();
487
488 // Destroy the Lock
489 if (mMonitor)
490 nsAutoMonitor::DestroyMonitor(mMonitor);
491}
492
493NS_IMETHODIMP
494PLDHashTableEnumeratorImpl::ReleaseElements()
495{
496 for (PRInt32 i = 0; i < mCount; i++) {
497 nsISupports *supports = NS_REINTERPRET_CAST(nsISupports *,
498 mElements[i]);
499 NS_IF_RELEASE(supports);
500 }
501 return NS_OK;
502}
503
504NS_IMETHODIMP
505PL_NewDHashTableEnumerator(PLDHashTable *table,
506 EnumeratorConverter converter,
507 void *converterData,
508 PLDHashTableEnumeratorImpl **retval)
509{
510 PLDHashTableEnumeratorImpl *impl =
511 new PLDHashTableEnumeratorImpl(table, converter, converterData);
512
513 if (!impl)
514 return NS_ERROR_OUT_OF_MEMORY;
515
516 NS_ADDREF(impl);
517
518 if (impl->Count() == -1) {
519 // conversion failed
520 NS_RELEASE(impl);
521 return NS_ERROR_FAILURE;
522 }
523
524 *retval = impl;
525 return NS_OK;
526}
527
528NS_IMETHODIMP
529PLDHashTableEnumeratorImpl::First()
530{
531 if (!mCount)
532 return NS_ERROR_FAILURE;
533
534 mCurrent = 0;
535 return NS_OK;
536}
537
538NS_IMETHODIMP
539PLDHashTableEnumeratorImpl::Last()
540{
541 if (!mCount)
542 return NS_ERROR_FAILURE;
543 mCurrent = mCount - 1;
544 return NS_OK;
545}
546
547NS_IMETHODIMP
548PLDHashTableEnumeratorImpl::Prev()
549{
550 if (!mCurrent)
551 return NS_ERROR_FAILURE;
552
553 mCurrent--;
554 return NS_OK;
555}
556
557NS_IMETHODIMP
558PLDHashTableEnumeratorImpl::Next()
559{
560 // If empty or we're past the end, or we are at the end return error
561 if (!mCount || (mCurrent == mCount) || (++mCurrent == mCount))
562 return NS_ERROR_FAILURE;
563
564 return NS_OK;
565}
566
567NS_IMETHODIMP
568PLDHashTableEnumeratorImpl::CurrentItem(nsISupports **retval)
569{
570 if (!mCount || mCurrent == mCount)
571 return NS_ERROR_FAILURE;
572
573 *retval = NS_REINTERPRET_CAST(nsISupports *, mElements[mCurrent]);
574 if (*retval)
575 NS_ADDREF(*retval);
576
577 return NS_OK;
578}
579
580NS_IMETHODIMP
581PLDHashTableEnumeratorImpl::IsDone()
582{
583 if (!mCount || (mCurrent == mCount))
584 return NS_OK;
585
586 return NS_ENUMERATOR_FALSE;
587}
588
589NS_IMETHODIMP
590PLDHashTableEnumeratorImpl::HasMoreElements(PRBool *_retval)
591{
592 if (!mCount || (mCurrent == mCount))
593 *_retval = PR_FALSE;
594 else
595 *_retval = PR_TRUE;
596
597 return NS_OK;
598}
599
600NS_IMETHODIMP
601PLDHashTableEnumeratorImpl::GetNext(nsISupports **_retval)
602{
603 nsresult rv = Next();
604 if (NS_FAILED(rv)) return rv;
605
606 return CurrentItem(_retval);
607}
608
609static NS_IMETHODIMP
610ConvertFactoryEntryToCID(PLDHashTable *table,
611 const PLDHashEntryHdr *hdr,
612 void *data, nsISupports **retval)
613{
614 nsresult rv;
615 nsCOMPtr<nsISupportsID> wrapper;
616
617 nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data);
618
619 rv = cm->CreateInstanceByContractID(NS_SUPPORTS_ID_CONTRACTID, nsnull,
620 NS_GET_IID(nsISupportsID), getter_AddRefs(wrapper));
621
622 NS_ENSURE_SUCCESS(rv, rv);
623
624 const nsFactoryTableEntry *entry =
625 NS_REINTERPRET_CAST(const nsFactoryTableEntry *, hdr);
626 if (entry) {
627 nsFactoryEntry *fe = entry->mFactoryEntry;
628
629 wrapper->SetData(&fe->mCid);
630 *retval = wrapper;
631 NS_ADDREF(*retval);
632 return NS_OK;
633 }
634 *retval = nsnull;
635
636 return rv;
637}
638
639static NS_IMETHODIMP
640ConvertContractIDKeyToString(PLDHashTable *table,
641 const PLDHashEntryHdr *hdr,
642 void *data, nsISupports **retval)
643{
644 nsresult rv;
645 nsCOMPtr<nsISupportsCString> wrapper;
646
647 nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data);
648
649 rv = cm->CreateInstanceByContractID(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull,
650 NS_GET_IID(nsISupportsCString), getter_AddRefs(wrapper));
651
652 NS_ENSURE_SUCCESS(rv, rv);
653
654 const nsContractIDTableEntry *entry =
655 NS_REINTERPRET_CAST(const nsContractIDTableEntry *, hdr);
656
657 wrapper->SetData(nsDependentCString(entry->mContractID,
658 entry->mContractIDLen));
659 *retval = wrapper;
660 NS_ADDREF(*retval);
661 return NS_OK;
662}
663
664// this is safe to call during InitXPCOM
665static nsresult GetLocationFromDirectoryService(const char* prop,
666 nsIFile** aDirectory)
667{
668 nsCOMPtr<nsIProperties> directoryService;
669 nsDirectoryService::Create(nsnull,
670 NS_GET_IID(nsIProperties),
671 getter_AddRefs(directoryService));
672
673 if (!directoryService)
674 return NS_ERROR_FAILURE;
675
676 return directoryService->Get(prop,
677 NS_GET_IID(nsIFile),
678 (void**)aDirectory);
679}
680
681
682////////////////////////////////////////////////////////////////////////////////
683// nsComponentManagerImpl
684////////////////////////////////////////////////////////////////////////////////
685
686
687nsComponentManagerImpl::nsComponentManagerImpl()
688 :
689 mMon(NULL),
690 mNativeComponentLoader(0),
691#ifdef ENABLE_STATIC_COMPONENT_LOADER
692 mStaticComponentLoader(0),
693#endif
694 mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED),
695 mLoaderData(nsnull),
696 mRegistryDirty(PR_FALSE)
697{
698 mFactories.ops = nsnull;
699 mContractIDs.ops = nsnull;
700}
701
702nsresult nsComponentManagerImpl::Init(void)
703{
704 Assert(mShuttingDown != NS_SHUTDOWN_INPROGRESS);
705 if (mShuttingDown == NS_SHUTDOWN_INPROGRESS)
706 return NS_ERROR_FAILURE;
707
708 mShuttingDown = NS_SHUTDOWN_NEVERHAPPENED;
709
710 // Initialize our arena
711 PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
712
713 if (!mFactories.ops) {
714 if (!PL_DHashTableInit(&mFactories, &factory_DHashTableOps,
715 0, sizeof(nsFactoryTableEntry),
716 1024)) {
717 mFactories.ops = nsnull;
718 return NS_ERROR_OUT_OF_MEMORY;
719 }
720
721 // Minimum alpha uses k=2 because nsFactoryTableEntry saves two
722 // words compared to what a chained hash table requires.
723 PL_DHashTableSetAlphaBounds(&mFactories,
724 0.875,
725 PL_DHASH_MIN_ALPHA(&mFactories, 2));
726 }
727
728 if (!mContractIDs.ops) {
729 if (!PL_DHashTableInit(&mContractIDs, &contractID_DHashTableOps,
730 0, sizeof(nsContractIDTableEntry),
731 1024)) {
732 mContractIDs.ops = nsnull;
733 return NS_ERROR_OUT_OF_MEMORY;
734 }
735
736 // Minimum alpha uses k=1 because nsContractIDTableEntry saves one
737 // word compared to what a chained hash table requires.
738#if 0
739 PL_DHashTableSetAlphaBounds(&mContractIDs,
740 0.875,
741 PL_DHASH_MIN_ALPHA(&mContractIDs, 1));
742#endif
743 }
744 if (mMon == nsnull) {
745 mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl");
746 if (mMon == nsnull)
747 return NS_ERROR_OUT_OF_MEMORY;
748 }
749
750 if (mNativeComponentLoader == nsnull) {
751 /* Create the NativeComponentLoader */
752 mNativeComponentLoader = new nsNativeComponentLoader();
753 if (!mNativeComponentLoader)
754 return NS_ERROR_OUT_OF_MEMORY;
755 NS_ADDREF(mNativeComponentLoader);
756
757 nsresult rv = mNativeComponentLoader->Init(this, nsnull);
758 if (NS_FAILED(rv))
759 return rv;
760 }
761
762 // Add predefined loaders
763 mLoaderData = (nsLoaderdata *) PR_Malloc(sizeof(nsLoaderdata) * NS_LOADER_DATA_ALLOC_STEP);
764 if (!mLoaderData)
765 return NS_ERROR_OUT_OF_MEMORY;
766 mMaxNLoaderData = NS_LOADER_DATA_ALLOC_STEP;
767
768 mNLoaderData = NS_COMPONENT_TYPE_NATIVE;
769 mLoaderData[mNLoaderData].type = PL_strdup(nativeComponentType);
770 mLoaderData[mNLoaderData].loader = mNativeComponentLoader;
771 NS_ADDREF(mLoaderData[mNLoaderData].loader);
772 mNLoaderData++;
773
774#ifdef ENABLE_STATIC_COMPONENT_LOADER
775 if (mStaticComponentLoader == nsnull) {
776 extern nsresult NS_NewStaticComponentLoader(nsIComponentLoader **);
777 NS_NewStaticComponentLoader(&mStaticComponentLoader);
778 if (!mStaticComponentLoader)
779 return NS_ERROR_OUT_OF_MEMORY;
780 }
781
782 mLoaderData[mNLoaderData].type = PL_strdup(staticComponentType);
783 mLoaderData[mNLoaderData].loader = mStaticComponentLoader;
784 NS_ADDREF(mLoaderData[mNLoaderData].loader);
785 mNLoaderData++;
786
787 if (mStaticComponentLoader) {
788 /* Init the static loader */
789 mStaticComponentLoader->Init(this, nsnull);
790 }
791#endif
792 GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_DIR, getter_AddRefs(mComponentsDir));
793 if (!mComponentsDir)
794 return NS_ERROR_OUT_OF_MEMORY;
795
796 nsCAutoString componentDescriptor;
797 nsresult rv = mComponentsDir->GetNativePath(componentDescriptor);
798 if (NS_FAILED(rv))
799 return rv;
800
801 mComponentsOffset = componentDescriptor.Length();
802
803 GetLocationFromDirectoryService(NS_GRE_COMPONENT_DIR, getter_AddRefs(mGREComponentsDir));
804 if (mGREComponentsDir) {
805 nsresult rv = mGREComponentsDir->GetNativePath(componentDescriptor);
806 if (NS_FAILED(rv)) {
807 NS_WARNING("No GRE component manager");
808 return rv;
809 }
810 mGREComponentsOffset = componentDescriptor.Length();
811 }
812
813 GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_REGISTRY_FILE,
814 getter_AddRefs(mRegistryFile));
815
816 if(!mRegistryFile) {
817 NS_WARNING("No Component Registry file was found in the directory service");
818 return NS_ERROR_FAILURE;
819 }
820
821 Log(("nsComponentManager: Initialized.\n"));
822 return NS_OK;
823}
824
825PRIntn PR_CALLBACK AutoRegEntryDestroy(nsHashKey *aKey, void *aData, void* aClosure)
826{
827 delete (AutoRegEntry*)aData;
828 return kHashEnumerateNext;
829}
830
831nsresult nsComponentManagerImpl::Shutdown(void)
832{
833 Assert(mShuttingDown == NS_SHUTDOWN_NEVERHAPPENED);
834 if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED)
835 return NS_ERROR_FAILURE;
836
837 mShuttingDown = NS_SHUTDOWN_INPROGRESS;
838
839 // Shutdown the component manager
840 Log(("nsComponentManager: Beginning Shutdown.\n"));
841
842 PRInt32 i;
843
844 // Write out our component data file.
845 if (mRegistryDirty) {
846 nsresult rv = WritePersistentRegistry();
847 if (NS_FAILED(rv)) {
848 Log(("nsComponentManager: Could not write out perisistant registry.\n"));
849 }
850 }
851
852 mAutoRegEntries.Reset(AutoRegEntryDestroy);
853
854 // Release all cached factories
855 if (mContractIDs.ops) {
856 PL_DHashTableFinish(&mContractIDs);
857 mContractIDs.ops = nsnull;
858 }
859 if (mFactories.ops) {
860 PL_DHashTableFinish(&mFactories);
861 mFactories.ops = nsnull;
862 }
863 // Unload libraries
864 UnloadLibraries(nsnull, NS_Shutdown);
865
866 // delete arena for strings and small objects
867 PL_FinishArenaPool(&mArena);
868
869 mComponentsDir = 0;
870
871 mCategoryManager = 0;
872
873 // Release all the component data - loaders and type strings
874 for (i=0; i < mNLoaderData; i++) {
875 NS_IF_RELEASE(mLoaderData[i].loader);
876 PL_strfree((char *)mLoaderData[i].type);
877 }
878 PR_Free(mLoaderData);
879 mLoaderData = nsnull;
880
881 // we have an extra reference on this one, which is probably a good thing
882 NS_IF_RELEASE(mNativeComponentLoader);
883#ifdef ENABLE_STATIC_COMPONENT_LOADER
884 NS_IF_RELEASE(mStaticComponentLoader);
885#endif
886
887 mShuttingDown = NS_SHUTDOWN_COMPLETE;
888
889 Log(("nsComponentManager: Shutdown complete.\n"));
890 return NS_OK;
891}
892
893nsComponentManagerImpl::~nsComponentManagerImpl()
894{
895 Log(("nsComponentManager: Beginning destruction.\n"));
896 if (mShuttingDown != NS_SHUTDOWN_COMPLETE)
897 Shutdown();
898
899 if (mMon) {
900 nsAutoMonitor::DestroyMonitor(mMon);
901 }
902 Log(("nsComponentManager: Destroyed.\n"));
903}
904
905NS_IMPL_THREADSAFE_ISUPPORTS8(nsComponentManagerImpl,
906 nsIComponentManager,
907 nsIServiceManager,
908 nsISupportsWeakReference,
909 nsIInterfaceRequestor,
910 nsIComponentRegistrar,
911 nsIServiceManagerObsolete,
912 nsIComponentManagerObsolete,
913 nsIComponentLoaderManager)
914
915
916nsresult
917nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
918{
919 if (uuid.Equals(NS_GET_IID(nsINativeComponentLoader)))
920 {
921 if (!mNativeComponentLoader)
922 return NS_ERROR_NOT_INITIALIZED;
923
924 return mNativeComponentLoader->QueryInterface(uuid, result);
925 }
926
927 NS_WARNING("This isn't supported");
928 // fall through to QI as anything QIable is a superset of what can be
929 // got via the GetInterface()
930 return QueryInterface(uuid, result);
931}
932
933////////////////////////////////////////////////////////////////////////////////
934// nsComponentManagerImpl: Platform methods
935////////////////////////////////////////////////////////////////////////////////
936
937#define PERSISTENT_REGISTRY_VERSION_MINOR 5
938#define PERSISTENT_REGISTRY_VERSION_MAJOR 0
939
940
941AutoRegEntry::AutoRegEntry(const nsACString& name, PRInt64* modDate) :
942 mName(ToNewCString(name)),
943 mNameLen(name.Length()),
944 mData(nsnull),
945 mModDate(*modDate)
946{
947}
948
949AutoRegEntry::~AutoRegEntry()
950{
951 if (mName) PL_strfree(mName);
952 if (mData) PL_strfree(mData);
953}
954
955PRBool
956AutoRegEntry::Modified(PRInt64 *date)
957{
958 return !LL_EQ(*date, mModDate);
959}
960
961void
962AutoRegEntry::SetOptionalData(const char* data)
963{
964 if (mData)
965 PL_strfree(mData);
966
967 if (!data) {
968 mData = nsnull;
969 return;
970 }
971
972 mData = PL_strdup(data);
973}
974
975static
976PRBool ReadSectionHeader(nsManifestLineReader& reader, const char *token)
977{
978 while (1)
979 {
980 if (*reader.LinePtr() == '[')
981 {
982 char* p = reader.LinePtr() + (reader.LineLength() - 1);
983 if (*p != ']')
984 break;
985 *p = 0;
986
987 char* values[1];
988 int lengths[1];
989 if (2 != reader.ParseLine(values, lengths, 1))
990 break;
991
992 // ignore the leading '['
993 if (0 != PL_strcmp(values[0]+1, token))
994 break;
995
996 return PR_TRUE;
997 }
998
999 if (!reader.NextLine())
1000 break;
1001 }
1002 return PR_FALSE;
1003}
1004
1005nsresult
1006nsComponentManagerImpl::ReadPersistentRegistry()
1007{
1008
1009 // populate Category Manager. need to get this early so that we don't get
1010 // skipped by 'goto out'
1011 nsresult rv = GetService(kCategoryManagerCID,
1012 NS_GET_IID(nsICategoryManager),
1013 getter_AddRefs(mCategoryManager));
1014 if (NS_FAILED(rv))
1015 return rv;
1016
1017 nsAutoMonitor mon(mMon);
1018 nsManifestLineReader reader;
1019
1020 if (!mComponentsDir)
1021 return NS_ERROR_NOT_INITIALIZED; // this should have been set by Init().
1022
1023 PRFileDesc* fd = nsnull;
1024
1025 // Set From Init
1026 if (!mRegistryFile) {
1027 return NS_ERROR_FILE_NOT_FOUND;
1028 }
1029
1030 nsCOMPtr<nsIFile> file;
1031 mRegistryFile->Clone(getter_AddRefs(file));
1032 if (!file)
1033 return NS_ERROR_OUT_OF_MEMORY;
1034
1035 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
1036
1037 rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
1038 if (NS_FAILED(rv))
1039 return rv;
1040
1041 PRInt64 fileSize;
1042 rv = localFile->GetFileSize(&fileSize);
1043 if (NS_FAILED(rv))
1044 {
1045 PR_Close(fd);
1046 return rv;
1047 }
1048
1049 PRInt32 flen = nsInt64(fileSize);
1050 if (flen == 0)
1051 {
1052 PR_Close(fd);
1053 NS_WARNING("Persistent Registry Empty!");
1054 return NS_OK; // ERROR CONDITION
1055 }
1056
1057 char* registry = new char[flen+1];
1058 if (!registry)
1059 goto out;
1060
1061 if (flen > PR_Read(fd, registry, flen))
1062 {
1063 rv = NS_ERROR_FAILURE;
1064 goto out;
1065 }
1066 registry[flen] = '\0';
1067
1068 reader.Init(registry, flen);
1069
1070 if (ReadSectionHeader(reader, "HEADER"))
1071 goto out;
1072
1073 if (!reader.NextLine())
1074 goto out;
1075
1076 char* values[6];
1077 int lengths[6];
1078
1079 // VersionLiteral,major,minor
1080 if (3 != reader.ParseLine(values, lengths, 3))
1081 goto out;
1082
1083 // VersionLiteral
1084 if (!nsDependentCString(values[0], lengths[0]).EqualsLiteral("Version"))
1085 goto out;
1086
1087 // major
1088 if (PERSISTENT_REGISTRY_VERSION_MAJOR != atoi(values[1]))
1089 goto out;
1090
1091 // minor
1092 if (PERSISTENT_REGISTRY_VERSION_MINOR != atoi(values[2]))
1093 goto out;
1094
1095 if (ReadSectionHeader(reader, "COMPONENTS"))
1096 goto out;
1097
1098 while (1)
1099 {
1100 if (!reader.NextLine())
1101 break;
1102
1103 //name,last_modification_date[,optionaldata]
1104 int parts = reader.ParseLine(values, lengths, 3);
1105 if (2 > parts)
1106 break;
1107
1108 PRInt64 a = nsCRT::atoll(values[1]);
1109 AutoRegEntry *entry =
1110 new AutoRegEntry(nsDependentCString(values[0], lengths[0]), &a);
1111
1112 if (!entry)
1113 return NS_ERROR_OUT_OF_MEMORY;
1114
1115 if (parts == 3)
1116 entry->SetOptionalData(values[2]);
1117
1118 nsCStringKey key((const char*)values[0]);
1119 mAutoRegEntries.Put(&key, entry);
1120 }
1121
1122 if (ReadSectionHeader(reader, "CLASSIDS"))
1123 goto out;
1124
1125 while (1)
1126 {
1127 if (!reader.NextLine())
1128 break;
1129
1130 // cid,contract_id,type,class_name,inproc_server
1131 if (5 != reader.ParseLine(values, lengths, 5))
1132 break;
1133
1134 nsCID aClass;
1135 if (!aClass.Parse(values[0]))
1136 continue;
1137
1138 int loadertype = GetLoaderType(values[2]);
1139 if (loadertype < 0) {
1140 rv = AddLoaderType(values[2], &loadertype);
1141 if (NS_FAILED(rv))
1142 continue;
1143 }
1144
1145 void *mem;
1146 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
1147 if (!mem)
1148 return NS_ERROR_OUT_OF_MEMORY;
1149
1150 nsFactoryEntry *entry = new (mem) nsFactoryEntry(aClass, values[4], lengths[4], loadertype);
1151
1152 nsFactoryTableEntry* factoryTableEntry =
1153 NS_STATIC_CAST(nsFactoryTableEntry*,
1154 PL_DHashTableOperate(&mFactories,
1155 &aClass,
1156 PL_DHASH_ADD));
1157
1158 if (!factoryTableEntry)
1159 return NS_ERROR_OUT_OF_MEMORY;
1160
1161 factoryTableEntry->mFactoryEntry = entry;
1162
1163 }
1164
1165 if (ReadSectionHeader(reader, "CONTRACTIDS"))
1166 goto out;
1167
1168 while (1)
1169 {
1170 if (!reader.NextLine())
1171 break;
1172
1173 //contractID,cid
1174 if (2 != reader.ParseLine(values, lengths, 2))
1175 break;
1176
1177 nsCID aClass;
1178 if (!aClass.Parse(values[1]))
1179 continue;
1180
1181
1182 //need to find the location for this cid.
1183 nsFactoryEntry *cidEntry = GetFactoryEntry(aClass);
1184 if (!cidEntry || cidEntry->mTypeIndex < 0)
1185 continue; //what should we really do?
1186
1187 nsContractIDTableEntry* contractIDTableEntry =
1188 NS_STATIC_CAST(nsContractIDTableEntry*,
1189 PL_DHashTableOperate(&mContractIDs,
1190 values[0],
1191 PL_DHASH_ADD));
1192 if (!contractIDTableEntry) {
1193 continue;
1194 }
1195
1196 if (!contractIDTableEntry->mContractID) {
1197 contractIDTableEntry->mContractID = ArenaStrndup(values[0], lengths[0], &mArena);
1198 contractIDTableEntry->mContractIDLen = lengths[0];
1199 }
1200
1201 contractIDTableEntry->mFactoryEntry = cidEntry;
1202 }
1203
1204#ifdef XPCOM_CHECK_PENDING_CIDS
1205 {
1206/*
1207 * If you get Asserts when you define SHOW_CI_ON_EXISTING_SERVICE and want to
1208 * track down their cause, then you should add the contracts listed by the
1209 * assertion to abusedContracts. The next time you run your xpcom app, xpcom
1210 * will assert the first time the object associated with the contract is
1211 * instantiated (which in many cases is the source of the problem).
1212 *
1213 * If you're doing this then you might want to NOP and soft breakpoint the
1214 * lines labeled: NOP_AND_BREAK.
1215 *
1216 * Otherwise XPCOM will refuse to create the object for the caller, which
1217 * while reasonable at some level, will almost certainly cause the app to
1218 * stop functioning normally.
1219 */
1220 static char abusedContracts[][128] = {
1221 /*// Example contracts:
1222 "@mozilla.org/rdf/container;1",
1223 "@mozilla.org/intl/charsetalias;1",
1224 "@mozilla.org/locale/win32-locale;1",
1225 "@mozilla.org/widget/lookandfeel/win;1",
1226 // */
1227 { 0 }
1228 };
1229 for (int i=0; abusedContracts[i] && *abusedContracts[i]; i++) {
1230 nsFactoryEntry *entry = nsnull;
1231 nsContractIDTableEntry* contractIDTableEntry =
1232 NS_STATIC_CAST(nsContractIDTableEntry*,
1233 PL_DHashTableOperate(&mContractIDs, abusedContracts[i],
1234 PL_DHASH_LOOKUP));
1235
1236 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
1237 entry = contractIDTableEntry->mFactoryEntry;
1238 AddPendingCID(entry->mCid);
1239 }
1240 }
1241 }
1242#endif
1243
1244 if (ReadSectionHeader(reader, "CATEGORIES"))
1245 goto out;
1246
1247 while (1)
1248 {
1249 if (!reader.NextLine())
1250 break;
1251
1252 //type,name,value
1253 if (3 != reader.ParseLine(values, lengths, 3))
1254 break;
1255
1256 mCategoryManager->AddCategoryEntry(values[0],
1257 values[1],
1258 values[2],
1259 PR_TRUE,
1260 PR_TRUE,
1261 0);
1262 }
1263
1264 mRegistryDirty = PR_FALSE;
1265out:
1266 if (fd)
1267 PR_Close(fd);
1268
1269 if (registry)
1270 delete [] registry;
1271
1272 return rv;
1273}
1274
1275struct PersistentWriterArgs
1276{
1277 PRFileDesc *mFD;
1278 nsLoaderdata *mLoaderData;
1279};
1280
1281PR_STATIC_CALLBACK(PLDHashOperator)
1282ContractIDWriter(PLDHashTable *table,
1283 PLDHashEntryHdr *hdr,
1284 PRUint32 number,
1285 void *arg)
1286{
1287 char *contractID = ((nsContractIDTableEntry*)hdr)->mContractID;
1288 nsFactoryEntry *factoryEntry = ((nsContractIDTableEntry*)hdr)->mFactoryEntry;
1289
1290 // for now, we only save out the top most parent.
1291 while (factoryEntry->mParent)
1292 factoryEntry = factoryEntry->mParent;
1293
1294 if (factoryEntry->mTypeIndex < 0)
1295 return PL_DHASH_NEXT;
1296
1297 PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
1298
1299 char cidString[UID_STRING_LENGTH];
1300 GetIDString(factoryEntry->mCid, cidString);
1301 PR_fprintf(fd, "%s,%s\n", contractID, cidString); // what if this fails?
1302 return PL_DHASH_NEXT;
1303}
1304
1305PR_STATIC_CALLBACK(PLDHashOperator)
1306ClassIDWriter(PLDHashTable *table,
1307 PLDHashEntryHdr *hdr,
1308 PRUint32 number,
1309 void *arg)
1310{
1311 nsFactoryEntry *factoryEntry = ((nsFactoryTableEntry*)hdr)->mFactoryEntry;
1312 PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
1313 nsLoaderdata *loaderData = ((PersistentWriterArgs*)arg)->mLoaderData;
1314
1315 // for now, we only save out the top most parent.
1316 while (factoryEntry->mParent)
1317 factoryEntry = factoryEntry->mParent;
1318
1319 if (factoryEntry->mTypeIndex < 0) {
1320 return PL_DHASH_NEXT;
1321 }
1322
1323 char cidString[UID_STRING_LENGTH];
1324 GetIDString(factoryEntry->mCid, cidString);
1325
1326 char *contractID = nsnull, *className = nsnull;
1327
1328 nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(factoryEntry->mFactory);
1329 if (classInfo)
1330 {
1331 classInfo->GetContractID(&contractID);
1332 classInfo->GetClassDescription(&className);
1333 }
1334
1335 const char * loaderName = nsnull;
1336 if (factoryEntry->mTypeIndex)
1337 loaderName = loaderData[factoryEntry->mTypeIndex].type;
1338
1339 char* location = factoryEntry->mLocation;
1340
1341 // cid,contract_id,type,class_name,inproc_server
1342 PR_fprintf(fd,
1343 "%s,%s,%s,%s,%s\n",
1344 cidString,
1345 (contractID ? contractID : ""),
1346 (loaderName ? loaderName : ""),
1347 (className ? className : ""),
1348 (location ? location : ""));
1349
1350 if (contractID)
1351 PR_Free(contractID);
1352 if (className)
1353 PR_Free(className);
1354
1355 return PL_DHASH_NEXT;
1356}
1357
1358PRIntn PR_CALLBACK
1359AutoRegEntryWriter(nsHashKey *aKey, void *aData, void* aClosure)
1360{
1361 PRFileDesc* fd = (PRFileDesc*) aClosure;
1362 AutoRegEntry* entry = (AutoRegEntry*) aData;
1363
1364 const char* extraData = entry->GetOptionalData();
1365 const char *fmt;
1366 if (extraData)
1367 fmt = "%s,%lld,%s\n";
1368 else
1369 fmt = "%s,%lld\n";
1370 PR_fprintf(fd, fmt, entry->GetName().get(), entry->GetDate(), extraData);
1371
1372 return PR_TRUE;
1373}
1374
1375nsresult
1376nsComponentManagerImpl::WritePersistentRegistry()
1377{
1378 if (!mRegistryFile)
1379 return NS_ERROR_FAILURE; // this should have been set by Init().
1380
1381 nsCOMPtr<nsIFile> file;
1382 mRegistryFile->Clone(getter_AddRefs(file));
1383 if (!file)
1384 return NS_ERROR_OUT_OF_MEMORY;
1385
1386 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
1387
1388 nsCAutoString originalLeafName;
1389 localFile->GetNativeLeafName(originalLeafName);
1390
1391 nsCAutoString leafName;
1392 leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp"));
1393
1394 localFile->SetNativeLeafName(leafName);
1395
1396 PRFileDesc* fd = nsnull;
1397 nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
1398 if (NS_FAILED(rv))
1399 return rv;
1400
1401 if (PR_fprintf(fd, "Generated File. Do not edit.\n") == (PRUint32) -1) {
1402 rv = NS_ERROR_UNEXPECTED;
1403 goto out;
1404 }
1405
1406 if (PR_fprintf(fd, "\n[HEADER]\nVersion,%d,%d\n",
1407 PERSISTENT_REGISTRY_VERSION_MAJOR,
1408 PERSISTENT_REGISTRY_VERSION_MINOR) == (PRUint32) -1) {
1409 rv = NS_ERROR_UNEXPECTED;
1410 goto out;
1411 }
1412
1413 if (PR_fprintf(fd, "\n[COMPONENTS]\n") == (PRUint32) -1) {
1414 rv = NS_ERROR_UNEXPECTED;
1415 goto out;
1416 }
1417
1418 mAutoRegEntries.Enumerate(AutoRegEntryWriter, (void*)fd);
1419
1420 PersistentWriterArgs args;
1421 args.mFD = fd;
1422 args.mLoaderData = mLoaderData;
1423
1424 if (PR_fprintf(fd, "\n[CLASSIDS]\n") == (PRUint32) -1) {
1425 rv = NS_ERROR_UNEXPECTED;
1426 goto out;
1427 }
1428
1429
1430 PL_DHashTableEnumerate(&mFactories, ClassIDWriter, (void*)&args);
1431
1432 if (PR_fprintf(fd, "\n[CONTRACTIDS]\n") == (PRUint32) -1) {
1433 rv = NS_ERROR_UNEXPECTED;
1434 goto out;
1435 }
1436
1437
1438 PL_DHashTableEnumerate(&mContractIDs, ContractIDWriter, (void*)&args);
1439
1440 if (PR_fprintf(fd, "\n[CATEGORIES]\n") == (PRUint32) -1) {
1441 rv = NS_ERROR_UNEXPECTED;
1442 goto out;
1443 }
1444
1445
1446 if (!mCategoryManager) {
1447 NS_WARNING("Could not access category manager. Will not be able to save categories!");
1448 rv = NS_ERROR_UNEXPECTED;
1449 } else {
1450 rv = mCategoryManager->WriteCategoryManagerToRegistry(fd);
1451 }
1452
1453out:
1454 if (fd)
1455 PR_Close(fd);
1456
1457 // don't create the file is there was a problem????
1458 NS_ENSURE_SUCCESS(rv, rv);
1459
1460 if (!mRegistryFile)
1461 return NS_ERROR_NOT_INITIALIZED;
1462
1463 PRBool exists;
1464 if(NS_FAILED(mRegistryFile->Exists(&exists)))
1465 return PR_FALSE;
1466
1467 if(exists && NS_FAILED(mRegistryFile->Remove(PR_FALSE)))
1468 return PR_FALSE;
1469
1470 nsCOMPtr<nsIFile> parent;
1471 mRegistryFile->GetParent(getter_AddRefs(parent));
1472
1473 rv = localFile->MoveToNative(parent, originalLeafName);
1474 mRegistryDirty = PR_FALSE;
1475
1476 return rv;
1477}
1478
1479
1480////////////////////////////////////////////////////////////////////////////////
1481// Hash Functions
1482////////////////////////////////////////////////////////////////////////////////
1483nsresult
1484nsComponentManagerImpl::HashContractID(const char *aContractID,
1485 PRUint32 aContractIDLen,
1486 nsFactoryEntry *fe)
1487{
1488 if(!aContractID || !aContractIDLen)
1489 return NS_ERROR_NULL_POINTER;
1490
1491 nsAutoMonitor mon(mMon);
1492
1493 nsContractIDTableEntry* contractIDTableEntry =
1494 NS_STATIC_CAST(nsContractIDTableEntry*,
1495 PL_DHashTableOperate(&mContractIDs, aContractID,
1496 PL_DHASH_ADD));
1497 if (!contractIDTableEntry)
1498 return NS_ERROR_OUT_OF_MEMORY;
1499
1500 NS_ASSERTION(!contractIDTableEntry->mContractID || !strcmp(contractIDTableEntry->mContractID, aContractID), "contractid conflict");
1501
1502 if (!contractIDTableEntry->mContractID) {
1503 contractIDTableEntry->mContractID = ArenaStrndup(aContractID, aContractIDLen, &mArena);
1504 contractIDTableEntry->mContractIDLen = aContractIDLen;
1505 }
1506
1507 contractIDTableEntry->mFactoryEntry = fe;
1508
1509 return NS_OK;
1510}
1511
1512/**
1513 * LoadFactory()
1514 *
1515 * Given a FactoryEntry, this loads the dll if it has to, find the NSGetFactory
1516 * symbol, calls the routine to create a new factory and returns it to the
1517 * caller.
1518 *
1519 * No attempt is made to store the factory in any form anywhere.
1520 */
1521nsresult
1522nsComponentManagerImpl::LoadFactory(nsFactoryEntry *aEntry,
1523 nsIFactory **aFactory)
1524{
1525
1526 if (!aFactory)
1527 return NS_ERROR_NULL_POINTER;
1528 *aFactory = nsnull;
1529
1530 nsresult rv;
1531 rv = aEntry->GetFactory(aFactory, this);
1532 if (NS_FAILED(rv)) {
1533 Log(("nsComponentManager: FAILED to load factory from %s (%s)\n",
1534 (const char *)aEntry->mLocation, mLoaderData[aEntry->mTypeIndex].type));
1535 return rv;
1536 }
1537
1538 return NS_OK;
1539}
1540
1541nsFactoryEntry *
1542nsComponentManagerImpl::GetFactoryEntry(const char *aContractID,
1543 PRUint32 aContractIDLen)
1544{
1545 nsFactoryEntry *fe = nsnull;
1546 {
1547 nsAutoMonitor mon(mMon);
1548
1549 nsContractIDTableEntry* contractIDTableEntry =
1550 NS_STATIC_CAST(nsContractIDTableEntry*,
1551 PL_DHashTableOperate(&mContractIDs, aContractID,
1552 PL_DHASH_LOOKUP));
1553
1554
1555 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
1556 fe = contractIDTableEntry->mFactoryEntry;
1557 }
1558 } //exit monitor
1559
1560 return fe;
1561}
1562
1563
1564nsFactoryEntry *
1565nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass)
1566{
1567 nsFactoryEntry *entry = nsnull;
1568 {
1569 nsAutoMonitor mon(mMon);
1570
1571 nsFactoryTableEntry* factoryTableEntry =
1572 NS_STATIC_CAST(nsFactoryTableEntry*,
1573 PL_DHashTableOperate(&mFactories, &aClass,
1574 PL_DHASH_LOOKUP));
1575
1576 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
1577 entry = factoryTableEntry->mFactoryEntry;
1578 }
1579 } // exit monitor
1580
1581 return entry;
1582}
1583
1584
1585/**
1586 * FindFactory()
1587 *
1588 * Given a classID, this finds the factory for this CID by first searching the
1589 * local CID<->factory mapping. Next it searches for a Dll that implements
1590 * this classID and calls LoadFactory() to create the factory.
1591 *
1592 * Again, no attempt is made at storing the factory.
1593 */
1594nsresult
1595nsComponentManagerImpl::FindFactory(const nsCID &aClass,
1596 nsIFactory **aFactory)
1597{
1598 Assert(aFactory != nsnull);
1599
1600 nsFactoryEntry *entry = GetFactoryEntry(aClass);
1601
1602 if (!entry)
1603 return NS_ERROR_FACTORY_NOT_REGISTERED;
1604
1605 return entry->GetFactory(aFactory, this);
1606}
1607
1608
1609nsresult
1610nsComponentManagerImpl::FindFactory(const char *contractID,
1611 PRUint32 aContractIDLen,
1612 nsIFactory **aFactory)
1613{
1614 Assert(aFactory != nsnull);
1615
1616 nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen);
1617
1618 if (!entry)
1619 return NS_ERROR_FACTORY_NOT_REGISTERED;
1620
1621 return entry->GetFactory(aFactory, this);
1622}
1623
1624/**
1625 * GetClassObject()
1626 *
1627 * Given a classID, this finds the singleton ClassObject that implements the CID.
1628 * Returns an interface of type aIID off the singleton classobject.
1629 */
1630nsresult
1631nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID,
1632 void **aResult)
1633{
1634 nsresult rv;
1635
1636 nsCOMPtr<nsIFactory> factory;
1637
1638#ifdef LOG_ENABLED
1639 char *buf = aClass.ToString();
1640 LogFlow(("nsComponentManager: GetClassObject(%s)", buf));
1641 if (buf)
1642 PR_Free(buf);
1643#endif
1644
1645 Assert(aResult != nsnull);
1646
1647 rv = FindFactory(aClass, getter_AddRefs(factory));
1648 if (NS_FAILED(rv)) return rv;
1649
1650 rv = factory->QueryInterface(aIID, aResult);
1651
1652 Log(("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1653 return rv;
1654}
1655
1656
1657nsresult
1658nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID,
1659 const nsIID &aIID,
1660 void **aResult)
1661{
1662 nsresult rv;
1663
1664 nsCOMPtr<nsIFactory> factory;
1665
1666 Log(("nsComponentManager: GetClassObject(%s)", contractID));
1667 Assert(aResult != nsnull);
1668
1669 rv = FindFactory(contractID, strlen(contractID), getter_AddRefs(factory));
1670 if (NS_FAILED(rv)) return rv;
1671
1672 rv = factory->QueryInterface(aIID, aResult);
1673
1674 Log(("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1675 return rv;
1676}
1677
1678/**
1679 * ContractIDToClassID()
1680 *
1681 * Mapping function from a ContractID to a classID. Directly talks to the registry.
1682 *
1683 */
1684nsresult
1685nsComponentManagerImpl::ContractIDToClassID(const char *aContractID, nsCID *aClass)
1686{
1687 NS_PRECONDITION(aContractID != nsnull, "null ptr");
1688 if (!aContractID)
1689 return NS_ERROR_NULL_POINTER;
1690
1691 NS_PRECONDITION(aClass != nsnull, "null ptr");
1692 if (!aClass)
1693 return NS_ERROR_NULL_POINTER;
1694
1695 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1696
1697 nsFactoryEntry *fe = GetFactoryEntry(aContractID, strlen(aContractID));
1698 if (fe) {
1699 *aClass = fe->mCid;
1700 rv = NS_OK;
1701 }
1702#ifdef LOG_ENABLED
1703 char *buf = 0;
1704 if (NS_SUCCEEDED(rv))
1705 buf = aClass->ToString();
1706 Log(("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID,
1707 NS_SUCCEEDED(rv) ? buf : "[FAILED]"));
1708 if (buf)
1709 PR_Free(buf);
1710#endif
1711 return rv;
1712}
1713
1714/**
1715 * CLSIDToContractID()
1716 *
1717 * Translates a classID to a {ContractID, Class Name}. Does direct registry
1718 * access to do the translation.
1719 *
1720 * NOTE: Since this isn't heavily used, we arent caching this.
1721 */
1722nsresult
1723nsComponentManagerImpl::CLSIDToContractID(const nsCID &aClass,
1724 char* *aClassName,
1725 char* *aContractID)
1726{
1727 NS_WARNING("Need to implement CLSIDToContractID");
1728
1729 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1730
1731#ifdef LOG_ENABLED
1732 char *buf = aClass.ToString();
1733 Log(("nsComponentManager: CLSIDToContractID(%s)->%s", buf,
1734 NS_SUCCEEDED(rv) ? *aContractID : "[FAILED]"));
1735 if (buf)
1736 PR_Free(buf);
1737#endif
1738 return rv;
1739}
1740
1741#ifdef XPCOM_CHECK_PENDING_CIDS
1742
1743// This method must be called from within the mMon monitor
1744nsresult
1745nsComponentManagerImpl::AddPendingCID(const nsCID &aClass)
1746{
1747 int max = mPendingCIDs.Count();
1748 for (int index = 0; index < max; index++)
1749 {
1750 nsCID *cidp = (nsCID*) mPendingCIDs.ElementAt(index);
1751 NS_ASSERTION(cidp, "Bad CID in pending list");
1752 if (cidp->Equals(aClass)) {
1753 nsXPIDLCString cid;
1754 cid.Adopt(aClass.ToString());
1755 nsCAutoString message;
1756 message = NS_LITERAL_CSTRING("Creation of \"") +
1757 cid + NS_LITERAL_CSTRING("\" in progress (Reentrant GS - see bug 194568)");
1758 // Note that you may see this assertion by near-simultaneous
1759 // calls to GetService on multiple threads.
1760 NS_WARNING(message.get());
1761 return NS_ERROR_NOT_AVAILABLE;
1762 }
1763 }
1764 mPendingCIDs.AppendElement((void*)&aClass);
1765 return NS_OK;
1766}
1767
1768// This method must be called from within the mMon monitor
1769void
1770nsComponentManagerImpl::RemovePendingCID(const nsCID &aClass)
1771{
1772 mPendingCIDs.RemoveElement((void*)&aClass);
1773}
1774#endif
1775/**
1776 * CreateInstance()
1777 *
1778 * Create an instance of an object that implements an interface and belongs
1779 * to the implementation aClass using the factory. The factory is immediately
1780 * released and not held onto for any longer.
1781 */
1782nsresult
1783nsComponentManagerImpl::CreateInstance(const nsCID &aClass,
1784 nsISupports *aDelegate,
1785 const nsIID &aIID,
1786 void **aResult)
1787{
1788 // test this first, since there's no point in creating a component during
1789 // shutdown -- whether it's available or not would depend on the order it
1790 // occurs in the list
1791 if (gXPCOMShuttingDown) {
1792 // When processing shutdown, dont process new GetService() requests
1793#ifdef SHOW_DENIED_ON_SHUTDOWN
1794 nsXPIDLCString cid, iid;
1795 cid.Adopt(aClass.ToString());
1796 iid.Adopt(aIID.ToString());
1797 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1798 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1799#endif /* SHOW_DENIED_ON_SHUTDOWN */
1800 return NS_ERROR_UNEXPECTED;
1801 }
1802
1803 if (aResult == nsnull)
1804 {
1805 return NS_ERROR_NULL_POINTER;
1806 }
1807 *aResult = nsnull;
1808
1809 nsFactoryEntry *entry = GetFactoryEntry(aClass);
1810
1811 if (!entry)
1812 return NS_ERROR_FACTORY_NOT_REGISTERED;
1813
1814#ifdef SHOW_CI_ON_EXISTING_SERVICE
1815 if (entry->mServiceObject) {
1816 nsXPIDLCString cid;
1817 cid.Adopt(aClass.ToString());
1818 nsCAutoString message;
1819 message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1820 cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!");
1821 NS_ERROR(message.get());
1822 }
1823#endif
1824
1825 nsIFactory *factory = nsnull;
1826 nsresult rv = entry->GetFactory(&factory, this);
1827
1828 if (NS_SUCCEEDED(rv))
1829 {
1830 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1831 NS_RELEASE(factory);
1832 }
1833 else
1834 {
1835 // Translate error values
1836 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1837 }
1838
1839#ifdef LOG_ENABLED
1840 char *buf = aClass.ToString();
1841 Log(("nsComponentManager: CreateInstance(%s) %s", buf,
1842 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1843 if (buf)
1844 PR_Free(buf);
1845#endif
1846
1847 return rv;
1848}
1849
1850/**
1851 * CreateInstanceByContractID()
1852 *
1853 * A variant of CreateInstance() that creates an instance of the object that
1854 * implements the interface aIID and whose implementation has a contractID aContractID.
1855 *
1856 * This is only a convenience routine that turns around can calls the
1857 * CreateInstance() with classid and iid.
1858 */
1859nsresult
1860nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID,
1861 nsISupports *aDelegate,
1862 const nsIID &aIID,
1863 void **aResult)
1864{
1865 // test this first, since there's no point in creating a component during
1866 // shutdown -- whether it's available or not would depend on the order it
1867 // occurs in the list
1868 if (gXPCOMShuttingDown) {
1869 // When processing shutdown, dont process new GetService() requests
1870#ifdef SHOW_DENIED_ON_SHUTDOWN
1871 nsXPIDLCString iid;
1872 iid.Adopt(aIID.ToString());
1873 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1874 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1875#endif /* SHOW_DENIED_ON_SHUTDOWN */
1876 return NS_ERROR_UNEXPECTED;
1877 }
1878
1879 if (aResult == nsnull)
1880 {
1881 return NS_ERROR_NULL_POINTER;
1882 }
1883 *aResult = nsnull;
1884
1885 nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID));
1886
1887 if (!entry)
1888 return NS_ERROR_FACTORY_NOT_REGISTERED;
1889
1890#ifdef SHOW_CI_ON_EXISTING_SERVICE
1891 if (entry->mServiceObject) {
1892 nsCAutoString message;
1893 message =
1894 NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1895 nsDependentCString(aContractID) +
1896 NS_LITERAL_CSTRING("\" when a service for this CID already exists! "
1897 "Add it to abusedContracts to track down the service consumer.");
1898 NS_ERROR(message.get());
1899 }
1900#endif
1901
1902 nsIFactory *factory = nsnull;
1903 nsresult rv = entry->GetFactory(&factory, this);
1904
1905 if (NS_SUCCEEDED(rv))
1906 {
1907
1908 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1909 NS_RELEASE(factory);
1910 }
1911 else
1912 {
1913 // Translate error values
1914 if (rv != NS_ERROR_SOCKET_FAIL)
1915 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1916 }
1917
1918 Log(("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
1919 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1920 return rv;
1921}
1922
1923// Service Manager Impl
1924static
1925PLDHashOperator PR_CALLBACK
1926FreeServiceFactoryEntryEnumerate(PLDHashTable *aTable,
1927 PLDHashEntryHdr *aHdr,
1928 PRUint32 aNumber,
1929 void *aData)
1930{
1931 nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
1932
1933 if (!entry->mFactoryEntry)
1934 return PL_DHASH_NEXT;
1935
1936 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
1937 factoryEntry->mServiceObject = nsnull;
1938 return PL_DHASH_NEXT;
1939}
1940
1941static
1942PLDHashOperator PR_CALLBACK
1943FreeServiceContractIDEntryEnumerate(PLDHashTable *aTable,
1944 PLDHashEntryHdr *aHdr,
1945 PRUint32 aNumber,
1946 void *aData)
1947{
1948 nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
1949
1950 if (!entry->mFactoryEntry)
1951 return PL_DHASH_NEXT;
1952
1953 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
1954 factoryEntry->mServiceObject = nsnull;
1955 return PL_DHASH_NEXT;
1956}
1957
1958nsresult
1959nsComponentManagerImpl::FreeServices()
1960{
1961 NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services");
1962
1963 if (!gXPCOMShuttingDown)
1964 return NS_ERROR_FAILURE;
1965
1966 if (mContractIDs.ops) {
1967 PL_DHashTableEnumerate(&mContractIDs, FreeServiceContractIDEntryEnumerate, nsnull);
1968 }
1969
1970
1971 if (mFactories.ops) {
1972 PL_DHashTableEnumerate(&mFactories, FreeServiceFactoryEntryEnumerate, nsnull);
1973 }
1974
1975 return NS_OK;
1976}
1977
1978NS_IMETHODIMP
1979nsComponentManagerImpl::GetService(const nsCID& aClass,
1980 const nsIID& aIID,
1981 void* *result)
1982{
1983 // test this first, since there's no point in returning a service during
1984 // shutdown -- whether it's available or not would depend on the order it
1985 // occurs in the list
1986 if (gXPCOMShuttingDown) {
1987 // When processing shutdown, dont process new GetService() requests
1988#ifdef SHOW_DENIED_ON_SHUTDOWN
1989 nsXPIDLCString cid, iid;
1990 cid.Adopt(aClass.ToString());
1991 iid.Adopt(aIID.ToString());
1992 fprintf(stderr, "Getting service on shutdown. Denied.\n"
1993 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1994#endif /* SHOW_DENIED_ON_SHUTDOWN */
1995 return NS_ERROR_UNEXPECTED;
1996 }
1997
1998 nsAutoMonitor mon(mMon);
1999
2000 nsresult rv = NS_OK;
2001 nsIDKey key(aClass);
2002 nsFactoryEntry* entry = nsnull;
2003 nsFactoryTableEntry* factoryTableEntry =
2004 NS_STATIC_CAST(nsFactoryTableEntry*,
2005 PL_DHashTableOperate(&mFactories, &aClass,
2006 PL_DHASH_LOOKUP));
2007
2008 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2009 entry = factoryTableEntry->mFactoryEntry;
2010 }
2011
2012 if (entry && entry->mServiceObject) {
2013 return entry->mServiceObject->QueryInterface(aIID, result);
2014 }
2015
2016#ifdef XPCOM_CHECK_PENDING_CIDS
2017 rv = AddPendingCID(aClass);
2018 if (NS_FAILED(rv))
2019 return rv; // NOP_AND_BREAK
2020#endif
2021 nsCOMPtr<nsISupports> service;
2022 // We need to not be holding the service manager's monitor while calling
2023 // CreateInstance, because it invokes user code which could try to re-enter
2024 // the service manager:
2025 mon.Exit();
2026
2027 rv = CreateInstance(aClass, nsnull, aIID, getter_AddRefs(service));
2028
2029 mon.Enter();
2030
2031#ifdef XPCOM_CHECK_PENDING_CIDS
2032 RemovePendingCID(aClass);
2033#endif
2034
2035 if (NS_FAILED(rv))
2036 return rv;
2037
2038 if (!entry) { // second hash lookup for GetService
2039 nsFactoryTableEntry* factoryTableEntry =
2040 NS_STATIC_CAST(nsFactoryTableEntry*,
2041 PL_DHashTableOperate(&mFactories, &aClass,
2042 PL_DHASH_LOOKUP));
2043 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2044 entry = factoryTableEntry->mFactoryEntry;
2045 }
2046 NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
2047 if (!entry) return NS_ERROR_FAILURE;
2048 }
2049
2050 entry->mServiceObject = service;
2051 *result = service.get();
2052 NS_ADDREF(NS_STATIC_CAST(nsISupports*, (*result)));
2053 return rv;
2054}
2055
2056NS_IMETHODIMP
2057nsComponentManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService)
2058{
2059 nsAutoMonitor mon(mMon);
2060
2061 // check to see if we have a factory entry for the service
2062 nsFactoryEntry *entry = GetFactoryEntry(aClass);
2063
2064 if (!entry) { // XXXdougt - should we require that all services register factories?? probably not.
2065 void *mem;
2066 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2067 if (!mem)
2068 return NS_ERROR_OUT_OF_MEMORY;
2069 entry = new (mem) nsFactoryEntry(aClass, nsnull);
2070
2071 entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
2072 nsFactoryTableEntry* factoryTableEntry =
2073 NS_STATIC_CAST(nsFactoryTableEntry*,
2074 PL_DHashTableOperate(&mFactories, &aClass,
2075 PL_DHASH_ADD));
2076 if (!factoryTableEntry)
2077 return NS_ERROR_OUT_OF_MEMORY;
2078
2079 factoryTableEntry->mFactoryEntry = entry;
2080 }
2081 else {
2082 if (entry->mServiceObject)
2083 return NS_ERROR_FAILURE;
2084 }
2085
2086 entry->mServiceObject = aService;
2087 return NS_OK;
2088}
2089
2090NS_IMETHODIMP
2091nsComponentManagerImpl::UnregisterService(const nsCID& aClass)
2092{
2093 nsresult rv = NS_OK;
2094
2095 nsFactoryEntry* entry = nsnull;
2096
2097 nsAutoMonitor mon(mMon);
2098
2099 nsFactoryTableEntry* factoryTableEntry =
2100 NS_STATIC_CAST(nsFactoryTableEntry*,
2101 PL_DHashTableOperate(&mFactories, &aClass,
2102 PL_DHASH_LOOKUP));
2103
2104 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2105 entry = factoryTableEntry->mFactoryEntry;
2106 }
2107
2108 if (!entry || !entry->mServiceObject)
2109 return NS_ERROR_SERVICE_NOT_AVAILABLE;
2110
2111 entry->mServiceObject = nsnull;
2112 return rv;
2113}
2114
2115NS_IMETHODIMP
2116nsComponentManagerImpl::RegisterService(const char* aContractID, nsISupports* aService)
2117{
2118
2119 nsAutoMonitor mon(mMon);
2120
2121 // check to see if we have a factory entry for the service
2122 PRUint32 contractIDLen = strlen(aContractID);
2123 nsFactoryEntry *entry = GetFactoryEntry(aContractID, contractIDLen);
2124
2125 if (!entry) { // XXXdougt - should we require that all services register factories?? probably not.
2126 void *mem;
2127 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2128 if (!mem)
2129 return NS_ERROR_OUT_OF_MEMORY;
2130 entry = new (mem) nsFactoryEntry(kEmptyCID, nsnull);
2131
2132 entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
2133
2134 nsContractIDTableEntry* contractIDTableEntry =
2135 NS_STATIC_CAST(nsContractIDTableEntry*,
2136 PL_DHashTableOperate(&mContractIDs, aContractID,
2137 PL_DHASH_ADD));
2138 if (!contractIDTableEntry) {
2139 delete entry;
2140 return NS_ERROR_OUT_OF_MEMORY;
2141 }
2142
2143 if (!contractIDTableEntry->mContractID) {
2144 contractIDTableEntry->mContractID =
2145 ArenaStrndup(aContractID, contractIDLen, &mArena);
2146
2147 contractIDTableEntry->mContractIDLen = contractIDLen;
2148 }
2149
2150 contractIDTableEntry->mFactoryEntry = entry;
2151 }
2152 else {
2153 if (entry->mServiceObject)
2154 return NS_ERROR_FAILURE;
2155 }
2156
2157 entry->mServiceObject = aService;
2158 return NS_OK;
2159}
2160
2161
2162NS_IMETHODIMP
2163nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
2164 const nsIID& aIID,
2165 PRBool *result)
2166{
2167 // Now we want to get the service if we already got it. If not, we dont want
2168 // to create an instance of it. mmh!
2169
2170 // test this first, since there's no point in returning a service during
2171 // shutdown -- whether it's available or not would depend on the order it
2172 // occurs in the list
2173 if (gXPCOMShuttingDown) {
2174 // When processing shutdown, dont process new GetService() requests
2175#ifdef SHOW_DENIED_ON_SHUTDOWN
2176 nsXPIDLCString cid, iid;
2177 cid.Adopt(aClass.ToString());
2178 iid.Adopt(aIID.ToString());
2179 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
2180 " CID: %s\n IID: %s\n", cid.get(), iid.get());
2181#endif /* SHOW_DENIED_ON_SHUTDOWN */
2182 return NS_ERROR_UNEXPECTED;
2183 }
2184
2185 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
2186 nsFactoryEntry* entry = nsnull;
2187 nsFactoryTableEntry* factoryTableEntry =
2188 NS_STATIC_CAST(nsFactoryTableEntry*,
2189 PL_DHashTableOperate(&mFactories, &aClass,
2190 PL_DHASH_LOOKUP));
2191
2192 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2193 entry = factoryTableEntry->mFactoryEntry;
2194 }
2195
2196 if (entry && entry->mServiceObject) {
2197 nsCOMPtr<nsISupports> service;
2198 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
2199 *result = (service!=nsnull);
2200 }
2201 return rv;
2202
2203}
2204
2205NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID,
2206 const nsIID& aIID,
2207 PRBool *result)
2208{
2209 // Now we want to get the service if we already got it. If not, we dont want
2210 // to create an instance of it. mmh!
2211
2212 // test this first, since there's no point in returning a service during
2213 // shutdown -- whether it's available or not would depend on the order it
2214 // occurs in the list
2215 if (gXPCOMShuttingDown) {
2216 // When processing shutdown, dont process new GetService() requests
2217#ifdef SHOW_DENIED_ON_SHUTDOWN
2218 nsXPIDLCString iid;
2219 iid.Adopt(aIID.ToString());
2220 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
2221 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
2222#endif /* SHOW_DENIED_ON_SHUTDOWN */
2223 return NS_ERROR_UNEXPECTED;
2224 }
2225
2226 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
2227 nsFactoryEntry *entry = nsnull;
2228 {
2229 nsAutoMonitor mon(mMon);
2230
2231 nsContractIDTableEntry* contractIDTableEntry =
2232 NS_STATIC_CAST(nsContractIDTableEntry*,
2233 PL_DHashTableOperate(&mContractIDs, aContractID,
2234 PL_DHASH_LOOKUP));
2235
2236 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2237 entry = contractIDTableEntry->mFactoryEntry;
2238 }
2239 } // exit monitor
2240
2241 if (entry && entry->mServiceObject) {
2242 nsCOMPtr<nsISupports> service;
2243 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
2244 *result = (service!=nsnull);
2245 }
2246 return rv;
2247}
2248
2249
2250NS_IMETHODIMP
2251nsComponentManagerImpl::UnregisterService(const char* aContractID)
2252{
2253 nsresult rv = NS_OK;
2254
2255 nsAutoMonitor mon(mMon);
2256
2257 nsFactoryEntry *entry = nsnull;
2258 nsContractIDTableEntry* contractIDTableEntry =
2259 NS_STATIC_CAST(nsContractIDTableEntry*,
2260 PL_DHashTableOperate(&mContractIDs, aContractID,
2261 PL_DHASH_LOOKUP));
2262
2263 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2264 entry = contractIDTableEntry->mFactoryEntry;
2265 }
2266
2267 if (!entry || !entry->mServiceObject)
2268 return NS_ERROR_SERVICE_NOT_AVAILABLE;
2269
2270 entry->mServiceObject = nsnull;
2271 return rv;
2272}
2273
2274NS_IMETHODIMP
2275nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
2276 const nsIID& aIID,
2277 void* *result)
2278{
2279 // test this first, since there's no point in returning a service during
2280 // shutdown -- whether it's available or not would depend on the order it
2281 // occurs in the list
2282 if (gXPCOMShuttingDown) {
2283 // When processing shutdown, dont process new GetService() requests
2284#ifdef SHOW_DENIED_ON_SHUTDOWN
2285 nsXPIDLCString iid;
2286 iid.Adopt(aIID.ToString());
2287 fprintf(stderr, "Getting service on shutdown. Denied.\n"
2288 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
2289#endif /* SHOW_DENIED_ON_SHUTDOWN */
2290 return NS_ERROR_UNEXPECTED;
2291 }
2292
2293 nsAutoMonitor mon(mMon);
2294
2295 nsresult rv = NS_OK;
2296 nsFactoryEntry *entry = nsnull;
2297 nsContractIDTableEntry* contractIDTableEntry =
2298 NS_STATIC_CAST(nsContractIDTableEntry*,
2299 PL_DHashTableOperate(&mContractIDs, aContractID,
2300 PL_DHASH_LOOKUP));
2301
2302 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2303 entry = contractIDTableEntry->mFactoryEntry;
2304 }
2305
2306 if (entry) {
2307 if (entry->mServiceObject) {
2308 return entry->mServiceObject->QueryInterface(aIID, result);
2309 }
2310#ifdef XPCOM_CHECK_PENDING_CIDS
2311 rv = AddPendingCID(entry->mCid);
2312 if (NS_FAILED(rv))
2313 return rv; // NOP_AND_BREAK
2314#endif
2315 }
2316
2317 nsCOMPtr<nsISupports> service;
2318 // We need to not be holding the service manager's monitor while calling
2319 // CreateInstance, because it invokes user code which could try to re-enter
2320 // the service manager:
2321 mon.Exit();
2322
2323 rv = CreateInstanceByContractID(aContractID, nsnull, aIID, getter_AddRefs(service));
2324
2325 mon.Enter();
2326
2327#ifdef XPCOM_CHECK_PENDING_CIDS
2328 if (entry)
2329 RemovePendingCID(entry->mCid);
2330#endif
2331
2332 if (NS_FAILED(rv))
2333 return rv;
2334
2335 if (!entry) { // second hash lookup for GetService
2336 nsContractIDTableEntry* contractIDTableEntry =
2337 NS_STATIC_CAST(nsContractIDTableEntry*,
2338 PL_DHashTableOperate(&mContractIDs, aContractID,
2339 PL_DHASH_LOOKUP));
2340
2341 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2342 entry = contractIDTableEntry->mFactoryEntry;
2343 }
2344 NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
2345 if (!entry) return NS_ERROR_FAILURE;
2346 }
2347
2348 entry->mServiceObject = service;
2349 *result = service.get();
2350 NS_ADDREF(NS_STATIC_CAST(nsISupports*, *result));
2351 return rv;
2352}
2353
2354NS_IMETHODIMP
2355nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
2356 nsISupports* *result,
2357 nsIShutdownListener* shutdownListener)
2358{
2359 return GetService(aClass, aIID, (void**)result);
2360}
2361
2362NS_IMETHODIMP
2363nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID,
2364 nsISupports* *result,
2365 nsIShutdownListener* shutdownListener)
2366{
2367 return GetServiceByContractID(aContractID, aIID, (void**)result);
2368}
2369
2370
2371NS_IMETHODIMP
2372nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service,
2373 nsIShutdownListener* shutdownListener)
2374{
2375 NS_IF_RELEASE(service);
2376 return NS_OK;
2377}
2378
2379NS_IMETHODIMP
2380nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service,
2381 nsIShutdownListener* shutdownListener)
2382{
2383 NS_IF_RELEASE(service);
2384 return NS_OK;
2385}
2386
2387/*
2388 * I want an efficient way to allocate a buffer to the right size
2389 * and stick the prefix and dllName in, then be able to hand that buffer
2390 * off to the FactoryEntry. Is that so wrong?
2391 *
2392 * *regName is allocated on success.
2393 *
2394 * This should live in nsNativeComponentLoader.cpp, I think.
2395 */
2396static nsresult
2397MakeRegistryName(const char *aDllName, const char *prefix, char **regName)
2398{
2399 char *registryName;
2400
2401 PRUint32 len = strlen(prefix);
2402
2403 PRUint32 registryNameLen = strlen(aDllName) + len;
2404 registryName = (char *)nsMemory::Alloc(registryNameLen + 1);
2405
2406 // from here on it, we want len sans terminating NUL
2407
2408 if (!registryName)
2409 return NS_ERROR_OUT_OF_MEMORY;
2410
2411 memcpy(registryName, prefix, len);
2412 strcpy(registryName + len, aDllName);
2413 registryName[registryNameLen] = '\0';
2414 *regName = registryName;
2415
2416 return NS_OK;
2417}
2418
2419nsresult
2420nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec,
2421 char **aRegistryName)
2422{
2423 nsresult rv;
2424
2425 if (!mComponentsDir)
2426 return NS_ERROR_NOT_INITIALIZED;
2427
2428 if (!aSpec) {
2429 *aRegistryName = PL_strdup("");
2430 return NS_OK;
2431 }
2432
2433
2434 // First check to see if this component is in the application
2435 // components directory
2436 PRBool containedIn;
2437 mComponentsDir->Contains(aSpec, PR_TRUE, &containedIn);
2438
2439 nsCAutoString nativePathString;
2440
2441 if (containedIn){
2442 rv = aSpec->GetNativePath(nativePathString);
2443 if (NS_FAILED(rv))
2444 return rv;
2445
2446 const char* relativeLocation = nativePathString.get() + mComponentsOffset + 1;
2447 return MakeRegistryName(relativeLocation, XPCOM_RELCOMPONENT_PREFIX, aRegistryName);
2448 }
2449
2450 // Next check to see if this component is in the GRE
2451 // components directory
2452
2453 mGREComponentsDir->Contains(aSpec, PR_TRUE, &containedIn);
2454
2455 if (containedIn){
2456 rv = aSpec->GetNativePath(nativePathString);
2457 if (NS_FAILED(rv))
2458 return rv;
2459
2460 const char* relativeLocation = nativePathString.get() + mGREComponentsOffset + 1;
2461 return MakeRegistryName(relativeLocation, XPCOM_GRECOMPONENT_PREFIX, aRegistryName);
2462 }
2463
2464 /* absolute names include volume info on Mac, so persistent descriptor */
2465 rv = aSpec->GetNativePath(nativePathString);
2466 if (NS_FAILED(rv))
2467 return rv;
2468 return MakeRegistryName(nativePathString.get(), XPCOM_ABSCOMPONENT_PREFIX, aRegistryName);
2469}
2470
2471nsresult
2472nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation,
2473 nsIFile **aSpec)
2474{
2475 // i18n: assuming aLocation is encoded for the current locale
2476
2477 nsresult rv;
2478 if (!aLocation || !aSpec)
2479 return NS_ERROR_NULL_POINTER;
2480
2481 /* abs:/full/path/to/libcomponent.so */
2482 if (!strncmp(aLocation, XPCOM_ABSCOMPONENT_PREFIX, 4)) {
2483
2484 nsLocalFile* file = new nsLocalFile;
2485 if (!file) return NS_ERROR_FAILURE;
2486
2487 rv = file->InitWithNativePath(nsDependentCString((char *)aLocation + 4));
2488 file->QueryInterface(NS_GET_IID(nsILocalFile), (void**)aSpec);
2489 return rv;
2490 }
2491
2492 if (!strncmp(aLocation, XPCOM_RELCOMPONENT_PREFIX, 4)) {
2493
2494 if (!mComponentsDir)
2495 return NS_ERROR_NOT_INITIALIZED;
2496
2497 nsILocalFile* file = nsnull;
2498 rv = mComponentsDir->Clone((nsIFile**)&file);
2499
2500 if (NS_FAILED(rv)) return rv;
2501
2502 rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4));
2503 *aSpec = file;
2504 return rv;
2505 }
2506
2507 if (!strncmp(aLocation, XPCOM_GRECOMPONENT_PREFIX, 4)) {
2508
2509 if (!mGREComponentsDir)
2510 return NS_ERROR_NOT_INITIALIZED;
2511
2512 nsILocalFile* file = nsnull;
2513 rv = mGREComponentsDir->Clone((nsIFile**)&file);
2514
2515 if (NS_FAILED(rv)) return rv;
2516
2517 rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4));
2518 *aSpec = file;
2519 return rv;
2520 }
2521
2522 *aSpec = nsnull;
2523 return NS_ERROR_INVALID_ARG;
2524}
2525
2526/**
2527 * RegisterFactory()
2528 *
2529 * Register a factory to be responsible for creation of implementation of
2530 * classID aClass. Plus creates as association of aClassName and aContractID
2531 * to the classID. If replace is PR_TRUE, we replace any existing registrations
2532 * with this one.
2533 *
2534 * Once registration is complete, we add the class to the factories cache
2535 * that we maintain. The factories cache is the ONLY place where these
2536 * registrations are ever kept.
2537 *
2538 * The other RegisterFunctions create a loader mapping and persistent
2539 * location, but we just slam it into the cache here. And we don't call the
2540 * loader's OnRegister function, either.
2541 */
2542nsresult
2543nsComponentManagerImpl::RegisterFactory(const nsCID &aClass,
2544 const char *aClassName,
2545 const char *aContractID,
2546 nsIFactory *aFactory,
2547 PRBool aReplace)
2548{
2549 nsAutoMonitor mon(mMon);
2550#ifdef LOG_ENABLED
2551 char *buf = aClass.ToString();
2552 Log(("nsComponentManager: RegisterFactory(%s, %s)", buf,
2553 (aContractID ? aContractID : "(null)")));
2554 if (buf)
2555 PR_Free(buf);
2556#endif
2557 nsFactoryEntry *entry = nsnull;
2558 nsFactoryTableEntry* factoryTableEntry = NS_STATIC_CAST(nsFactoryTableEntry*,
2559 PL_DHashTableOperate(&mFactories,
2560 &aClass,
2561 PL_DHASH_ADD));
2562
2563 if (!factoryTableEntry)
2564 return NS_ERROR_OUT_OF_MEMORY;
2565
2566
2567 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2568 entry = factoryTableEntry->mFactoryEntry;
2569 }
2570
2571 if (entry && !aReplace)
2572 {
2573 // Already registered
2574 Log(("\t\tFactory already registered."));
2575 return NS_ERROR_FACTORY_EXISTS;
2576 }
2577
2578 void *mem;
2579 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2580 if (!mem)
2581 return NS_ERROR_OUT_OF_MEMORY;
2582
2583 entry = new (mem) nsFactoryEntry(aClass, aFactory, entry);
2584
2585 if (!entry)
2586 return NS_ERROR_OUT_OF_MEMORY;
2587
2588 factoryTableEntry->mFactoryEntry = entry;
2589
2590 // Update the ContractID->CLSID Map
2591 if (aContractID) {
2592 nsresult rv = HashContractID(aContractID, strlen(aContractID), entry);
2593 if (NS_FAILED(rv)) {
2594 Log(("\t\tFactory register succeeded. "
2595 "Hashing contractid (%s) FAILED.", aContractID));
2596 return rv;
2597 }
2598 }
2599
2600 Log(("\t\tFactory register succeeded contractid=%s.",
2601 aContractID ? aContractID : "<none>"));
2602 return NS_OK;
2603}
2604
2605nsresult
2606nsComponentManagerImpl::RegisterComponent(const nsCID &aClass,
2607 const char *aClassName,
2608 const char *aContractID,
2609 const char *aPersistentDescriptor,
2610 PRBool aReplace,
2611 PRBool aPersist)
2612{
2613 return RegisterComponentCommon(aClass, aClassName,
2614 aContractID,
2615 aContractID ? strlen(aContractID) : 0,
2616 aPersistentDescriptor,
2617 aPersistentDescriptor ?
2618 strlen(aPersistentDescriptor) : 0,
2619 aReplace, aPersist,
2620 nativeComponentType);
2621}
2622
2623nsresult
2624nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass,
2625 const char *aClassName,
2626 const char *aContractID,
2627 nsIFile *aSpec,
2628 const char *aLocation,
2629 PRBool aReplace,
2630 PRBool aPersist,
2631 const char *aType)
2632{
2633 return RegisterComponentCommon(aClass, aClassName,
2634 aContractID,
2635 aContractID ? strlen(aContractID) : 0,
2636 aLocation,
2637 aLocation ? strlen(aLocation) : 0,
2638 aReplace, aPersist,
2639 aType);
2640}
2641
2642/*
2643 * Register a component, using whatever they stuck in the nsIFile.
2644 */
2645nsresult
2646nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass,
2647 const char *aClassName,
2648 const char *aContractID,
2649 nsIFile *aLibrarySpec,
2650 PRBool aReplace,
2651 PRBool aPersist)
2652{
2653 nsXPIDLCString registryName;
2654 nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName));
2655 if (NS_FAILED(rv))
2656 return rv;
2657
2658 rv = RegisterComponentWithType(aClass, aClassName,
2659 aContractID,
2660 aLibrarySpec,
2661 registryName,
2662 aReplace, aPersist,
2663 nativeComponentType);
2664 return rv;
2665}
2666
2667nsresult
2668nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass,
2669 const char *aClassName,
2670 const char *aContractID,
2671 const char *aDllName,
2672 PRBool aReplace,
2673 PRBool aPersist)
2674{
2675 // deprecated and obsolete.
2676 return NS_ERROR_NOT_IMPLEMENTED;
2677}
2678
2679/*
2680 * Add a component to the known universe of components.
2681
2682 * Once we enter this function, we own aRegistryName, and must free it
2683 * or hand it to nsFactoryEntry. Common exit point ``out'' helps keep us
2684 * sane.
2685 */
2686
2687nsresult
2688nsComponentManagerImpl::RegisterComponentCommon(const nsCID &aClass,
2689 const char *aClassName,
2690 const char *aContractID,
2691 PRUint32 aContractIDLen,
2692 const char *aRegistryName,
2693 PRUint32 aRegistryNameLen,
2694 PRBool aReplace,
2695 PRBool aPersist,
2696 const char *aType)
2697{
2698 nsIDKey key(aClass);
2699 nsAutoMonitor mon(mMon);
2700
2701 nsFactoryEntry *entry = GetFactoryEntry(aClass);
2702
2703 // Normalize proid and classname
2704 const char *contractID = (aContractID && *aContractID) ? aContractID : nsnull;
2705 const char *className = (aClassName && *aClassName) ? aClassName : nsnull;
2706#ifdef LOG_ENABLED
2707 char *buf = aClass.ToString();
2708 Log(("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)",
2709 buf, contractID ? contractID : "(null)",
2710 aRegistryName, aType));
2711 if (buf)
2712 PR_Free(buf);
2713#endif
2714 if (entry && !aReplace) {
2715 Log(("\t\tFactory already registered."));
2716 return NS_ERROR_FACTORY_EXISTS;
2717 }
2718
2719 int typeIndex = GetLoaderType(aType);
2720
2721 nsCOMPtr<nsIComponentLoader> loader;
2722 nsresult rv = GetLoaderForType(typeIndex, getter_AddRefs(loader));
2723 if (NS_FAILED(rv)) {
2724 Log(("\t\tgetting loader for %s FAILED\n", aType));
2725 return rv;
2726 }
2727
2728 if (entry) {
2729 entry->ReInit(aClass, aRegistryName, typeIndex);
2730 }
2731 else {
2732
2733 // Arena allocate the nsFactoryEntry
2734 void *mem;
2735 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2736 if (!mem)
2737 return NS_ERROR_OUT_OF_MEMORY;
2738
2739 mRegistryDirty = PR_TRUE;
2740 entry = new (mem) nsFactoryEntry(aClass,
2741 aRegistryName, aRegistryNameLen,
2742 typeIndex);
2743 if (!entry)
2744 return NS_ERROR_OUT_OF_MEMORY;
2745
2746 nsFactoryTableEntry* factoryTableEntry =
2747 NS_STATIC_CAST(nsFactoryTableEntry*,
2748 PL_DHashTableOperate(&mFactories, &aClass,
2749 PL_DHASH_ADD));
2750
2751 if (!factoryTableEntry)
2752 return NS_ERROR_OUT_OF_MEMORY;
2753
2754 factoryTableEntry->mFactoryEntry = entry;
2755 }
2756
2757 // Update the ContractID->CLSID Map
2758 if (contractID) {
2759 rv = HashContractID(contractID, aContractIDLen, entry);
2760 if (NS_FAILED(rv)) {
2761 Log(("\t\tHashContractID(%s) FAILED\n", contractID));
2762 return rv;
2763 }
2764 }
2765 return rv;
2766}
2767
2768
2769nsresult
2770nsComponentManagerImpl::GetLoaderForType(int aType,
2771 nsIComponentLoader **aLoader)
2772{
2773 nsresult rv;
2774
2775 // Make sure we have a valid type
2776 if (aType < 0 || aType >= mNLoaderData)
2777 return NS_ERROR_INVALID_ARG;
2778
2779 *aLoader = mLoaderData[aType].loader;
2780 if (*aLoader) {
2781 NS_ADDREF(*aLoader);
2782 return NS_OK;
2783 }
2784
2785 nsCOMPtr<nsIComponentLoader> loader;
2786 loader = do_GetServiceFromCategory("component-loader", mLoaderData[aType].type, &rv);
2787 if (NS_FAILED(rv))
2788 return rv;
2789
2790 rv = loader->Init(this, nsnull);
2791
2792 if (NS_SUCCEEDED(rv)) {
2793 mLoaderData[aType].loader = loader;
2794 NS_ADDREF(mLoaderData[aType].loader);
2795 *aLoader = loader;
2796 NS_ADDREF(*aLoader);
2797 }
2798 return rv;
2799}
2800
2801
2802
2803// Convert a loader type string into an index into the component data
2804// array. Empty loader types are converted to NATIVE. Returns -1 if
2805// loader type cannot be determined.
2806int
2807nsComponentManagerImpl::GetLoaderType(const char *typeStr)
2808{
2809 if (!typeStr || !*typeStr) {
2810 // Empty type strings are NATIVE
2811 return NS_COMPONENT_TYPE_NATIVE;
2812 }
2813
2814 for (int i=NS_COMPONENT_TYPE_NATIVE; i<mNLoaderData; i++) {
2815 if (!strcmp(typeStr, mLoaderData[i].type))
2816 return i;
2817 }
2818 // Not found
2819 return NS_COMPONENT_TYPE_FACTORY_ONLY;
2820}
2821
2822// Add a loader type if not already known. Out the typeIndex
2823// if the loader type is either added or already there.
2824nsresult
2825nsComponentManagerImpl::AddLoaderType(const char *typeStr, int *aTypeIndex)
2826{
2827 int typeIndex = GetLoaderType(typeStr);
2828 if (typeIndex >= 0) {
2829 *aTypeIndex = typeIndex;
2830 return NS_OK;
2831 }
2832
2833 // Add the loader type
2834 if (mNLoaderData >= mMaxNLoaderData) {
2835 NS_ASSERTION(mNLoaderData == mMaxNLoaderData,
2836 "Memory corruption. nsComponentManagerImpl::mLoaderData array overrun.");
2837 // Need to increase our loader array
2838 nsLoaderdata *new_mLoaderData = (nsLoaderdata *) PR_Realloc(mLoaderData, (mMaxNLoaderData + NS_LOADER_DATA_ALLOC_STEP) * sizeof(nsLoaderdata));
2839 if (!new_mLoaderData)
2840 return NS_ERROR_OUT_OF_MEMORY;
2841 mLoaderData = new_mLoaderData;
2842 mMaxNLoaderData += NS_LOADER_DATA_ALLOC_STEP;
2843 }
2844
2845 typeIndex = mNLoaderData;
2846 mLoaderData[typeIndex].type = PL_strdup(typeStr);
2847 if (!mLoaderData[typeIndex].type) {
2848 // mmh! no memory. return failure.
2849 return NS_ERROR_OUT_OF_MEMORY;
2850 }
2851 mLoaderData[typeIndex].loader = nsnull;
2852 mNLoaderData++;
2853
2854 *aTypeIndex = typeIndex;
2855 return NS_OK;
2856}
2857
2858typedef struct
2859{
2860 const nsCID* cid;
2861 const char* regName;
2862 nsIFactory* factory;
2863} UnregisterConditions;
2864
2865static PLDHashOperator PR_CALLBACK
2866DeleteFoundCIDs(PLDHashTable *aTable,
2867 PLDHashEntryHdr *aHdr,
2868 PRUint32 aNumber,
2869 void *aData)
2870{
2871 nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
2872
2873 if (!entry->mFactoryEntry)
2874 return PL_DHASH_NEXT;
2875
2876 UnregisterConditions* data = (UnregisterConditions*)aData;
2877
2878 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
2879 if (data->cid->Equals(factoryEntry->mCid) &&
2880 ((data->regName && !PL_strcasecmp(factoryEntry->mLocation, data->regName)) ||
2881 (data->factory && data->factory == factoryEntry->mFactory.get())))
2882 return PL_DHASH_REMOVE;
2883
2884 return PL_DHASH_NEXT;
2885}
2886
2887void
2888nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName)
2889{
2890 UnregisterConditions aData;
2891 aData.cid = aClass;
2892 aData.regName = registryName;
2893 aData.factory = nsnull;
2894 PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData);
2895
2896}
2897
2898void
2899nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory)
2900{
2901 UnregisterConditions aData;
2902 aData.cid = aClass;
2903 aData.regName = nsnull;
2904 aData.factory = factory;
2905 PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData);
2906}
2907
2908nsresult
2909nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass,
2910 nsIFactory *aFactory)
2911{
2912#ifdef LOG_ENABLED
2913 char *buf = aClass.ToString();
2914 Log(("nsComponentManager: UnregisterFactory(%s)", buf));
2915 if (buf)
2916 PR_Free(buf);
2917#endif
2918 nsFactoryEntry *old;
2919
2920 // first delete all contract id entries that are registered with this cid.
2921 DeleteContractIDEntriesByCID(&aClass, aFactory);
2922
2923 // next check to see if there is a CID registered
2924 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
2925 old = GetFactoryEntry(aClass);
2926
2927 if (old && (old->mFactory.get() == aFactory))
2928 {
2929 nsAutoMonitor mon(mMon);
2930 PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
2931 rv = NS_OK;
2932 }
2933
2934 Log(("\t\tUnregisterFactory() %s",
2935 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
2936 return rv;
2937}
2938
2939nsresult
2940nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass,
2941 const char *registryName)
2942{
2943#ifdef PR_LOGGING
2944 char *buf = aClass.ToString();
2945 Log(("nsComponentManager: UnregisterComponent(%s)", buf));
2946 if (buf)
2947 PR_Free(buf);
2948#endif
2949
2950 NS_ENSURE_ARG_POINTER(registryName);
2951 nsFactoryEntry *old;
2952
2953 // first delete all contract id entries that are registered with this cid.
2954 DeleteContractIDEntriesByCID(&aClass, registryName);
2955
2956 // next check to see if there is a CID registered
2957 old = GetFactoryEntry(aClass);
2958 if (old && old->mLocation && !PL_strcasecmp(old->mLocation, registryName))
2959 {
2960 nsAutoMonitor mon(mMon);
2961 PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
2962 }
2963
2964 Log(("nsComponentManager: Factory unregister(%s) succeeded.", registryName));
2965 return NS_OK;
2966}
2967
2968nsresult
2969nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass,
2970 nsIFile *aLibrarySpec)
2971{
2972 nsXPIDLCString registryName;
2973 nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName));
2974 if (NS_FAILED(rv)) return rv;
2975 return UnregisterComponent(aClass, registryName);
2976}
2977
2978// XXX Need to pass in aWhen and servicemanager
2979nsresult
2980nsComponentManagerImpl::FreeLibraries(void)
2981{
2982 return UnloadLibraries(NS_STATIC_CAST(nsIServiceManager*, this), NS_Timer); // XXX when
2983}
2984
2985// Private implementation of unloading libraries
2986nsresult
2987nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr, PRInt32 aWhen)
2988{
2989 nsresult rv = NS_OK;
2990
2991 nsAutoMonitor mon(mMon);
2992
2993 Log(("nsComponentManager: Unloading Libraries."));
2994
2995 // UnloadAll the loaders
2996 /* iterate over all known loaders and ask them to autoregister. */
2997 // Skip mNativeComponentLoader
2998 for (int i=NS_COMPONENT_TYPE_NATIVE + 1; i<mNLoaderData; i++) {
2999 if (mLoaderData[i].loader) {
3000 rv = mLoaderData[i].loader->UnloadAll(aWhen);
3001 if (NS_FAILED(rv))
3002 break;
3003 }
3004 }
3005
3006 // UnloadAll the native loader
3007 rv = mNativeComponentLoader->UnloadAll(aWhen);
3008 return rv;
3009}
3010
3011////////////////////////////////////////////////////////////////////////////////
3012
3013/**
3014 * AutoRegister(RegistrationInstant, const char *directory)
3015 *
3016 * Given a directory in the following format, this will ensure proper registration
3017 * of all components. No default directory is looked at.
3018 *
3019 * Directory and fullname are what NSPR will accept. For eg.
3020 * WIN y:/home/dp/mozilla/dist/bin
3021 * UNIX /home/dp/mozilla/dist/bin
3022 * MAC /Hard drive/mozilla/dist/apprunner
3023 *
3024 * This will take care not loading already registered dlls, finding and
3025 * registering new dlls, re-registration of modified dlls
3026 *
3027 */
3028
3029nsresult
3030nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec)
3031{
3032 return AutoRegisterImpl(when, inDirSpec);
3033}
3034
3035nsresult
3036nsComponentManagerImpl::AutoRegisterImpl(PRInt32 when,
3037 nsIFile *inDirSpec,
3038 PRBool fileIsCompDir)
3039{
3040 nsCOMPtr<nsIFile> dir;
3041 nsresult rv;
3042
3043#ifdef DEBUG
3044 // testing release behaviour
3045 if (getenv("XPCOM_NO_AUTOREG"))
3046 return NS_OK;
3047#endif
3048 if (inDirSpec)
3049 {
3050 // Use supplied components' directory
3051 dir = inDirSpec;
3052 }
3053 else
3054 {
3055 mComponentsDir->Clone(getter_AddRefs(dir));
3056 if (!dir)
3057 return NS_ERROR_NOT_INITIALIZED;
3058 }
3059
3060 nsCOMPtr<nsIInterfaceInfoManager> iim =
3061 dont_AddRef(XPTI_GetInterfaceInfoManager());
3062
3063 if (!iim)
3064 return NS_ERROR_UNEXPECTED;
3065
3066 // Notify observers of xpcom autoregistration start
3067 NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
3068 nsnull,
3069 "start");
3070
3071 /* do the native loader first, so we can find other loaders */
3072 rv = mNativeComponentLoader->AutoRegisterComponents((PRInt32)when, dir);
3073 if (NS_FAILED(rv)) return rv;
3074
3075#ifdef ENABLE_STATIC_COMPONENT_LOADER
3076 rv = mStaticComponentLoader->AutoRegisterComponents((PRInt32)when, inDirSpec);
3077 if (NS_FAILED(rv)) return rv;
3078#endif
3079
3080 /* do InterfaceInfoManager after native loader so it can use components. */
3081 rv = iim->AutoRegisterInterfaces();
3082 if (NS_FAILED(rv)) return rv;
3083
3084 if (!mCategoryManager) {
3085 NS_WARNING("mCategoryManager is null");
3086 return NS_ERROR_UNEXPECTED;
3087 }
3088
3089 nsCOMPtr<nsISimpleEnumerator> loaderEnum;
3090 rv = mCategoryManager->EnumerateCategory("component-loader",
3091 getter_AddRefs(loaderEnum));
3092 if (NS_FAILED(rv)) return rv;
3093
3094 PRBool hasMore;
3095 while (NS_SUCCEEDED(loaderEnum->HasMoreElements(&hasMore)) && hasMore) {
3096 nsCOMPtr<nsISupports> supports;
3097 if (NS_FAILED(loaderEnum->GetNext(getter_AddRefs(supports))))
3098 continue;
3099
3100 nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports);
3101 if (!supStr)
3102 continue;
3103
3104 nsCAutoString loaderType;
3105 if (NS_FAILED(supStr->GetData(loaderType)))
3106 continue;
3107
3108 // We depend on the loader being created. Add the loader type and
3109 // create the loader object too.
3110 nsCOMPtr<nsIComponentLoader> loader;
3111 int typeIndex;
3112 rv = AddLoaderType(loaderType.get(), &typeIndex);
3113 if (NS_FAILED(rv))
3114 return rv;
3115 GetLoaderForType(typeIndex, getter_AddRefs(loader));
3116 }
3117
3118 rv = AutoRegisterNonNativeComponents(dir.get());
3119
3120 // Notify observers of xpcom autoregistration completion
3121 NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
3122 nsnull,
3123 "end");
3124
3125 if (mRegistryDirty)
3126 FlushPersistentStore(PR_TRUE);
3127 return rv;
3128}
3129
3130nsresult
3131nsComponentManagerImpl::AutoRegisterNonNativeComponents(nsIFile* spec)
3132{
3133 nsresult rv = NS_OK;
3134 nsCOMPtr<nsIFile> directory = spec;
3135
3136 if (!directory) {
3137 mComponentsDir->Clone(getter_AddRefs(directory));
3138 if (!directory)
3139 return NS_ERROR_NOT_INITIALIZED;
3140 }
3141
3142 for (int i = 1; i < mNLoaderData; i++) {
3143 if (!mLoaderData[i].loader) {
3144 rv = GetLoaderForType(i, &mLoaderData[i].loader);
3145 if (NS_FAILED(rv))
3146 continue;
3147 }
3148 rv = mLoaderData[i].loader->AutoRegisterComponents(0, directory);
3149 if (NS_FAILED(rv))
3150 break;
3151 }
3152
3153 if (NS_SUCCEEDED(rv))
3154 {
3155 PRBool registered;
3156 do {
3157 registered = PR_FALSE;
3158 for (int i = 0; i < mNLoaderData; i++) {
3159 PRBool b = PR_FALSE;
3160 if (mLoaderData[i].loader) {
3161 rv = mLoaderData[i].loader->RegisterDeferredComponents(0, &b);
3162 if (NS_FAILED(rv))
3163 continue;
3164 registered |= b;
3165 }
3166 }
3167 } while (NS_SUCCEEDED(rv) && registered);
3168 }
3169 return rv;
3170}
3171nsresult
3172nsComponentManagerImpl::AutoRegisterComponent(PRInt32 when,
3173 nsIFile *component)
3174{
3175 nsresult rv = NS_OK, res = NS_ERROR_FACTORY_NOT_REGISTERED;
3176 /*
3177 * Do we have to give the native loader first crack at it?
3178 * I vote ``no''.
3179 */
3180 for (int i = 0; i < mNLoaderData; i++) {
3181 PRBool didRegister;
3182 if (!mLoaderData[i].loader) {
3183 nsCOMPtr<nsIComponentLoader> loader;
3184 rv = GetLoaderForType(i, getter_AddRefs(loader));
3185 if (NS_FAILED(rv))
3186 continue;
3187 // |GetLoaderForType| has filled in |mLoaderData[i].loader|:
3188 NS_ASSERTION(loader == mLoaderData[i].loader, "oops");
3189 }
3190 rv = mLoaderData[i].loader->AutoRegisterComponent((int)when, component, &didRegister);
3191 if (NS_FAILED(rv)) {
3192 res = rv;
3193 } else if (didRegister) {
3194 return rv;
3195 }
3196 }
3197 return res;
3198}
3199
3200nsresult
3201nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 when,
3202 nsIFile *component)
3203{
3204 nsresult rv = NS_OK;
3205 for (int i = 0; i < mNLoaderData; i++) {
3206 PRBool didUnRegister;
3207 if (!mLoaderData[i].loader) {
3208 rv = GetLoaderForType(i, &mLoaderData[i].loader);
3209 if (NS_FAILED(rv))
3210 continue;
3211 }
3212 rv = mLoaderData[i].loader->AutoUnregisterComponent(when, component, &didUnRegister);
3213 if (NS_SUCCEEDED(rv) && didUnRegister) {
3214 // we need to remove this file from our list of known libraries.
3215 RemoveFileInfo(component, nsnull);
3216 mRegistryDirty = PR_TRUE;
3217 break;
3218 }
3219 }
3220 return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK;
3221}
3222
3223nsresult
3224nsComponentManagerImpl::IsRegistered(const nsCID &aClass,
3225 PRBool *aRegistered)
3226{
3227 if (!aRegistered)
3228 {
3229 NS_ASSERTION(0, "null ptr");
3230 return NS_ERROR_NULL_POINTER;
3231 }
3232 *aRegistered = (nsnull != GetFactoryEntry(aClass));
3233 return NS_OK;
3234}
3235
3236nsresult
3237nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEnumerator)
3238{
3239 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3240 if (!aEnumerator)
3241 {
3242 return NS_ERROR_NULL_POINTER;
3243 }
3244 *aEnumerator = nsnull;
3245
3246 nsresult rv;
3247
3248 PLDHashTableEnumeratorImpl *aEnum;
3249 rv = PL_NewDHashTableEnumerator(&mFactories,
3250 ConvertFactoryEntryToCID,
3251 (void*)this,
3252 &aEnum);
3253 if (NS_FAILED(rv))
3254 return rv;
3255
3256 *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum);
3257 return NS_OK;
3258}
3259
3260nsresult
3261nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEnumerator)
3262{
3263 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3264 if (!aEnumerator)
3265 {
3266 return NS_ERROR_NULL_POINTER;
3267 }
3268
3269 *aEnumerator = nsnull;
3270
3271 nsresult rv;
3272 PLDHashTableEnumeratorImpl *aEnum;
3273 rv = PL_NewDHashTableEnumerator(&mContractIDs,
3274 ConvertContractIDKeyToString,
3275 (void*)this,
3276 &aEnum);
3277 if (NS_FAILED(rv))
3278 return rv;
3279
3280 *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum);
3281 return NS_OK;
3282}
3283
3284// nsIComponentRegistrar
3285
3286NS_IMETHODIMP
3287nsComponentManagerImpl::AutoRegister(nsIFile *aSpec)
3288{
3289 if (aSpec == nsnull)
3290 return AutoRegisterImpl(0, aSpec);
3291
3292 PRBool directory;
3293 aSpec->IsDirectory(&directory);
3294
3295 if (directory)
3296 return AutoRegisterImpl(0, aSpec, PR_FALSE);
3297
3298 return AutoRegisterComponent(0, aSpec);
3299}
3300
3301NS_IMETHODIMP
3302nsComponentManagerImpl::AutoUnregister(nsIFile *aSpec)
3303{
3304 // unregistering a complete directory is not implmeneted yet...FIX
3305 if (aSpec == nsnull)
3306 return NS_ERROR_NOT_IMPLEMENTED;
3307
3308 PRBool directory;
3309 aSpec->IsDirectory(&directory);
3310
3311 if (directory)
3312 return NS_ERROR_NOT_IMPLEMENTED;
3313
3314 return AutoUnregisterComponent(0, aSpec);
3315}
3316
3317NS_IMETHODIMP
3318nsComponentManagerImpl::RegisterFactory(const nsCID & aClass,
3319 const char *aClassName,
3320 const char *aContractID,
3321 nsIFactory *aFactory)
3322{
3323 return RegisterFactory(aClass,
3324 aClassName,
3325 aContractID,
3326 aFactory,
3327 PR_TRUE);
3328}
3329
3330NS_IMETHODIMP
3331nsComponentManagerImpl::RegisterFactoryLocation(const nsCID & aClass,
3332 const char *aClassName,
3333 const char *aContractID,
3334 nsIFile *aFile,
3335 const char *loaderStr,
3336 const char *aType)
3337{
3338 nsXPIDLCString registryName;
3339
3340 if (!loaderStr)
3341 {
3342 nsresult rv = RegistryLocationForSpec(aFile, getter_Copies(registryName));
3343 if (NS_FAILED(rv))
3344 return rv;
3345 }
3346
3347 nsresult rv;
3348 rv = RegisterComponentWithType(aClass,
3349 aClassName,
3350 aContractID,
3351 aFile,
3352 (loaderStr ? loaderStr : registryName.get()),
3353 PR_TRUE,
3354 PR_TRUE,
3355 (aType ? aType : nativeComponentType));
3356 return rv;
3357}
3358
3359NS_IMETHODIMP
3360nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID & aClass,
3361 nsIFile *aFile)
3362{
3363 return UnregisterComponentSpec(aClass, aFile);
3364}
3365
3366NS_IMETHODIMP
3367nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass,
3368 PRBool *_retval)
3369{
3370 return IsRegistered(aClass, _retval);
3371}
3372
3373NS_IMETHODIMP
3374nsComponentManagerImpl::IsContractIDRegistered(const char *aClass,
3375 PRBool *_retval)
3376{
3377 nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass));
3378
3379 if (entry)
3380 *_retval = PR_TRUE;
3381 else
3382 *_retval = PR_FALSE;
3383 return NS_OK;
3384}
3385
3386NS_IMETHODIMP
3387nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator)
3388{
3389 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3390
3391 if (!aEnumerator)
3392 return NS_ERROR_NULL_POINTER;
3393
3394 *aEnumerator = nsnull;
3395
3396 nsresult rv;
3397 PLDHashTableEnumeratorImpl *aEnum;
3398 rv = PL_NewDHashTableEnumerator(&mFactories,
3399 ConvertFactoryEntryToCID,
3400 (void*)this,
3401 &aEnum);
3402 if (NS_FAILED(rv))
3403 return rv;
3404
3405 *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum);
3406 return NS_OK;
3407}
3408
3409NS_IMETHODIMP
3410nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator)
3411{
3412 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3413 if (!aEnumerator)
3414 return NS_ERROR_NULL_POINTER;
3415
3416 *aEnumerator = nsnull;
3417
3418 nsresult rv;
3419 PLDHashTableEnumeratorImpl *aEnum;
3420 rv = PL_NewDHashTableEnumerator(&mContractIDs,
3421 ConvertContractIDKeyToString,
3422 (void*)this,
3423 &aEnum);
3424 if (NS_FAILED(rv))
3425 return rv;
3426
3427 *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum);
3428 return NS_OK;
3429}
3430
3431NS_IMETHODIMP
3432nsComponentManagerImpl::CIDToContractID(const nsCID & aClass,
3433 char **_retval)
3434{
3435 return CLSIDToContractID(aClass,
3436 nsnull,
3437 _retval);
3438}
3439
3440NS_IMETHODIMP
3441nsComponentManagerImpl::ContractIDToCID(const char *aContractID,
3442 nsCID * *_retval)
3443{
3444 *_retval = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
3445 if (!*_retval)
3446 return NS_ERROR_OUT_OF_MEMORY;
3447
3448 nsresult rv = ContractIDToClassID(aContractID, *_retval);
3449 if (NS_FAILED(rv)) {
3450 nsMemory::Free(*_retval);
3451 *_retval = nsnull;
3452 }
3453 return rv;
3454}
3455
3456// end nsIComponentRegistrar
3457
3458
3459
3460
3461NS_IMETHODIMP
3462nsComponentManagerImpl::HasFileChanged(nsIFile *file, const char *loaderString, PRInt64 modDate, PRBool *_retval)
3463{
3464 *_retval = PR_TRUE;
3465
3466 nsXPIDLCString registryName;
3467 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3468 if (NS_FAILED(rv))
3469 return rv;
3470
3471 nsCStringKey key(registryName);
3472 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
3473 if (entry)
3474 *_retval = entry->Modified(&modDate);
3475 else
3476 *_retval = PR_TRUE;
3477
3478 return NS_OK;
3479}
3480
3481NS_IMETHODIMP
3482nsComponentManagerImpl::SaveFileInfo(nsIFile *file, const char *loaderString, PRInt64 modDate)
3483{
3484 mRegistryDirty = PR_TRUE;
3485 nsXPIDLCString registryName;
3486 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3487 if (NS_FAILED(rv))
3488 return rv;
3489
3490 // check to see if exists in the array before adding it so that we don't have dups.
3491 nsCStringKey key(registryName);
3492 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
3493
3494 if (entry)
3495 {
3496 entry->SetDate(&modDate);
3497 return NS_OK;
3498 }
3499
3500 entry = new AutoRegEntry(registryName, &modDate);
3501 if (!entry)
3502 return NS_ERROR_OUT_OF_MEMORY;
3503
3504 mAutoRegEntries.Put(&key, entry);
3505 return NS_OK;
3506}
3507
3508NS_IMETHODIMP
3509nsComponentManagerImpl::RemoveFileInfo(nsIFile *file, const char *loaderString)
3510{
3511 mRegistryDirty = PR_TRUE;
3512 nsXPIDLCString registryName;
3513 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3514 if (NS_FAILED(rv))
3515 return rv;
3516
3517 nsCStringKey key(registryName);
3518 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Remove(&key);
3519 if (entry)
3520 delete entry;
3521
3522 return NS_OK;
3523}
3524
3525NS_IMETHODIMP
3526nsComponentManagerImpl::GetOptionalData(nsIFile *file,
3527 const char *loaderString,
3528 char **_retval)
3529{
3530 nsXPIDLCString registryName;
3531 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3532 if (NS_FAILED(rv))
3533 return rv;
3534
3535 nsCStringKey key(registryName);
3536 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
3537 if (!entry) {
3538 return NS_ERROR_NOT_INITIALIZED;
3539 }
3540 const char* opData = entry->GetOptionalData();
3541
3542 if (opData)
3543 *_retval = ToNewCString(nsDependentCString(opData));
3544 else
3545 *_retval = nsnull;
3546 return NS_OK;
3547 }
3548
3549NS_IMETHODIMP
3550nsComponentManagerImpl::SetOptionalData(nsIFile *file,
3551 const char *loaderString,
3552 const char *data)
3553{
3554 nsXPIDLCString registryName;
3555 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3556 if (NS_FAILED(rv))
3557 return rv;
3558
3559 nsCStringKey key(registryName);
3560 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
3561
3562 if (!entry) {
3563 PRInt64 zero = LL_Zero();
3564 entry = new AutoRegEntry(registryName, &zero);
3565 if (!entry)
3566 return NS_ERROR_OUT_OF_MEMORY;
3567
3568 mAutoRegEntries.Put(&key, entry);
3569 }
3570
3571 entry->SetOptionalData(data);
3572
3573 return NS_OK;
3574 }
3575
3576
3577NS_IMETHODIMP
3578nsComponentManagerImpl::FlushPersistentStore(PRBool now)
3579{
3580 mRegistryDirty = PR_TRUE;
3581 if (now)
3582 return WritePersistentRegistry();
3583
3584 return NS_OK;
3585}
3586
3587
3588////////////////////////////////////////////////////////////////////////////////
3589// Static Access Functions
3590////////////////////////////////////////////////////////////////////////////////
3591
3592NS_COM nsresult
3593NS_GetGlobalComponentManager(nsIComponentManager* *result)
3594{
3595#ifdef DEBUG_dougt
3596 // NS_WARNING("DEPRECATED FUNCTION: Use NS_GetComponentManager");
3597#endif
3598 nsresult rv = NS_OK;
3599
3600 if (nsComponentManagerImpl::gComponentManager == nsnull)
3601 {
3602 // XPCOM needs initialization.
3603 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3604 }
3605
3606 if (NS_SUCCEEDED(rv))
3607 {
3608 // NO ADDREF since this is never intended to be released.
3609 // See nsComponentManagerObsolete.h for the reason for such
3610 // casting uglyness
3611 *result = (nsIComponentManager*)(void*)(nsIComponentManagerObsolete*) nsComponentManagerImpl::gComponentManager;
3612 }
3613
3614 return rv;
3615}
3616
3617NS_COM nsresult
3618NS_GetComponentManager(nsIComponentManager* *result)
3619{
3620 if (nsComponentManagerImpl::gComponentManager == nsnull)
3621 {
3622 // XPCOM needs initialization.
3623 nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3624 if (NS_FAILED(rv))
3625 return rv;
3626 }
3627
3628 *result = NS_STATIC_CAST(nsIComponentManager*,
3629 nsComponentManagerImpl::gComponentManager);
3630 NS_IF_ADDREF(*result);
3631 return NS_OK;
3632}
3633
3634NS_COM nsresult
3635NS_GetServiceManager(nsIServiceManager* *result)
3636{
3637 nsresult rv = NS_OK;
3638
3639 if (nsComponentManagerImpl::gComponentManager == nsnull)
3640 {
3641#ifdef VBOX
3642 // While XPCOM might need initialization, we're not in a position
3643 // to pass the right values to this call. This is actually triggered
3644 // on object destruction, so there is no point in re-initializing,
3645 // and actually the attempt would lead to nested calls to
3646 // xptiInterfaceInfoManager::BuildFileSearchPath, which it detects
3647 // as unsafe in debug builds. Just fail, no real problem.
3648#ifdef DEBUG
3649 printf("NS_GetServiceManager: no current instance, suppressed XPCOM initialization!\n");
3650#endif
3651 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
3652#else /* !VBOX */
3653 // XPCOM needs initialization.
3654 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3655#endif /* !VBOX */
3656 }
3657
3658 if (NS_FAILED(rv))
3659 return rv;
3660
3661 *result = NS_STATIC_CAST(nsIServiceManager*,
3662 nsComponentManagerImpl::gComponentManager);
3663 NS_IF_ADDREF(*result);
3664 return NS_OK;
3665}
3666
3667
3668NS_COM nsresult
3669NS_GetComponentRegistrar(nsIComponentRegistrar* *result)
3670{
3671 nsresult rv = NS_OK;
3672
3673 if (nsComponentManagerImpl::gComponentManager == nsnull)
3674 {
3675 // XPCOM needs initialization.
3676 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3677 }
3678
3679 if (NS_FAILED(rv))
3680 return rv;
3681
3682 *result = NS_STATIC_CAST(nsIComponentRegistrar*,
3683 nsComponentManagerImpl::gComponentManager);
3684 NS_IF_ADDREF(*result);
3685 return NS_OK;
3686}
3687
3688
3689// nsIComponentLoaderManager is not frozen, but is defined here
3690// so that I can use it internally in xpcom.
3691nsresult
3692NS_GetComponentLoaderManager(nsIComponentLoaderManager* *result)
3693{
3694 nsresult rv = NS_OK;
3695
3696 if (nsComponentManagerImpl::gComponentManager == NULL)
3697 {
3698 // XPCOM needs initialization.
3699 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3700 }
3701
3702 if (NS_FAILED(rv))
3703 return rv;
3704
3705 *result = NS_STATIC_CAST(nsIComponentLoaderManager*,
3706 nsComponentManagerImpl::gComponentManager);
3707 NS_IF_ADDREF(*result);
3708 return NS_OK;
3709}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette