VirtualBox

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

Last change on this file since 101967 was 101907, checked in by vboxsync, 15 months ago

libs/xpcom: Remove unused code from nsprpub, bugref:10545 [fix]

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

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