VirtualBox

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

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 112.3 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 "prcmon.h"
83#include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself...
84
85#include "nsInt64.h"
86#include "nsManifestLineReader.h"
87
88#include NEW_H // for placement new
89
90
91#ifdef XP_BEOS
92#include <FindDirectory.h>
93#include <Path.h>
94#endif
95
96#include "prlog.h"
97
98PRLogModuleInfo* nsComponentManagerLog = nsnull;
99
100#if 0 || defined (DEBUG_timeless)
101 #define SHOW_DENIED_ON_SHUTDOWN
102 #define SHOW_CI_ON_EXISTING_SERVICE
103 #define XPCOM_CHECK_PENDING_CIDS
104#endif
105
106// Loader Types
107#define NS_LOADER_DATA_ALLOC_STEP 6
108
109// Bloated registry buffer size to improve startup performance -- needs to
110// be big enough to fit the entire file into memory or it'll thrash.
111// 512K is big enough to allow for some future growth in the registry.
112#define BIG_REGISTRY_BUFLEN (512*1024)
113
114// Common Key Names
115const char classIDKeyName[]="classID";
116const char classesKeyName[]="contractID";
117const char componentLoadersKeyName[]="componentLoaders";
118const char componentsKeyName[]="components";
119const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components";
120const char xpcomKeyName[]="software/mozilla/XPCOM";
121
122// Common Value Names
123const char classIDValueName[]="ClassID";
124const char classNameValueName[]="ClassName";
125const char componentCountValueName[]="ComponentsCount";
126const char componentTypeValueName[]="ComponentType";
127const char contractIDValueName[]="ContractID";
128const char fileSizeValueName[]="FileSize";
129const char inprocServerValueName[]="InprocServer";
130const char lastModValueName[]="LastModTimeStamp";
131const char nativeComponentType[]="application/x-mozilla-native";
132const char staticComponentType[]="application/x-mozilla-static";
133const char versionValueName[]="VersionString";
134
135const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:";
136const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:";
137const static char XPCOM_GRECOMPONENT_PREFIX[] = "gre:";
138
139static const char gIDFormat[] =
140 "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
141
142
143#define NS_EMPTY_IID \
144{ \
145 0x00000000, \
146 0x0000, \
147 0x0000, \
148 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \
149}
150
151NS_DEFINE_CID(kEmptyCID, NS_EMPTY_IID);
152NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
153
154#define UID_STRING_LENGTH 39
155
156// Set to true from NS_ShutdownXPCOM.
157extern PRBool gXPCOMShuttingDown;
158
159static void GetIDString(const nsID& aCID, char buf[UID_STRING_LENGTH])
160{
161 PR_snprintf(buf, UID_STRING_LENGTH, gIDFormat,
162 aCID.m0, (PRUint32) aCID.m1, (PRUint32) aCID.m2,
163 (PRUint32) aCID.m3[0], (PRUint32) aCID.m3[1],
164 (PRUint32) aCID.m3[2], (PRUint32) aCID.m3[3],
165 (PRUint32) aCID.m3[4], (PRUint32) aCID.m3[5],
166 (PRUint32) aCID.m3[6], (PRUint32) aCID.m3[7]);
167}
168
169nsresult
170nsCreateInstanceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
171{
172 /*
173 * If I were a real man, I would consolidate this with
174 * nsGetServiceFromContractID::operator().
175 */
176 nsresult rv;
177 nsXPIDLCString value;
178 nsCOMPtr<nsIComponentManager> compMgr;
179 nsCOMPtr<nsICategoryManager> catman =
180 do_GetService(kCategoryManagerCID, &rv);
181
182 if (NS_FAILED(rv)) goto error;
183
184 if (!mCategory || !mEntry) {
185 // when categories have defaults, use that for null mEntry
186 rv = NS_ERROR_NULL_POINTER;
187 goto error;
188 }
189
190 /* find the contractID for category.entry */
191 rv = catman->GetCategoryEntry(mCategory, mEntry,
192 getter_Copies(value));
193 if (NS_FAILED(rv)) goto error;
194 if (!value) {
195 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
196 goto error;
197 }
198 NS_GetComponentManager(getter_AddRefs(compMgr));
199 if (!compMgr)
200 return NS_ERROR_FAILURE;
201 compMgr->CreateInstanceByContractID(value,
202 mOuter,
203 aIID,
204 aInstancePtr);
205 if (NS_FAILED(rv)) {
206 error:
207 *aInstancePtr = 0;
208 }
209
210 *mErrorPtr = rv;
211 return rv;
212}
213
214
215nsresult
216nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
217{
218 nsresult rv;
219 nsXPIDLCString value;
220 nsCOMPtr<nsICategoryManager> catman =
221 do_GetService(kCategoryManagerCID, &rv);
222 if (NS_FAILED(rv)) goto error;
223 if (!mCategory || !mEntry) {
224 // when categories have defaults, use that for null mEntry
225 rv = NS_ERROR_NULL_POINTER;
226 goto error;
227 }
228 /* find the contractID for category.entry */
229 rv = catman->GetCategoryEntry(mCategory, mEntry,
230 getter_Copies(value));
231 if (NS_FAILED(rv)) goto error;
232 if (!value) {
233 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
234 goto error;
235 }
236 if (mServiceManager) {
237 rv = mServiceManager->GetServiceByContractID(value, aIID, (void**)aInstancePtr);
238 } else {
239 nsCOMPtr<nsIServiceManager> mgr;
240 NS_GetServiceManager(getter_AddRefs(mgr));
241 if (mgr)
242 rv = mgr->GetServiceByContractID(value, aIID, (void**)aInstancePtr);
243 }
244 if (NS_FAILED(rv)) {
245 error:
246 *aInstancePtr = 0;
247 }
248 *mErrorPtr = rv;
249 return rv;
250}
251
252////////////////////////////////////////////////////////////////////////////////
253// Arena helper functions
254////////////////////////////////////////////////////////////////////////////////
255char *
256ArenaStrndup(const char *s, PRUint32 len, PLArenaPool *arena)
257{
258 void *mem;
259 // Include trailing null in the len
260 PL_ARENA_ALLOCATE(mem, arena, len+1);
261 if (mem)
262 memcpy(mem, s, len+1);
263 return NS_STATIC_CAST(char *, mem);
264}
265
266char*
267ArenaStrdup(const char *s, PLArenaPool *arena)
268{
269 return ArenaStrndup(s, strlen(s), arena);
270}
271
272////////////////////////////////////////////////////////////////////////////////
273// Hashtable Callbacks
274////////////////////////////////////////////////////////////////////////////////
275
276PRBool PR_CALLBACK
277nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure);
278
279PR_STATIC_CALLBACK(const void *)
280factory_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
281{
282 nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
283
284 return &entry->mFactoryEntry->mCid;
285}
286
287PR_STATIC_CALLBACK(PLDHashNumber)
288factory_HashKey(PLDHashTable *aTable, const void *aKey)
289{
290 const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey);
291
292 return cidp->m0;
293}
294
295PR_STATIC_CALLBACK(PRBool)
296factory_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr,
297 const void *aKey)
298{
299 const nsFactoryTableEntry* entry =
300 NS_STATIC_CAST(const nsFactoryTableEntry*, aHdr);
301 const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey);
302
303 return (entry->mFactoryEntry->mCid).Equals(*cidp);
304}
305
306PR_STATIC_CALLBACK(void)
307factory_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
308{
309 nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
310 // nsFactoryEntry is arena allocated. So we dont delete it.
311 // We call the destructor by hand.
312 entry->mFactoryEntry->~nsFactoryEntry();
313 PL_DHashClearEntryStub(aTable, aHdr);
314}
315
316static const PLDHashTableOps factory_DHashTableOps = {
317 PL_DHashAllocTable,
318 PL_DHashFreeTable,
319 factory_GetKey,
320 factory_HashKey,
321 factory_MatchEntry,
322 PL_DHashMoveEntryStub,
323 factory_ClearEntry,
324 PL_DHashFinalizeStub,
325};
326
327PR_STATIC_CALLBACK(void)
328contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
329{
330 nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
331 if (entry->mFactoryEntry->mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY &&
332 entry->mFactoryEntry->mCid.Equals(kEmptyCID)) {
333 // this object is owned by the hash.
334 // nsFactoryEntry is arena allocated. So we dont delete it.
335 // We call the destructor by hand.
336 entry->mFactoryEntry->~nsFactoryEntry();
337 }
338
339 // contractIDs are arena allocated. No need to free them.
340
341 PL_DHashClearEntryStub(aTable, aHdr);
342}
343
344static const PLDHashTableOps contractID_DHashTableOps = {
345 PL_DHashAllocTable,
346 PL_DHashFreeTable,
347 PL_DHashGetKeyStub,
348 PL_DHashStringKey,
349 PL_DHashMatchStringKey,
350 PL_DHashMoveEntryStub,
351 contractID_ClearEntry,
352 PL_DHashFinalizeStub,
353};
354
355////////////////////////////////////////////////////////////////////////////////
356// nsFactoryEntry
357////////////////////////////////////////////////////////////////////////////////
358
359MOZ_DECL_CTOR_COUNTER(nsFactoryEntry)
360nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
361 const char *aLocation,
362 PRUint32 locationlen,
363 int aType,
364 class nsFactoryEntry* parent)
365: mCid(aClass), mTypeIndex(aType), mParent(parent)
366{
367 // Arena allocate the location string
368 mLocation = ArenaStrndup(aLocation, locationlen, &nsComponentManagerImpl::gComponentManager->mArena);
369}
370
371nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
372 nsIFactory *aFactory,
373 class nsFactoryEntry* parent)
374: mCid(aClass), mTypeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY), mParent(parent)
375{
376 mFactory = aFactory;
377 mLocation = nsnull;
378}
379
380// nsFactoryEntry is usually arena allocated including the strings it
381// holds. So we call destructor by hand.
382nsFactoryEntry::~nsFactoryEntry(void)
383{
384 // Release the reference to the factory
385 mFactory = nsnull;
386
387 // Release any service reference
388 mServiceObject = nsnull;
389
390 // nsFactoryEntry is arena allocated. So we dont delete it.
391 // We call the destructor by hand.
392 if (mParent)
393 mParent->~nsFactoryEntry();
394}
395
396nsresult
397nsFactoryEntry::ReInit(const nsCID &aClass, const char *aLocation, int aType)
398{
399 NS_ENSURE_TRUE(mTypeIndex != NS_COMPONENT_TYPE_FACTORY_ONLY, NS_ERROR_INVALID_ARG);
400 // cid has to match
401 // SERVICE_ONLY entries can be promoted to an entry of another type
402 NS_ENSURE_TRUE((mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || mCid.Equals(aClass)),
403 NS_ERROR_INVALID_ARG);
404
405 // Arena allocate the location string
406 mLocation = ArenaStrdup(aLocation, &nsComponentManagerImpl::gComponentManager->mArena);
407
408 mTypeIndex = aType;
409 return NS_OK;
410}
411
412////////////////////////////////////////////////////////////////////////////////
413// Hashtable Enumeration
414////////////////////////////////////////////////////////////////////////////////
415typedef NS_CALLBACK(EnumeratorConverter)(PLDHashTable *table,
416 const PLDHashEntryHdr *hdr,
417 void *data,
418 nsISupports **retval);
419
420class PLDHashTableEnumeratorImpl : public nsIBidirectionalEnumerator,
421 public nsISimpleEnumerator
422{
423public:
424 NS_DECL_ISUPPORTS
425 NS_DECL_NSIENUMERATOR
426 NS_DECL_NSIBIDIRECTIONALENUMERATOR
427 NS_DECL_NSISIMPLEENUMERATOR
428
429 PLDHashTableEnumeratorImpl(PLDHashTable *table,
430 EnumeratorConverter converter,
431 void *converterData);
432 PRInt32 Count() { return mCount; }
433private:
434 PLDHashTableEnumeratorImpl(); /* no implementation */
435
436 ~PLDHashTableEnumeratorImpl();
437 NS_IMETHODIMP ReleaseElements();
438
439 nsVoidArray mElements;
440 PRInt32 mCount, mCurrent;
441 PRMonitor* mMonitor;
442
443 struct Closure {
444 PRBool succeeded;
445 EnumeratorConverter converter;
446 void *data;
447 PLDHashTableEnumeratorImpl *impl;
448 };
449
450 static PLDHashOperator PR_CALLBACK Enumerator(PLDHashTable *table,
451 PLDHashEntryHdr *hdr,
452 PRUint32 number,
453 void *data);
454};
455
456// static
457PLDHashOperator PR_CALLBACK
458PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable *table,
459 PLDHashEntryHdr *hdr,
460 PRUint32 number,
461 void *data)
462{
463 Closure *c = NS_REINTERPRET_CAST(Closure *, data);
464 nsISupports *converted;
465 if (NS_FAILED(c->converter(table, hdr, c->data, &converted)) ||
466 !c->impl->mElements.AppendElement(converted)) {
467 c->succeeded = PR_FALSE;
468 return PL_DHASH_STOP;
469 }
470
471 c->succeeded = PR_TRUE;
472 return PL_DHASH_NEXT;
473}
474
475PLDHashTableEnumeratorImpl::PLDHashTableEnumeratorImpl(PLDHashTable *table,
476 EnumeratorConverter converter,
477 void *converterData)
478: mCurrent(0)
479{
480 mMonitor = nsAutoMonitor::NewMonitor("PLDHashTableEnumeratorImpl");
481 NS_ASSERTION(mMonitor, "NULL Monitor");
482
483 nsAutoMonitor mon(mMonitor);
484
485 Closure c = { PR_FALSE, converter, converterData, this };
486 mCount = PL_DHashTableEnumerate(table, Enumerator, &c);
487 if (!c.succeeded) {
488 ReleaseElements();
489 mCount = 0;
490 }
491}
492
493NS_IMPL_ISUPPORTS3(PLDHashTableEnumeratorImpl,
494 nsIBidirectionalEnumerator,
495 nsIEnumerator,
496 nsISimpleEnumerator)
497
498PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl()
499{
500 (void) ReleaseElements();
501
502 // Destroy the Lock
503 if (mMonitor)
504 nsAutoMonitor::DestroyMonitor(mMonitor);
505}
506
507NS_IMETHODIMP
508PLDHashTableEnumeratorImpl::ReleaseElements()
509{
510 for (PRInt32 i = 0; i < mCount; i++) {
511 nsISupports *supports = NS_REINTERPRET_CAST(nsISupports *,
512 mElements[i]);
513 NS_IF_RELEASE(supports);
514 }
515 return NS_OK;
516}
517
518NS_IMETHODIMP
519PL_NewDHashTableEnumerator(PLDHashTable *table,
520 EnumeratorConverter converter,
521 void *converterData,
522 PLDHashTableEnumeratorImpl **retval)
523{
524 PLDHashTableEnumeratorImpl *impl =
525 new PLDHashTableEnumeratorImpl(table, converter, converterData);
526
527 if (!impl)
528 return NS_ERROR_OUT_OF_MEMORY;
529
530 NS_ADDREF(impl);
531
532 if (impl->Count() == -1) {
533 // conversion failed
534 NS_RELEASE(impl);
535 return NS_ERROR_FAILURE;
536 }
537
538 *retval = impl;
539 return NS_OK;
540}
541
542NS_IMETHODIMP
543PLDHashTableEnumeratorImpl::First()
544{
545 if (!mCount)
546 return NS_ERROR_FAILURE;
547
548 mCurrent = 0;
549 return NS_OK;
550}
551
552NS_IMETHODIMP
553PLDHashTableEnumeratorImpl::Last()
554{
555 if (!mCount)
556 return NS_ERROR_FAILURE;
557 mCurrent = mCount - 1;
558 return NS_OK;
559}
560
561NS_IMETHODIMP
562PLDHashTableEnumeratorImpl::Prev()
563{
564 if (!mCurrent)
565 return NS_ERROR_FAILURE;
566
567 mCurrent--;
568 return NS_OK;
569}
570
571NS_IMETHODIMP
572PLDHashTableEnumeratorImpl::Next()
573{
574 // If empty or we're past the end, or we are at the end return error
575 if (!mCount || (mCurrent == mCount) || (++mCurrent == mCount))
576 return NS_ERROR_FAILURE;
577
578 return NS_OK;
579}
580
581NS_IMETHODIMP
582PLDHashTableEnumeratorImpl::CurrentItem(nsISupports **retval)
583{
584 if (!mCount || mCurrent == mCount)
585 return NS_ERROR_FAILURE;
586
587 *retval = NS_REINTERPRET_CAST(nsISupports *, mElements[mCurrent]);
588 if (*retval)
589 NS_ADDREF(*retval);
590
591 return NS_OK;
592}
593
594NS_IMETHODIMP
595PLDHashTableEnumeratorImpl::IsDone()
596{
597 if (!mCount || (mCurrent == mCount))
598 return NS_OK;
599
600 return NS_ENUMERATOR_FALSE;
601}
602
603NS_IMETHODIMP
604PLDHashTableEnumeratorImpl::HasMoreElements(PRBool *_retval)
605{
606 if (!mCount || (mCurrent == mCount))
607 *_retval = PR_FALSE;
608 else
609 *_retval = PR_TRUE;
610
611 return NS_OK;
612}
613
614NS_IMETHODIMP
615PLDHashTableEnumeratorImpl::GetNext(nsISupports **_retval)
616{
617 nsresult rv = Next();
618 if (NS_FAILED(rv)) return rv;
619
620 return CurrentItem(_retval);
621}
622
623static NS_IMETHODIMP
624ConvertFactoryEntryToCID(PLDHashTable *table,
625 const PLDHashEntryHdr *hdr,
626 void *data, nsISupports **retval)
627{
628 nsresult rv;
629 nsCOMPtr<nsISupportsID> wrapper;
630
631 nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data);
632
633 rv = cm->CreateInstanceByContractID(NS_SUPPORTS_ID_CONTRACTID, nsnull,
634 NS_GET_IID(nsISupportsID), getter_AddRefs(wrapper));
635
636 NS_ENSURE_SUCCESS(rv, rv);
637
638 const nsFactoryTableEntry *entry =
639 NS_REINTERPRET_CAST(const nsFactoryTableEntry *, hdr);
640 if (entry) {
641 nsFactoryEntry *fe = entry->mFactoryEntry;
642
643 wrapper->SetData(&fe->mCid);
644 *retval = wrapper;
645 NS_ADDREF(*retval);
646 return NS_OK;
647 }
648 *retval = nsnull;
649
650 return rv;
651}
652
653static NS_IMETHODIMP
654ConvertContractIDKeyToString(PLDHashTable *table,
655 const PLDHashEntryHdr *hdr,
656 void *data, nsISupports **retval)
657{
658 nsresult rv;
659 nsCOMPtr<nsISupportsCString> wrapper;
660
661 nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data);
662
663 rv = cm->CreateInstanceByContractID(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull,
664 NS_GET_IID(nsISupportsCString), getter_AddRefs(wrapper));
665
666 NS_ENSURE_SUCCESS(rv, rv);
667
668 const nsContractIDTableEntry *entry =
669 NS_REINTERPRET_CAST(const nsContractIDTableEntry *, hdr);
670
671 wrapper->SetData(nsDependentCString(entry->mContractID,
672 entry->mContractIDLen));
673 *retval = wrapper;
674 NS_ADDREF(*retval);
675 return NS_OK;
676}
677
678// this is safe to call during InitXPCOM
679static nsresult GetLocationFromDirectoryService(const char* prop,
680 nsIFile** aDirectory)
681{
682 nsCOMPtr<nsIProperties> directoryService;
683 nsDirectoryService::Create(nsnull,
684 NS_GET_IID(nsIProperties),
685 getter_AddRefs(directoryService));
686
687 if (!directoryService)
688 return NS_ERROR_FAILURE;
689
690 return directoryService->Get(prop,
691 NS_GET_IID(nsIFile),
692 (void**)aDirectory);
693}
694
695
696////////////////////////////////////////////////////////////////////////////////
697// nsComponentManagerImpl
698////////////////////////////////////////////////////////////////////////////////
699
700
701nsComponentManagerImpl::nsComponentManagerImpl()
702 :
703 mMon(NULL),
704 mNativeComponentLoader(0),
705#ifdef ENABLE_STATIC_COMPONENT_LOADER
706 mStaticComponentLoader(0),
707#endif
708 mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED),
709 mLoaderData(nsnull),
710 mRegistryDirty(PR_FALSE)
711{
712 mFactories.ops = nsnull;
713 mContractIDs.ops = nsnull;
714}
715
716nsresult nsComponentManagerImpl::Init(void)
717{
718 PR_ASSERT(mShuttingDown != NS_SHUTDOWN_INPROGRESS);
719 if (mShuttingDown == NS_SHUTDOWN_INPROGRESS)
720 return NS_ERROR_FAILURE;
721
722 mShuttingDown = NS_SHUTDOWN_NEVERHAPPENED;
723
724 if (nsComponentManagerLog == nsnull)
725 {
726 nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
727 }
728
729 // Initialize our arena
730 PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
731
732 if (!mFactories.ops) {
733 if (!PL_DHashTableInit(&mFactories, &factory_DHashTableOps,
734 0, sizeof(nsFactoryTableEntry),
735 1024)) {
736 mFactories.ops = nsnull;
737 return NS_ERROR_OUT_OF_MEMORY;
738 }
739
740 // Minimum alpha uses k=2 because nsFactoryTableEntry saves two
741 // words compared to what a chained hash table requires.
742 PL_DHashTableSetAlphaBounds(&mFactories,
743 0.875,
744 PL_DHASH_MIN_ALPHA(&mFactories, 2));
745 }
746
747 if (!mContractIDs.ops) {
748 if (!PL_DHashTableInit(&mContractIDs, &contractID_DHashTableOps,
749 0, sizeof(nsContractIDTableEntry),
750 1024)) {
751 mContractIDs.ops = nsnull;
752 return NS_ERROR_OUT_OF_MEMORY;
753 }
754
755 // Minimum alpha uses k=1 because nsContractIDTableEntry saves one
756 // word compared to what a chained hash table requires.
757#if 0
758 PL_DHashTableSetAlphaBounds(&mContractIDs,
759 0.875,
760 PL_DHASH_MIN_ALPHA(&mContractIDs, 1));
761#endif
762 }
763 if (mMon == nsnull) {
764 mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl");
765 if (mMon == nsnull)
766 return NS_ERROR_OUT_OF_MEMORY;
767 }
768
769 if (mNativeComponentLoader == nsnull) {
770 /* Create the NativeComponentLoader */
771 mNativeComponentLoader = new nsNativeComponentLoader();
772 if (!mNativeComponentLoader)
773 return NS_ERROR_OUT_OF_MEMORY;
774 NS_ADDREF(mNativeComponentLoader);
775
776 nsresult rv = mNativeComponentLoader->Init(this, nsnull);
777 if (NS_FAILED(rv))
778 return rv;
779 }
780
781 // Add predefined loaders
782 mLoaderData = (nsLoaderdata *) PR_Malloc(sizeof(nsLoaderdata) * NS_LOADER_DATA_ALLOC_STEP);
783 if (!mLoaderData)
784 return NS_ERROR_OUT_OF_MEMORY;
785 mMaxNLoaderData = NS_LOADER_DATA_ALLOC_STEP;
786
787 mNLoaderData = NS_COMPONENT_TYPE_NATIVE;
788 mLoaderData[mNLoaderData].type = PL_strdup(nativeComponentType);
789 mLoaderData[mNLoaderData].loader = mNativeComponentLoader;
790 NS_ADDREF(mLoaderData[mNLoaderData].loader);
791 mNLoaderData++;
792
793#ifdef ENABLE_STATIC_COMPONENT_LOADER
794 if (mStaticComponentLoader == nsnull) {
795 extern nsresult NS_NewStaticComponentLoader(nsIComponentLoader **);
796 NS_NewStaticComponentLoader(&mStaticComponentLoader);
797 if (!mStaticComponentLoader)
798 return NS_ERROR_OUT_OF_MEMORY;
799 }
800
801 mLoaderData[mNLoaderData].type = PL_strdup(staticComponentType);
802 mLoaderData[mNLoaderData].loader = mStaticComponentLoader;
803 NS_ADDREF(mLoaderData[mNLoaderData].loader);
804 mNLoaderData++;
805
806 if (mStaticComponentLoader) {
807 /* Init the static loader */
808 mStaticComponentLoader->Init(this, nsnull);
809 }
810#endif
811 GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_DIR, getter_AddRefs(mComponentsDir));
812 if (!mComponentsDir)
813 return NS_ERROR_OUT_OF_MEMORY;
814
815 nsCAutoString componentDescriptor;
816 nsresult rv = mComponentsDir->GetNativePath(componentDescriptor);
817 if (NS_FAILED(rv))
818 return rv;
819
820 mComponentsOffset = componentDescriptor.Length();
821
822 GetLocationFromDirectoryService(NS_GRE_COMPONENT_DIR, getter_AddRefs(mGREComponentsDir));
823 if (mGREComponentsDir) {
824 nsresult rv = mGREComponentsDir->GetNativePath(componentDescriptor);
825 if (NS_FAILED(rv)) {
826 NS_WARNING("No GRE component manager");
827 return rv;
828 }
829 mGREComponentsOffset = componentDescriptor.Length();
830 }
831
832 GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_REGISTRY_FILE,
833 getter_AddRefs(mRegistryFile));
834
835 if(!mRegistryFile) {
836 NS_WARNING("No Component Registry file was found in the directory service");
837 return NS_ERROR_FAILURE;
838 }
839
840 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
841 ("nsComponentManager: Initialized."));
842
843 return NS_OK;
844}
845
846PRIntn PR_CALLBACK AutoRegEntryDestroy(nsHashKey *aKey, void *aData, void* aClosure)
847{
848 delete (AutoRegEntry*)aData;
849 return kHashEnumerateNext;
850}
851
852nsresult nsComponentManagerImpl::Shutdown(void)
853{
854 PR_ASSERT(mShuttingDown == NS_SHUTDOWN_NEVERHAPPENED);
855 if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED)
856 return NS_ERROR_FAILURE;
857
858 mShuttingDown = NS_SHUTDOWN_INPROGRESS;
859
860 // Shutdown the component manager
861 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
862
863 PRInt32 i;
864
865 // Write out our component data file.
866 if (mRegistryDirty) {
867 nsresult rv = WritePersistentRegistry();
868 if (NS_FAILED(rv)) {
869 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Could not write out perisistant registry."));
870#ifdef DEBUG
871 printf("Could not write out perisistant registry!\n");
872#endif
873 }
874 }
875
876 mAutoRegEntries.Reset(AutoRegEntryDestroy);
877
878 // Release all cached factories
879 if (mContractIDs.ops) {
880 PL_DHashTableFinish(&mContractIDs);
881 mContractIDs.ops = nsnull;
882 }
883 if (mFactories.ops) {
884 PL_DHashTableFinish(&mFactories);
885 mFactories.ops = nsnull;
886 }
887 // Unload libraries
888 UnloadLibraries(nsnull, NS_Shutdown);
889
890 // delete arena for strings and small objects
891 PL_FinishArenaPool(&mArena);
892
893 mComponentsDir = 0;
894
895 mCategoryManager = 0;
896
897 // Release all the component data - loaders and type strings
898 for (i=0; i < mNLoaderData; i++) {
899 NS_IF_RELEASE(mLoaderData[i].loader);
900 PL_strfree((char *)mLoaderData[i].type);
901 }
902 PR_Free(mLoaderData);
903 mLoaderData = nsnull;
904
905 // we have an extra reference on this one, which is probably a good thing
906 NS_IF_RELEASE(mNativeComponentLoader);
907#ifdef ENABLE_STATIC_COMPONENT_LOADER
908 NS_IF_RELEASE(mStaticComponentLoader);
909#endif
910
911 mShuttingDown = NS_SHUTDOWN_COMPLETE;
912
913 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete."));
914
915 return NS_OK;
916}
917
918nsComponentManagerImpl::~nsComponentManagerImpl()
919{
920 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction."));
921
922 if (mShuttingDown != NS_SHUTDOWN_COMPLETE)
923 Shutdown();
924
925 if (mMon) {
926 nsAutoMonitor::DestroyMonitor(mMon);
927 }
928 PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed."));
929}
930
931NS_IMPL_THREADSAFE_ISUPPORTS8(nsComponentManagerImpl,
932 nsIComponentManager,
933 nsIServiceManager,
934 nsISupportsWeakReference,
935 nsIInterfaceRequestor,
936 nsIComponentRegistrar,
937 nsIServiceManagerObsolete,
938 nsIComponentManagerObsolete,
939 nsIComponentLoaderManager)
940
941
942nsresult
943nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
944{
945 if (uuid.Equals(NS_GET_IID(nsINativeComponentLoader)))
946 {
947 if (!mNativeComponentLoader)
948 return NS_ERROR_NOT_INITIALIZED;
949
950 return mNativeComponentLoader->QueryInterface(uuid, result);
951 }
952
953 NS_WARNING("This isn't supported");
954 // fall through to QI as anything QIable is a superset of what can be
955 // got via the GetInterface()
956 return QueryInterface(uuid, result);
957}
958
959////////////////////////////////////////////////////////////////////////////////
960// nsComponentManagerImpl: Platform methods
961////////////////////////////////////////////////////////////////////////////////
962
963#define PERSISTENT_REGISTRY_VERSION_MINOR 5
964#define PERSISTENT_REGISTRY_VERSION_MAJOR 0
965
966
967AutoRegEntry::AutoRegEntry(const nsACString& name, PRInt64* modDate) :
968 mName(ToNewCString(name)),
969 mNameLen(name.Length()),
970 mData(nsnull),
971 mModDate(*modDate)
972{
973}
974
975AutoRegEntry::~AutoRegEntry()
976{
977 if (mName) PL_strfree(mName);
978 if (mData) PL_strfree(mData);
979}
980
981PRBool
982AutoRegEntry::Modified(PRInt64 *date)
983{
984 return !LL_EQ(*date, mModDate);
985}
986
987void
988AutoRegEntry::SetOptionalData(const char* data)
989{
990 if (mData)
991 PL_strfree(mData);
992
993 if (!data) {
994 mData = nsnull;
995 return;
996 }
997
998 mData = PL_strdup(data);
999}
1000
1001static
1002PRBool ReadSectionHeader(nsManifestLineReader& reader, const char *token)
1003{
1004 while (1)
1005 {
1006 if (*reader.LinePtr() == '[')
1007 {
1008 char* p = reader.LinePtr() + (reader.LineLength() - 1);
1009 if (*p != ']')
1010 break;
1011 *p = 0;
1012
1013 char* values[1];
1014 int lengths[1];
1015 if (2 != reader.ParseLine(values, lengths, 1))
1016 break;
1017
1018 // ignore the leading '['
1019 if (0 != PL_strcmp(values[0]+1, token))
1020 break;
1021
1022 return PR_TRUE;
1023 }
1024
1025 if (!reader.NextLine())
1026 break;
1027 }
1028 return PR_FALSE;
1029}
1030
1031nsresult
1032nsComponentManagerImpl::ReadPersistentRegistry()
1033{
1034
1035 // populate Category Manager. need to get this early so that we don't get
1036 // skipped by 'goto out'
1037 nsresult rv = GetService(kCategoryManagerCID,
1038 NS_GET_IID(nsICategoryManager),
1039 getter_AddRefs(mCategoryManager));
1040 if (NS_FAILED(rv))
1041 return rv;
1042
1043 nsAutoMonitor mon(mMon);
1044 nsManifestLineReader reader;
1045
1046 if (!mComponentsDir)
1047 return NS_ERROR_NOT_INITIALIZED; // this should have been set by Init().
1048
1049 PRFileDesc* fd = nsnull;
1050
1051 // Set From Init
1052 if (!mRegistryFile) {
1053 return NS_ERROR_FILE_NOT_FOUND;
1054 }
1055
1056 nsCOMPtr<nsIFile> file;
1057 mRegistryFile->Clone(getter_AddRefs(file));
1058 if (!file)
1059 return NS_ERROR_OUT_OF_MEMORY;
1060
1061 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
1062
1063 rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
1064 if (NS_FAILED(rv))
1065 return rv;
1066
1067 PRInt64 fileSize;
1068 rv = localFile->GetFileSize(&fileSize);
1069 if (NS_FAILED(rv))
1070 {
1071 PR_Close(fd);
1072 return rv;
1073 }
1074
1075 PRInt32 flen = nsInt64(fileSize);
1076 if (flen == 0)
1077 {
1078 PR_Close(fd);
1079 NS_WARNING("Persistent Registry Empty!");
1080 return NS_OK; // ERROR CONDITION
1081 }
1082
1083 char* registry = new char[flen+1];
1084 if (!registry)
1085 goto out;
1086
1087 if (flen > PR_Read(fd, registry, flen))
1088 {
1089 rv = NS_ERROR_FAILURE;
1090 goto out;
1091 }
1092 registry[flen] = '\0';
1093
1094 reader.Init(registry, flen);
1095
1096 if (ReadSectionHeader(reader, "HEADER"))
1097 goto out;
1098
1099 if (!reader.NextLine())
1100 goto out;
1101
1102 char* values[6];
1103 int lengths[6];
1104
1105 // VersionLiteral,major,minor
1106 if (3 != reader.ParseLine(values, lengths, 3))
1107 goto out;
1108
1109 // VersionLiteral
1110 if (!nsDependentCString(values[0], lengths[0]).EqualsLiteral("Version"))
1111 goto out;
1112
1113 // major
1114 if (PERSISTENT_REGISTRY_VERSION_MAJOR != atoi(values[1]))
1115 goto out;
1116
1117 // minor
1118 if (PERSISTENT_REGISTRY_VERSION_MINOR != atoi(values[2]))
1119 goto out;
1120
1121 if (ReadSectionHeader(reader, "COMPONENTS"))
1122 goto out;
1123
1124 while (1)
1125 {
1126 if (!reader.NextLine())
1127 break;
1128
1129 //name,last_modification_date[,optionaldata]
1130 int parts = reader.ParseLine(values, lengths, 3);
1131 if (2 > parts)
1132 break;
1133
1134 PRInt64 a = nsCRT::atoll(values[1]);
1135 AutoRegEntry *entry =
1136 new AutoRegEntry(nsDependentCString(values[0], lengths[0]), &a);
1137
1138 if (!entry)
1139 return NS_ERROR_OUT_OF_MEMORY;
1140
1141 if (parts == 3)
1142 entry->SetOptionalData(values[2]);
1143
1144 nsCStringKey key((const char*)values[0]);
1145 mAutoRegEntries.Put(&key, entry);
1146 }
1147
1148 if (ReadSectionHeader(reader, "CLASSIDS"))
1149 goto out;
1150
1151 while (1)
1152 {
1153 if (!reader.NextLine())
1154 break;
1155
1156 // cid,contract_id,type,class_name,inproc_server
1157 if (5 != reader.ParseLine(values, lengths, 5))
1158 break;
1159
1160 nsCID aClass;
1161 if (!aClass.Parse(values[0]))
1162 continue;
1163
1164 int loadertype = GetLoaderType(values[2]);
1165 if (loadertype < 0) {
1166 rv = AddLoaderType(values[2], &loadertype);
1167 if (NS_FAILED(rv))
1168 continue;
1169 }
1170
1171 void *mem;
1172 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
1173 if (!mem)
1174 return NS_ERROR_OUT_OF_MEMORY;
1175
1176 nsFactoryEntry *entry = new (mem) nsFactoryEntry(aClass, values[4], lengths[4], loadertype);
1177
1178 nsFactoryTableEntry* factoryTableEntry =
1179 NS_STATIC_CAST(nsFactoryTableEntry*,
1180 PL_DHashTableOperate(&mFactories,
1181 &aClass,
1182 PL_DHASH_ADD));
1183
1184 if (!factoryTableEntry)
1185 return NS_ERROR_OUT_OF_MEMORY;
1186
1187 factoryTableEntry->mFactoryEntry = entry;
1188
1189 }
1190
1191 if (ReadSectionHeader(reader, "CONTRACTIDS"))
1192 goto out;
1193
1194 while (1)
1195 {
1196 if (!reader.NextLine())
1197 break;
1198
1199 //contractID,cid
1200 if (2 != reader.ParseLine(values, lengths, 2))
1201 break;
1202
1203 nsCID aClass;
1204 if (!aClass.Parse(values[1]))
1205 continue;
1206
1207
1208 //need to find the location for this cid.
1209 nsFactoryEntry *cidEntry = GetFactoryEntry(aClass);
1210 if (!cidEntry || cidEntry->mTypeIndex < 0)
1211 continue; //what should we really do?
1212
1213 nsContractIDTableEntry* contractIDTableEntry =
1214 NS_STATIC_CAST(nsContractIDTableEntry*,
1215 PL_DHashTableOperate(&mContractIDs,
1216 values[0],
1217 PL_DHASH_ADD));
1218 if (!contractIDTableEntry) {
1219 continue;
1220 }
1221
1222 if (!contractIDTableEntry->mContractID) {
1223 contractIDTableEntry->mContractID = ArenaStrndup(values[0], lengths[0], &mArena);
1224 contractIDTableEntry->mContractIDLen = lengths[0];
1225 }
1226
1227 contractIDTableEntry->mFactoryEntry = cidEntry;
1228 }
1229
1230#ifdef XPCOM_CHECK_PENDING_CIDS
1231 {
1232/*
1233 * If you get Asserts when you define SHOW_CI_ON_EXISTING_SERVICE and want to
1234 * track down their cause, then you should add the contracts listed by the
1235 * assertion to abusedContracts. The next time you run your xpcom app, xpcom
1236 * will assert the first time the object associated with the contract is
1237 * instantiated (which in many cases is the source of the problem).
1238 *
1239 * If you're doing this then you might want to NOP and soft breakpoint the
1240 * lines labeled: NOP_AND_BREAK.
1241 *
1242 * Otherwise XPCOM will refuse to create the object for the caller, which
1243 * while reasonable at some level, will almost certainly cause the app to
1244 * stop functioning normally.
1245 */
1246 static char abusedContracts[][128] = {
1247 /*// Example contracts:
1248 "@mozilla.org/rdf/container;1",
1249 "@mozilla.org/intl/charsetalias;1",
1250 "@mozilla.org/locale/win32-locale;1",
1251 "@mozilla.org/widget/lookandfeel/win;1",
1252 // */
1253 0
1254 };
1255 for (int i=0; abusedContracts[i] && *abusedContracts[i]; i++) {
1256 nsFactoryEntry *entry = nsnull;
1257 nsContractIDTableEntry* contractIDTableEntry =
1258 NS_STATIC_CAST(nsContractIDTableEntry*,
1259 PL_DHashTableOperate(&mContractIDs, abusedContracts[i],
1260 PL_DHASH_LOOKUP));
1261
1262 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
1263 entry = contractIDTableEntry->mFactoryEntry;
1264 AddPendingCID(entry->mCid);
1265 }
1266 }
1267 }
1268#endif
1269
1270 if (ReadSectionHeader(reader, "CATEGORIES"))
1271 goto out;
1272
1273 while (1)
1274 {
1275 if (!reader.NextLine())
1276 break;
1277
1278 //type,name,value
1279 if (3 != reader.ParseLine(values, lengths, 3))
1280 break;
1281
1282 mCategoryManager->AddCategoryEntry(values[0],
1283 values[1],
1284 values[2],
1285 PR_TRUE,
1286 PR_TRUE,
1287 0);
1288 }
1289
1290 mRegistryDirty = PR_FALSE;
1291out:
1292 if (fd)
1293 PR_Close(fd);
1294
1295 if (registry)
1296 delete [] registry;
1297
1298 return rv;
1299}
1300
1301struct PersistentWriterArgs
1302{
1303 PRFileDesc *mFD;
1304 nsLoaderdata *mLoaderData;
1305};
1306
1307PR_STATIC_CALLBACK(PLDHashOperator)
1308ContractIDWriter(PLDHashTable *table,
1309 PLDHashEntryHdr *hdr,
1310 PRUint32 number,
1311 void *arg)
1312{
1313 char *contractID = ((nsContractIDTableEntry*)hdr)->mContractID;
1314 nsFactoryEntry *factoryEntry = ((nsContractIDTableEntry*)hdr)->mFactoryEntry;
1315
1316 // for now, we only save out the top most parent.
1317 while (factoryEntry->mParent)
1318 factoryEntry = factoryEntry->mParent;
1319
1320 if (factoryEntry->mTypeIndex < 0)
1321 return PL_DHASH_NEXT;
1322
1323 PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
1324
1325 char cidString[UID_STRING_LENGTH];
1326 GetIDString(factoryEntry->mCid, cidString);
1327 PR_fprintf(fd, "%s,%s\n", contractID, cidString); // what if this fails?
1328 return PL_DHASH_NEXT;
1329}
1330
1331PR_STATIC_CALLBACK(PLDHashOperator)
1332ClassIDWriter(PLDHashTable *table,
1333 PLDHashEntryHdr *hdr,
1334 PRUint32 number,
1335 void *arg)
1336{
1337 nsFactoryEntry *factoryEntry = ((nsFactoryTableEntry*)hdr)->mFactoryEntry;
1338 PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
1339 nsLoaderdata *loaderData = ((PersistentWriterArgs*)arg)->mLoaderData;
1340
1341 // for now, we only save out the top most parent.
1342 while (factoryEntry->mParent)
1343 factoryEntry = factoryEntry->mParent;
1344
1345 if (factoryEntry->mTypeIndex < 0) {
1346 return PL_DHASH_NEXT;
1347 }
1348
1349 char cidString[UID_STRING_LENGTH];
1350 GetIDString(factoryEntry->mCid, cidString);
1351
1352 char *contractID = nsnull, *className = nsnull;
1353
1354 nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(factoryEntry->mFactory);
1355 if (classInfo)
1356 {
1357 classInfo->GetContractID(&contractID);
1358 classInfo->GetClassDescription(&className);
1359 }
1360
1361 const char * loaderName = nsnull;
1362 if (factoryEntry->mTypeIndex)
1363 loaderName = loaderData[factoryEntry->mTypeIndex].type;
1364
1365 char* location = factoryEntry->mLocation;
1366
1367 // cid,contract_id,type,class_name,inproc_server
1368 PR_fprintf(fd,
1369 "%s,%s,%s,%s,%s\n",
1370 cidString,
1371 (contractID ? contractID : ""),
1372 (loaderName ? loaderName : ""),
1373 (className ? className : ""),
1374 (location ? location : ""));
1375
1376 if (contractID)
1377 PR_Free(contractID);
1378 if (className)
1379 PR_Free(className);
1380
1381 return PL_DHASH_NEXT;
1382}
1383
1384PRIntn PR_CALLBACK
1385AutoRegEntryWriter(nsHashKey *aKey, void *aData, void* aClosure)
1386{
1387 PRFileDesc* fd = (PRFileDesc*) aClosure;
1388 AutoRegEntry* entry = (AutoRegEntry*) aData;
1389
1390 const char* extraData = entry->GetOptionalData();
1391 const char *fmt;
1392 if (extraData)
1393 fmt = "%s,%lld,%s\n";
1394 else
1395 fmt = "%s,%lld\n";
1396 PR_fprintf(fd, fmt, entry->GetName().get(), entry->GetDate(), extraData);
1397
1398 return PR_TRUE;
1399}
1400
1401nsresult
1402nsComponentManagerImpl::WritePersistentRegistry()
1403{
1404 if (!mRegistryFile)
1405 return NS_ERROR_FAILURE; // this should have been set by Init().
1406
1407 nsCOMPtr<nsIFile> file;
1408 mRegistryFile->Clone(getter_AddRefs(file));
1409 if (!file)
1410 return NS_ERROR_OUT_OF_MEMORY;
1411
1412 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
1413
1414 nsCAutoString originalLeafName;
1415 localFile->GetNativeLeafName(originalLeafName);
1416
1417 nsCAutoString leafName;
1418 leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp"));
1419
1420 localFile->SetNativeLeafName(leafName);
1421
1422 PRFileDesc* fd = nsnull;
1423 nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666, &fd);
1424 if (NS_FAILED(rv))
1425 return rv;
1426
1427 if (PR_fprintf(fd, "Generated File. Do not edit.\n") == (PRUint32) -1) {
1428 rv = NS_ERROR_UNEXPECTED;
1429 goto out;
1430 }
1431
1432 if (PR_fprintf(fd, "\n[HEADER]\nVersion,%d,%d\n",
1433 PERSISTENT_REGISTRY_VERSION_MAJOR,
1434 PERSISTENT_REGISTRY_VERSION_MINOR) == (PRUint32) -1) {
1435 rv = NS_ERROR_UNEXPECTED;
1436 goto out;
1437 }
1438
1439 if (PR_fprintf(fd, "\n[COMPONENTS]\n") == (PRUint32) -1) {
1440 rv = NS_ERROR_UNEXPECTED;
1441 goto out;
1442 }
1443
1444 mAutoRegEntries.Enumerate(AutoRegEntryWriter, (void*)fd);
1445
1446 PersistentWriterArgs args;
1447 args.mFD = fd;
1448 args.mLoaderData = mLoaderData;
1449
1450 if (PR_fprintf(fd, "\n[CLASSIDS]\n") == (PRUint32) -1) {
1451 rv = NS_ERROR_UNEXPECTED;
1452 goto out;
1453 }
1454
1455
1456 PL_DHashTableEnumerate(&mFactories, ClassIDWriter, (void*)&args);
1457
1458 if (PR_fprintf(fd, "\n[CONTRACTIDS]\n") == (PRUint32) -1) {
1459 rv = NS_ERROR_UNEXPECTED;
1460 goto out;
1461 }
1462
1463
1464 PL_DHashTableEnumerate(&mContractIDs, ContractIDWriter, (void*)&args);
1465
1466 if (PR_fprintf(fd, "\n[CATEGORIES]\n") == (PRUint32) -1) {
1467 rv = NS_ERROR_UNEXPECTED;
1468 goto out;
1469 }
1470
1471
1472 if (!mCategoryManager) {
1473 NS_WARNING("Could not access category manager. Will not be able to save categories!");
1474 rv = NS_ERROR_UNEXPECTED;
1475 } else {
1476 rv = mCategoryManager->WriteCategoryManagerToRegistry(fd);
1477 }
1478
1479out:
1480 if (fd)
1481 PR_Close(fd);
1482
1483 // don't create the file is there was a problem????
1484 NS_ENSURE_SUCCESS(rv, rv);
1485
1486 if (!mRegistryFile)
1487 return NS_ERROR_NOT_INITIALIZED;
1488
1489 PRBool exists;
1490 if(NS_FAILED(mRegistryFile->Exists(&exists)))
1491 return PR_FALSE;
1492
1493 if(exists && NS_FAILED(mRegistryFile->Remove(PR_FALSE)))
1494 return PR_FALSE;
1495
1496 nsCOMPtr<nsIFile> parent;
1497 mRegistryFile->GetParent(getter_AddRefs(parent));
1498
1499 rv = localFile->MoveToNative(parent, originalLeafName);
1500 mRegistryDirty = PR_FALSE;
1501
1502 return rv;
1503}
1504
1505
1506////////////////////////////////////////////////////////////////////////////////
1507// Hash Functions
1508////////////////////////////////////////////////////////////////////////////////
1509nsresult
1510nsComponentManagerImpl::HashContractID(const char *aContractID,
1511 PRUint32 aContractIDLen,
1512 nsFactoryEntry *fe)
1513{
1514 if(!aContractID || !aContractIDLen)
1515 return NS_ERROR_NULL_POINTER;
1516
1517 nsAutoMonitor mon(mMon);
1518
1519 nsContractIDTableEntry* contractIDTableEntry =
1520 NS_STATIC_CAST(nsContractIDTableEntry*,
1521 PL_DHashTableOperate(&mContractIDs, aContractID,
1522 PL_DHASH_ADD));
1523 if (!contractIDTableEntry)
1524 return NS_ERROR_OUT_OF_MEMORY;
1525
1526 NS_ASSERTION(!contractIDTableEntry->mContractID || !strcmp(contractIDTableEntry->mContractID, aContractID), "contractid conflict");
1527
1528 if (!contractIDTableEntry->mContractID) {
1529 contractIDTableEntry->mContractID = ArenaStrndup(aContractID, aContractIDLen, &mArena);
1530 contractIDTableEntry->mContractIDLen = aContractIDLen;
1531 }
1532
1533 contractIDTableEntry->mFactoryEntry = fe;
1534
1535 return NS_OK;
1536}
1537
1538/**
1539 * LoadFactory()
1540 *
1541 * Given a FactoryEntry, this loads the dll if it has to, find the NSGetFactory
1542 * symbol, calls the routine to create a new factory and returns it to the
1543 * caller.
1544 *
1545 * No attempt is made to store the factory in any form anywhere.
1546 */
1547nsresult
1548nsComponentManagerImpl::LoadFactory(nsFactoryEntry *aEntry,
1549 nsIFactory **aFactory)
1550{
1551
1552 if (!aFactory)
1553 return NS_ERROR_NULL_POINTER;
1554 *aFactory = nsnull;
1555
1556 nsresult rv;
1557 rv = aEntry->GetFactory(aFactory, this);
1558 if (NS_FAILED(rv)) {
1559 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
1560 ("nsComponentManager: FAILED to load factory from %s (%s)\n",
1561 (const char *)aEntry->mLocation, mLoaderData[aEntry->mTypeIndex].type));
1562 return rv;
1563 }
1564
1565 return NS_OK;
1566}
1567
1568nsFactoryEntry *
1569nsComponentManagerImpl::GetFactoryEntry(const char *aContractID,
1570 PRUint32 aContractIDLen)
1571{
1572 nsFactoryEntry *fe = nsnull;
1573 {
1574 nsAutoMonitor mon(mMon);
1575
1576 nsContractIDTableEntry* contractIDTableEntry =
1577 NS_STATIC_CAST(nsContractIDTableEntry*,
1578 PL_DHashTableOperate(&mContractIDs, aContractID,
1579 PL_DHASH_LOOKUP));
1580
1581
1582 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
1583 fe = contractIDTableEntry->mFactoryEntry;
1584 }
1585 } //exit monitor
1586
1587 return fe;
1588}
1589
1590
1591nsFactoryEntry *
1592nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass)
1593{
1594 nsFactoryEntry *entry = nsnull;
1595 {
1596 nsAutoMonitor mon(mMon);
1597
1598 nsFactoryTableEntry* factoryTableEntry =
1599 NS_STATIC_CAST(nsFactoryTableEntry*,
1600 PL_DHashTableOperate(&mFactories, &aClass,
1601 PL_DHASH_LOOKUP));
1602
1603 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
1604 entry = factoryTableEntry->mFactoryEntry;
1605 }
1606 } // exit monitor
1607
1608 return entry;
1609}
1610
1611
1612/**
1613 * FindFactory()
1614 *
1615 * Given a classID, this finds the factory for this CID by first searching the
1616 * local CID<->factory mapping. Next it searches for a Dll that implements
1617 * this classID and calls LoadFactory() to create the factory.
1618 *
1619 * Again, no attempt is made at storing the factory.
1620 */
1621nsresult
1622nsComponentManagerImpl::FindFactory(const nsCID &aClass,
1623 nsIFactory **aFactory)
1624{
1625 PR_ASSERT(aFactory != nsnull);
1626
1627 nsFactoryEntry *entry = GetFactoryEntry(aClass);
1628
1629 if (!entry)
1630 return NS_ERROR_FACTORY_NOT_REGISTERED;
1631
1632 return entry->GetFactory(aFactory, this);
1633}
1634
1635
1636nsresult
1637nsComponentManagerImpl::FindFactory(const char *contractID,
1638 PRUint32 aContractIDLen,
1639 nsIFactory **aFactory)
1640{
1641 PR_ASSERT(aFactory != nsnull);
1642
1643 nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen);
1644
1645 if (!entry)
1646 return NS_ERROR_FACTORY_NOT_REGISTERED;
1647
1648 return entry->GetFactory(aFactory, this);
1649}
1650
1651/**
1652 * GetClassObject()
1653 *
1654 * Given a classID, this finds the singleton ClassObject that implements the CID.
1655 * Returns an interface of type aIID off the singleton classobject.
1656 */
1657nsresult
1658nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID,
1659 void **aResult)
1660{
1661 nsresult rv;
1662
1663 nsCOMPtr<nsIFactory> factory;
1664
1665#ifdef PR_LOGGING
1666 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
1667 {
1668 char *buf = aClass.ToString();
1669 PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
1670 if (buf)
1671 PR_Free(buf);
1672 }
1673#endif
1674
1675 PR_ASSERT(aResult != nsnull);
1676
1677 rv = FindFactory(aClass, getter_AddRefs(factory));
1678 if (NS_FAILED(rv)) return rv;
1679
1680 rv = factory->QueryInterface(aIID, aResult);
1681
1682 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1683 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1684
1685 return rv;
1686}
1687
1688
1689nsresult
1690nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID,
1691 const nsIID &aIID,
1692 void **aResult)
1693{
1694 nsresult rv;
1695
1696 nsCOMPtr<nsIFactory> factory;
1697
1698#ifdef PR_LOGGING
1699 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
1700 {
1701 PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID);
1702 }
1703#endif
1704
1705 PR_ASSERT(aResult != nsnull);
1706
1707 rv = FindFactory(contractID, strlen(contractID), getter_AddRefs(factory));
1708 if (NS_FAILED(rv)) return rv;
1709
1710 rv = factory->QueryInterface(aIID, aResult);
1711
1712 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1713 ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1714
1715 return rv;
1716}
1717
1718/**
1719 * ContractIDToClassID()
1720 *
1721 * Mapping function from a ContractID to a classID. Directly talks to the registry.
1722 *
1723 */
1724nsresult
1725nsComponentManagerImpl::ContractIDToClassID(const char *aContractID, nsCID *aClass)
1726{
1727 NS_PRECONDITION(aContractID != nsnull, "null ptr");
1728 if (!aContractID)
1729 return NS_ERROR_NULL_POINTER;
1730
1731 NS_PRECONDITION(aClass != nsnull, "null ptr");
1732 if (!aClass)
1733 return NS_ERROR_NULL_POINTER;
1734
1735 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1736
1737 nsFactoryEntry *fe = GetFactoryEntry(aContractID, strlen(aContractID));
1738 if (fe) {
1739 *aClass = fe->mCid;
1740 rv = NS_OK;
1741 }
1742#ifdef PR_LOGGING
1743 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) {
1744 char *buf = 0;
1745 if (NS_SUCCEEDED(rv))
1746 buf = aClass->ToString();
1747 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1748 ("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID,
1749 NS_SUCCEEDED(rv) ? buf : "[FAILED]"));
1750 if (buf)
1751 PR_Free(buf);
1752 }
1753#endif
1754 return rv;
1755}
1756
1757/**
1758 * CLSIDToContractID()
1759 *
1760 * Translates a classID to a {ContractID, Class Name}. Does direct registry
1761 * access to do the translation.
1762 *
1763 * NOTE: Since this isn't heavily used, we arent caching this.
1764 */
1765nsresult
1766nsComponentManagerImpl::CLSIDToContractID(const nsCID &aClass,
1767 char* *aClassName,
1768 char* *aContractID)
1769{
1770 NS_WARNING("Need to implement CLSIDToContractID");
1771
1772 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1773#ifdef PR_LOGGING
1774 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
1775 {
1776 char *buf = aClass.ToString();
1777 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1778 ("nsComponentManager: CLSIDToContractID(%s)->%s", buf,
1779 NS_SUCCEEDED(rv) ? *aContractID : "[FAILED]"));
1780 if (buf)
1781 PR_Free(buf);
1782 }
1783#endif
1784 return rv;
1785}
1786
1787#ifdef XPCOM_CHECK_PENDING_CIDS
1788
1789// This method must be called from within the mMon monitor
1790nsresult
1791nsComponentManagerImpl::AddPendingCID(const nsCID &aClass)
1792{
1793 int max = mPendingCIDs.Count();
1794 for (int index = 0; index < max; index++)
1795 {
1796 nsCID *cidp = (nsCID*) mPendingCIDs.ElementAt(index);
1797 NS_ASSERTION(cidp, "Bad CID in pending list");
1798 if (cidp->Equals(aClass)) {
1799 nsXPIDLCString cid;
1800 cid.Adopt(aClass.ToString());
1801 nsCAutoString message;
1802 message = NS_LITERAL_CSTRING("Creation of \"") +
1803 cid + NS_LITERAL_CSTRING("\" in progress (Reentrant GS - see bug 194568)");
1804 // Note that you may see this assertion by near-simultaneous
1805 // calls to GetService on multiple threads.
1806 NS_WARNING(message.get());
1807 return NS_ERROR_NOT_AVAILABLE;
1808 }
1809 }
1810 mPendingCIDs.AppendElement((void*)&aClass);
1811 return NS_OK;
1812}
1813
1814// This method must be called from within the mMon monitor
1815void
1816nsComponentManagerImpl::RemovePendingCID(const nsCID &aClass)
1817{
1818 mPendingCIDs.RemoveElement((void*)&aClass);
1819}
1820#endif
1821/**
1822 * CreateInstance()
1823 *
1824 * Create an instance of an object that implements an interface and belongs
1825 * to the implementation aClass using the factory. The factory is immediately
1826 * released and not held onto for any longer.
1827 */
1828nsresult
1829nsComponentManagerImpl::CreateInstance(const nsCID &aClass,
1830 nsISupports *aDelegate,
1831 const nsIID &aIID,
1832 void **aResult)
1833{
1834 // test this first, since there's no point in creating a component during
1835 // shutdown -- whether it's available or not would depend on the order it
1836 // occurs in the list
1837 if (gXPCOMShuttingDown) {
1838 // When processing shutdown, dont process new GetService() requests
1839#ifdef SHOW_DENIED_ON_SHUTDOWN
1840 nsXPIDLCString cid, iid;
1841 cid.Adopt(aClass.ToString());
1842 iid.Adopt(aIID.ToString());
1843 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1844 " CID: %s\n IID: %s\n", cid.get(), iid.get());
1845#endif /* SHOW_DENIED_ON_SHUTDOWN */
1846 return NS_ERROR_UNEXPECTED;
1847 }
1848
1849 if (aResult == nsnull)
1850 {
1851 return NS_ERROR_NULL_POINTER;
1852 }
1853 *aResult = nsnull;
1854
1855 nsFactoryEntry *entry = GetFactoryEntry(aClass);
1856
1857 if (!entry)
1858 return NS_ERROR_FACTORY_NOT_REGISTERED;
1859
1860#ifdef SHOW_CI_ON_EXISTING_SERVICE
1861 if (entry->mServiceObject) {
1862 nsXPIDLCString cid;
1863 cid.Adopt(aClass.ToString());
1864 nsCAutoString message;
1865 message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1866 cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!");
1867 NS_ERROR(message.get());
1868 }
1869#endif
1870
1871 nsIFactory *factory = nsnull;
1872 nsresult rv = entry->GetFactory(&factory, this);
1873
1874 if (NS_SUCCEEDED(rv))
1875 {
1876 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1877 NS_RELEASE(factory);
1878 }
1879 else
1880 {
1881 // Translate error values
1882 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1883 }
1884
1885#ifdef PR_LOGGING
1886 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
1887 {
1888 char *buf = aClass.ToString();
1889 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1890 ("nsComponentManager: CreateInstance(%s) %s", buf,
1891 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1892 if (buf)
1893 PR_Free(buf);
1894 }
1895#endif
1896
1897 return rv;
1898}
1899
1900/**
1901 * CreateInstanceByContractID()
1902 *
1903 * A variant of CreateInstance() that creates an instance of the object that
1904 * implements the interface aIID and whose implementation has a contractID aContractID.
1905 *
1906 * This is only a convenience routine that turns around can calls the
1907 * CreateInstance() with classid and iid.
1908 */
1909nsresult
1910nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID,
1911 nsISupports *aDelegate,
1912 const nsIID &aIID,
1913 void **aResult)
1914{
1915 // test this first, since there's no point in creating a component during
1916 // shutdown -- whether it's available or not would depend on the order it
1917 // occurs in the list
1918 if (gXPCOMShuttingDown) {
1919 // When processing shutdown, dont process new GetService() requests
1920#ifdef SHOW_DENIED_ON_SHUTDOWN
1921 nsXPIDLCString iid;
1922 iid.Adopt(aIID.ToString());
1923 fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
1924 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
1925#endif /* SHOW_DENIED_ON_SHUTDOWN */
1926 return NS_ERROR_UNEXPECTED;
1927 }
1928
1929 if (aResult == nsnull)
1930 {
1931 return NS_ERROR_NULL_POINTER;
1932 }
1933 *aResult = nsnull;
1934
1935 nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID));
1936
1937 if (!entry)
1938 return NS_ERROR_FACTORY_NOT_REGISTERED;
1939
1940#ifdef SHOW_CI_ON_EXISTING_SERVICE
1941 if (entry->mServiceObject) {
1942 nsCAutoString message;
1943 message =
1944 NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
1945 nsDependentCString(aContractID) +
1946 NS_LITERAL_CSTRING("\" when a service for this CID already exists! "
1947 "Add it to abusedContracts to track down the service consumer.");
1948 NS_ERROR(message.get());
1949 }
1950#endif
1951
1952 nsIFactory *factory = nsnull;
1953 nsresult rv = entry->GetFactory(&factory, this);
1954
1955 if (NS_SUCCEEDED(rv))
1956 {
1957
1958 rv = factory->CreateInstance(aDelegate, aIID, aResult);
1959 NS_RELEASE(factory);
1960 }
1961 else
1962 {
1963 // Translate error values
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 // XPCOM needs initialization.
3726 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3727 }
3728
3729 if (NS_FAILED(rv))
3730 return rv;
3731
3732 *result = NS_STATIC_CAST(nsIServiceManager*,
3733 nsComponentManagerImpl::gComponentManager);
3734 NS_IF_ADDREF(*result);
3735 return NS_OK;
3736}
3737
3738
3739NS_COM nsresult
3740NS_GetComponentRegistrar(nsIComponentRegistrar* *result)
3741{
3742 nsresult rv = NS_OK;
3743
3744 if (nsComponentManagerImpl::gComponentManager == nsnull)
3745 {
3746 // XPCOM needs initialization.
3747 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3748 }
3749
3750 if (NS_FAILED(rv))
3751 return rv;
3752
3753 *result = NS_STATIC_CAST(nsIComponentRegistrar*,
3754 nsComponentManagerImpl::gComponentManager);
3755 NS_IF_ADDREF(*result);
3756 return NS_OK;
3757}
3758
3759
3760// nsIComponentLoaderManager is not frozen, but is defined here
3761// so that I can use it internally in xpcom.
3762nsresult
3763NS_GetComponentLoaderManager(nsIComponentLoaderManager* *result)
3764{
3765 nsresult rv = NS_OK;
3766
3767 if (nsComponentManagerImpl::gComponentManager == NULL)
3768 {
3769 // XPCOM needs initialization.
3770 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3771 }
3772
3773 if (NS_FAILED(rv))
3774 return rv;
3775
3776 *result = NS_STATIC_CAST(nsIComponentLoaderManager*,
3777 nsComponentManagerImpl::gComponentManager);
3778 NS_IF_ADDREF(*result);
3779 return NS_OK;
3780}
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