VirtualBox

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

Last change on this file since 66250 was 64428, checked in by vboxsync, 8 years ago

xpcom/Runtime: introduced NS_ERROR_SOCKET_FAIL which is used for XPCOM socket errors at /tmp/.vbox-*-ipc/ipcd

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 113.0 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, 0600, &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 if (rv != NS_ERROR_SOCKET_FAIL)
1965 rv = NS_ERROR_FACTORY_NOT_REGISTERED;
1966 }
1967
1968 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
1969 ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
1970 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
1971
1972 return rv;
1973}
1974
1975// Service Manager Impl
1976static
1977PLDHashOperator PR_CALLBACK
1978FreeServiceFactoryEntryEnumerate(PLDHashTable *aTable,
1979 PLDHashEntryHdr *aHdr,
1980 PRUint32 aNumber,
1981 void *aData)
1982{
1983 nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
1984
1985 if (!entry->mFactoryEntry)
1986 return PL_DHASH_NEXT;
1987
1988 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
1989 factoryEntry->mServiceObject = nsnull;
1990 return PL_DHASH_NEXT;
1991}
1992
1993static
1994PLDHashOperator PR_CALLBACK
1995FreeServiceContractIDEntryEnumerate(PLDHashTable *aTable,
1996 PLDHashEntryHdr *aHdr,
1997 PRUint32 aNumber,
1998 void *aData)
1999{
2000 nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
2001
2002 if (!entry->mFactoryEntry)
2003 return PL_DHASH_NEXT;
2004
2005 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
2006 factoryEntry->mServiceObject = nsnull;
2007 return PL_DHASH_NEXT;
2008}
2009
2010nsresult
2011nsComponentManagerImpl::FreeServices()
2012{
2013 NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services");
2014
2015 if (!gXPCOMShuttingDown)
2016 return NS_ERROR_FAILURE;
2017
2018 if (mContractIDs.ops) {
2019 PL_DHashTableEnumerate(&mContractIDs, FreeServiceContractIDEntryEnumerate, nsnull);
2020 }
2021
2022
2023 if (mFactories.ops) {
2024 PL_DHashTableEnumerate(&mFactories, FreeServiceFactoryEntryEnumerate, nsnull);
2025 }
2026
2027 return NS_OK;
2028}
2029
2030NS_IMETHODIMP
2031nsComponentManagerImpl::GetService(const nsCID& aClass,
2032 const nsIID& aIID,
2033 void* *result)
2034{
2035 // test this first, since there's no point in returning a service during
2036 // shutdown -- whether it's available or not would depend on the order it
2037 // occurs in the list
2038 if (gXPCOMShuttingDown) {
2039 // When processing shutdown, dont process new GetService() requests
2040#ifdef SHOW_DENIED_ON_SHUTDOWN
2041 nsXPIDLCString cid, iid;
2042 cid.Adopt(aClass.ToString());
2043 iid.Adopt(aIID.ToString());
2044 fprintf(stderr, "Getting service on shutdown. Denied.\n"
2045 " CID: %s\n IID: %s\n", cid.get(), iid.get());
2046#endif /* SHOW_DENIED_ON_SHUTDOWN */
2047 return NS_ERROR_UNEXPECTED;
2048 }
2049
2050 nsAutoMonitor mon(mMon);
2051
2052 nsresult rv = NS_OK;
2053 nsIDKey key(aClass);
2054 nsFactoryEntry* entry = nsnull;
2055 nsFactoryTableEntry* factoryTableEntry =
2056 NS_STATIC_CAST(nsFactoryTableEntry*,
2057 PL_DHashTableOperate(&mFactories, &aClass,
2058 PL_DHASH_LOOKUP));
2059
2060 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2061 entry = factoryTableEntry->mFactoryEntry;
2062 }
2063
2064 if (entry && entry->mServiceObject) {
2065 return entry->mServiceObject->QueryInterface(aIID, result);
2066 }
2067
2068#ifdef XPCOM_CHECK_PENDING_CIDS
2069 rv = AddPendingCID(aClass);
2070 if (NS_FAILED(rv))
2071 return rv; // NOP_AND_BREAK
2072#endif
2073 nsCOMPtr<nsISupports> service;
2074 // We need to not be holding the service manager's monitor while calling
2075 // CreateInstance, because it invokes user code which could try to re-enter
2076 // the service manager:
2077 mon.Exit();
2078
2079 rv = CreateInstance(aClass, nsnull, aIID, getter_AddRefs(service));
2080
2081 mon.Enter();
2082
2083#ifdef XPCOM_CHECK_PENDING_CIDS
2084 RemovePendingCID(aClass);
2085#endif
2086
2087 if (NS_FAILED(rv))
2088 return rv;
2089
2090 if (!entry) { // second hash lookup for GetService
2091 nsFactoryTableEntry* factoryTableEntry =
2092 NS_STATIC_CAST(nsFactoryTableEntry*,
2093 PL_DHashTableOperate(&mFactories, &aClass,
2094 PL_DHASH_LOOKUP));
2095 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2096 entry = factoryTableEntry->mFactoryEntry;
2097 }
2098 NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
2099 if (!entry) return NS_ERROR_FAILURE;
2100 }
2101
2102 entry->mServiceObject = service;
2103 *result = service.get();
2104 NS_ADDREF(NS_STATIC_CAST(nsISupports*, (*result)));
2105 return rv;
2106}
2107
2108NS_IMETHODIMP
2109nsComponentManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService)
2110{
2111 nsAutoMonitor mon(mMon);
2112
2113 // check to see if we have a factory entry for the service
2114 nsFactoryEntry *entry = GetFactoryEntry(aClass);
2115
2116 if (!entry) { // XXXdougt - should we require that all services register factories?? probably not.
2117 void *mem;
2118 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2119 if (!mem)
2120 return NS_ERROR_OUT_OF_MEMORY;
2121 entry = new (mem) nsFactoryEntry(aClass, nsnull);
2122
2123 entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
2124 nsFactoryTableEntry* factoryTableEntry =
2125 NS_STATIC_CAST(nsFactoryTableEntry*,
2126 PL_DHashTableOperate(&mFactories, &aClass,
2127 PL_DHASH_ADD));
2128 if (!factoryTableEntry)
2129 return NS_ERROR_OUT_OF_MEMORY;
2130
2131 factoryTableEntry->mFactoryEntry = entry;
2132 }
2133 else {
2134 if (entry->mServiceObject)
2135 return NS_ERROR_FAILURE;
2136 }
2137
2138 entry->mServiceObject = aService;
2139 return NS_OK;
2140}
2141
2142NS_IMETHODIMP
2143nsComponentManagerImpl::UnregisterService(const nsCID& aClass)
2144{
2145 nsresult rv = NS_OK;
2146
2147 nsFactoryEntry* entry = nsnull;
2148
2149 nsAutoMonitor mon(mMon);
2150
2151 nsFactoryTableEntry* factoryTableEntry =
2152 NS_STATIC_CAST(nsFactoryTableEntry*,
2153 PL_DHashTableOperate(&mFactories, &aClass,
2154 PL_DHASH_LOOKUP));
2155
2156 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2157 entry = factoryTableEntry->mFactoryEntry;
2158 }
2159
2160 if (!entry || !entry->mServiceObject)
2161 return NS_ERROR_SERVICE_NOT_AVAILABLE;
2162
2163 entry->mServiceObject = nsnull;
2164 return rv;
2165}
2166
2167NS_IMETHODIMP
2168nsComponentManagerImpl::RegisterService(const char* aContractID, nsISupports* aService)
2169{
2170
2171 nsAutoMonitor mon(mMon);
2172
2173 // check to see if we have a factory entry for the service
2174 PRUint32 contractIDLen = strlen(aContractID);
2175 nsFactoryEntry *entry = GetFactoryEntry(aContractID, contractIDLen);
2176
2177 if (!entry) { // XXXdougt - should we require that all services register factories?? probably not.
2178 void *mem;
2179 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2180 if (!mem)
2181 return NS_ERROR_OUT_OF_MEMORY;
2182 entry = new (mem) nsFactoryEntry(kEmptyCID, nsnull);
2183
2184 entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
2185
2186 nsContractIDTableEntry* contractIDTableEntry =
2187 NS_STATIC_CAST(nsContractIDTableEntry*,
2188 PL_DHashTableOperate(&mContractIDs, aContractID,
2189 PL_DHASH_ADD));
2190 if (!contractIDTableEntry) {
2191 delete entry;
2192 return NS_ERROR_OUT_OF_MEMORY;
2193 }
2194
2195 if (!contractIDTableEntry->mContractID) {
2196 contractIDTableEntry->mContractID =
2197 ArenaStrndup(aContractID, contractIDLen, &mArena);
2198
2199 contractIDTableEntry->mContractIDLen = contractIDLen;
2200 }
2201
2202 contractIDTableEntry->mFactoryEntry = entry;
2203 }
2204 else {
2205 if (entry->mServiceObject)
2206 return NS_ERROR_FAILURE;
2207 }
2208
2209 entry->mServiceObject = aService;
2210 return NS_OK;
2211}
2212
2213
2214NS_IMETHODIMP
2215nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
2216 const nsIID& aIID,
2217 PRBool *result)
2218{
2219 // Now we want to get the service if we already got it. If not, we dont want
2220 // to create an instance of it. mmh!
2221
2222 // test this first, since there's no point in returning a service during
2223 // shutdown -- whether it's available or not would depend on the order it
2224 // occurs in the list
2225 if (gXPCOMShuttingDown) {
2226 // When processing shutdown, dont process new GetService() requests
2227#ifdef SHOW_DENIED_ON_SHUTDOWN
2228 nsXPIDLCString cid, iid;
2229 cid.Adopt(aClass.ToString());
2230 iid.Adopt(aIID.ToString());
2231 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
2232 " CID: %s\n IID: %s\n", cid.get(), iid.get());
2233#endif /* SHOW_DENIED_ON_SHUTDOWN */
2234 return NS_ERROR_UNEXPECTED;
2235 }
2236
2237 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
2238 nsFactoryEntry* entry = nsnull;
2239 nsFactoryTableEntry* factoryTableEntry =
2240 NS_STATIC_CAST(nsFactoryTableEntry*,
2241 PL_DHashTableOperate(&mFactories, &aClass,
2242 PL_DHASH_LOOKUP));
2243
2244 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2245 entry = factoryTableEntry->mFactoryEntry;
2246 }
2247
2248 if (entry && entry->mServiceObject) {
2249 nsCOMPtr<nsISupports> service;
2250 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
2251 *result = (service!=nsnull);
2252 }
2253 return rv;
2254
2255}
2256
2257NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID,
2258 const nsIID& aIID,
2259 PRBool *result)
2260{
2261 // Now we want to get the service if we already got it. If not, we dont want
2262 // to create an instance of it. mmh!
2263
2264 // test this first, since there's no point in returning a service during
2265 // shutdown -- whether it's available or not would depend on the order it
2266 // occurs in the list
2267 if (gXPCOMShuttingDown) {
2268 // When processing shutdown, dont process new GetService() requests
2269#ifdef SHOW_DENIED_ON_SHUTDOWN
2270 nsXPIDLCString iid;
2271 iid.Adopt(aIID.ToString());
2272 fprintf(stderr, "Checking for service on shutdown. Denied.\n"
2273 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
2274#endif /* SHOW_DENIED_ON_SHUTDOWN */
2275 return NS_ERROR_UNEXPECTED;
2276 }
2277
2278 nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
2279 nsFactoryEntry *entry = nsnull;
2280 {
2281 nsAutoMonitor mon(mMon);
2282
2283 nsContractIDTableEntry* contractIDTableEntry =
2284 NS_STATIC_CAST(nsContractIDTableEntry*,
2285 PL_DHashTableOperate(&mContractIDs, aContractID,
2286 PL_DHASH_LOOKUP));
2287
2288 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2289 entry = contractIDTableEntry->mFactoryEntry;
2290 }
2291 } // exit monitor
2292
2293 if (entry && entry->mServiceObject) {
2294 nsCOMPtr<nsISupports> service;
2295 rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
2296 *result = (service!=nsnull);
2297 }
2298 return rv;
2299}
2300
2301
2302NS_IMETHODIMP
2303nsComponentManagerImpl::UnregisterService(const char* aContractID)
2304{
2305 nsresult rv = NS_OK;
2306
2307 nsAutoMonitor mon(mMon);
2308
2309 nsFactoryEntry *entry = nsnull;
2310 nsContractIDTableEntry* contractIDTableEntry =
2311 NS_STATIC_CAST(nsContractIDTableEntry*,
2312 PL_DHashTableOperate(&mContractIDs, aContractID,
2313 PL_DHASH_LOOKUP));
2314
2315 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2316 entry = contractIDTableEntry->mFactoryEntry;
2317 }
2318
2319 if (!entry || !entry->mServiceObject)
2320 return NS_ERROR_SERVICE_NOT_AVAILABLE;
2321
2322 entry->mServiceObject = nsnull;
2323 return rv;
2324}
2325
2326NS_IMETHODIMP
2327nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
2328 const nsIID& aIID,
2329 void* *result)
2330{
2331 // test this first, since there's no point in returning a service during
2332 // shutdown -- whether it's available or not would depend on the order it
2333 // occurs in the list
2334 if (gXPCOMShuttingDown) {
2335 // When processing shutdown, dont process new GetService() requests
2336#ifdef SHOW_DENIED_ON_SHUTDOWN
2337 nsXPIDLCString iid;
2338 iid.Adopt(aIID.ToString());
2339 fprintf(stderr, "Getting service on shutdown. Denied.\n"
2340 " ContractID: %s\n IID: %s\n", aContractID, iid.get());
2341#endif /* SHOW_DENIED_ON_SHUTDOWN */
2342 return NS_ERROR_UNEXPECTED;
2343 }
2344
2345 nsAutoMonitor mon(mMon);
2346
2347 nsresult rv = NS_OK;
2348 nsFactoryEntry *entry = nsnull;
2349 nsContractIDTableEntry* contractIDTableEntry =
2350 NS_STATIC_CAST(nsContractIDTableEntry*,
2351 PL_DHashTableOperate(&mContractIDs, aContractID,
2352 PL_DHASH_LOOKUP));
2353
2354 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2355 entry = contractIDTableEntry->mFactoryEntry;
2356 }
2357
2358 if (entry) {
2359 if (entry->mServiceObject) {
2360 return entry->mServiceObject->QueryInterface(aIID, result);
2361 }
2362#ifdef XPCOM_CHECK_PENDING_CIDS
2363 rv = AddPendingCID(entry->mCid);
2364 if (NS_FAILED(rv))
2365 return rv; // NOP_AND_BREAK
2366#endif
2367 }
2368
2369 nsCOMPtr<nsISupports> service;
2370 // We need to not be holding the service manager's monitor while calling
2371 // CreateInstance, because it invokes user code which could try to re-enter
2372 // the service manager:
2373 mon.Exit();
2374
2375 rv = CreateInstanceByContractID(aContractID, nsnull, aIID, getter_AddRefs(service));
2376
2377 mon.Enter();
2378
2379#ifdef XPCOM_CHECK_PENDING_CIDS
2380 if (entry)
2381 RemovePendingCID(entry->mCid);
2382#endif
2383
2384 if (NS_FAILED(rv))
2385 return rv;
2386
2387 if (!entry) { // second hash lookup for GetService
2388 nsContractIDTableEntry* contractIDTableEntry =
2389 NS_STATIC_CAST(nsContractIDTableEntry*,
2390 PL_DHashTableOperate(&mContractIDs, aContractID,
2391 PL_DHASH_LOOKUP));
2392
2393 if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
2394 entry = contractIDTableEntry->mFactoryEntry;
2395 }
2396 NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
2397 if (!entry) return NS_ERROR_FAILURE;
2398 }
2399
2400 entry->mServiceObject = service;
2401 *result = service.get();
2402 NS_ADDREF(NS_STATIC_CAST(nsISupports*, *result));
2403 return rv;
2404}
2405
2406NS_IMETHODIMP
2407nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
2408 nsISupports* *result,
2409 nsIShutdownListener* shutdownListener)
2410{
2411 return GetService(aClass, aIID, (void**)result);
2412}
2413
2414NS_IMETHODIMP
2415nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID,
2416 nsISupports* *result,
2417 nsIShutdownListener* shutdownListener)
2418{
2419 return GetServiceByContractID(aContractID, aIID, (void**)result);
2420}
2421
2422
2423NS_IMETHODIMP
2424nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service,
2425 nsIShutdownListener* shutdownListener)
2426{
2427 NS_IF_RELEASE(service);
2428 return NS_OK;
2429}
2430
2431NS_IMETHODIMP
2432nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service,
2433 nsIShutdownListener* shutdownListener)
2434{
2435 NS_IF_RELEASE(service);
2436 return NS_OK;
2437}
2438
2439/*
2440 * I want an efficient way to allocate a buffer to the right size
2441 * and stick the prefix and dllName in, then be able to hand that buffer
2442 * off to the FactoryEntry. Is that so wrong?
2443 *
2444 * *regName is allocated on success.
2445 *
2446 * This should live in nsNativeComponentLoader.cpp, I think.
2447 */
2448static nsresult
2449MakeRegistryName(const char *aDllName, const char *prefix, char **regName)
2450{
2451 char *registryName;
2452
2453 PRUint32 len = strlen(prefix);
2454
2455 PRUint32 registryNameLen = strlen(aDllName) + len;
2456 registryName = (char *)nsMemory::Alloc(registryNameLen + 1);
2457
2458 // from here on it, we want len sans terminating NUL
2459
2460 if (!registryName)
2461 return NS_ERROR_OUT_OF_MEMORY;
2462
2463 memcpy(registryName, prefix, len);
2464 strcpy(registryName + len, aDllName);
2465 registryName[registryNameLen] = '\0';
2466 *regName = registryName;
2467
2468#ifdef DEBUG_shaver_off
2469 fprintf(stderr, "MakeRegistryName(%s, %s, &[%s])\n",
2470 aDllName, prefix, *regName);
2471#endif
2472
2473 return NS_OK;
2474}
2475
2476nsresult
2477nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec,
2478 char **aRegistryName)
2479{
2480 nsresult rv;
2481
2482 if (!mComponentsDir)
2483 return NS_ERROR_NOT_INITIALIZED;
2484
2485 if (!aSpec) {
2486 *aRegistryName = PL_strdup("");
2487 return NS_OK;
2488 }
2489
2490
2491 // First check to see if this component is in the application
2492 // components directory
2493 PRBool containedIn;
2494 mComponentsDir->Contains(aSpec, PR_TRUE, &containedIn);
2495
2496 nsCAutoString nativePathString;
2497
2498 if (containedIn){
2499 rv = aSpec->GetNativePath(nativePathString);
2500 if (NS_FAILED(rv))
2501 return rv;
2502
2503 const char* relativeLocation = nativePathString.get() + mComponentsOffset + 1;
2504 return MakeRegistryName(relativeLocation, XPCOM_RELCOMPONENT_PREFIX, aRegistryName);
2505 }
2506
2507 // Next check to see if this component is in the GRE
2508 // components directory
2509
2510 mGREComponentsDir->Contains(aSpec, PR_TRUE, &containedIn);
2511
2512 if (containedIn){
2513 rv = aSpec->GetNativePath(nativePathString);
2514 if (NS_FAILED(rv))
2515 return rv;
2516
2517 const char* relativeLocation = nativePathString.get() + mGREComponentsOffset + 1;
2518 return MakeRegistryName(relativeLocation, XPCOM_GRECOMPONENT_PREFIX, aRegistryName);
2519 }
2520
2521 /* absolute names include volume info on Mac, so persistent descriptor */
2522 rv = aSpec->GetNativePath(nativePathString);
2523 if (NS_FAILED(rv))
2524 return rv;
2525 return MakeRegistryName(nativePathString.get(), XPCOM_ABSCOMPONENT_PREFIX, aRegistryName);
2526}
2527
2528nsresult
2529nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation,
2530 nsIFile **aSpec)
2531{
2532 // i18n: assuming aLocation is encoded for the current locale
2533
2534 nsresult rv;
2535 if (!aLocation || !aSpec)
2536 return NS_ERROR_NULL_POINTER;
2537
2538 /* abs:/full/path/to/libcomponent.so */
2539 if (!strncmp(aLocation, XPCOM_ABSCOMPONENT_PREFIX, 4)) {
2540
2541 nsLocalFile* file = new nsLocalFile;
2542 if (!file) return NS_ERROR_FAILURE;
2543
2544 rv = file->InitWithNativePath(nsDependentCString((char *)aLocation + 4));
2545 file->QueryInterface(NS_GET_IID(nsILocalFile), (void**)aSpec);
2546 return rv;
2547 }
2548
2549 if (!strncmp(aLocation, XPCOM_RELCOMPONENT_PREFIX, 4)) {
2550
2551 if (!mComponentsDir)
2552 return NS_ERROR_NOT_INITIALIZED;
2553
2554 nsILocalFile* file = nsnull;
2555 rv = mComponentsDir->Clone((nsIFile**)&file);
2556
2557 if (NS_FAILED(rv)) return rv;
2558
2559 rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4));
2560 *aSpec = file;
2561 return rv;
2562 }
2563
2564 if (!strncmp(aLocation, XPCOM_GRECOMPONENT_PREFIX, 4)) {
2565
2566 if (!mGREComponentsDir)
2567 return NS_ERROR_NOT_INITIALIZED;
2568
2569 nsILocalFile* file = nsnull;
2570 rv = mGREComponentsDir->Clone((nsIFile**)&file);
2571
2572 if (NS_FAILED(rv)) return rv;
2573
2574 rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4));
2575 *aSpec = file;
2576 return rv;
2577 }
2578
2579 *aSpec = nsnull;
2580 return NS_ERROR_INVALID_ARG;
2581}
2582
2583/**
2584 * RegisterFactory()
2585 *
2586 * Register a factory to be responsible for creation of implementation of
2587 * classID aClass. Plus creates as association of aClassName and aContractID
2588 * to the classID. If replace is PR_TRUE, we replace any existing registrations
2589 * with this one.
2590 *
2591 * Once registration is complete, we add the class to the factories cache
2592 * that we maintain. The factories cache is the ONLY place where these
2593 * registrations are ever kept.
2594 *
2595 * The other RegisterFunctions create a loader mapping and persistent
2596 * location, but we just slam it into the cache here. And we don't call the
2597 * loader's OnRegister function, either.
2598 */
2599nsresult
2600nsComponentManagerImpl::RegisterFactory(const nsCID &aClass,
2601 const char *aClassName,
2602 const char *aContractID,
2603 nsIFactory *aFactory,
2604 PRBool aReplace)
2605{
2606 nsAutoMonitor mon(mMon);
2607#ifdef PR_LOGGING
2608 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
2609 {
2610 char *buf = aClass.ToString();
2611 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2612 ("nsComponentManager: RegisterFactory(%s, %s)", buf,
2613 (aContractID ? aContractID : "(null)")));
2614 if (buf)
2615 PR_Free(buf);
2616 }
2617#endif
2618 nsFactoryEntry *entry = nsnull;
2619 nsFactoryTableEntry* factoryTableEntry = NS_STATIC_CAST(nsFactoryTableEntry*,
2620 PL_DHashTableOperate(&mFactories,
2621 &aClass,
2622 PL_DHASH_ADD));
2623
2624 if (!factoryTableEntry)
2625 return NS_ERROR_OUT_OF_MEMORY;
2626
2627
2628 if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
2629 entry = factoryTableEntry->mFactoryEntry;
2630 }
2631
2632 if (entry && !aReplace)
2633 {
2634 // Already registered
2635 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
2636 ("\t\tFactory already registered."));
2637 return NS_ERROR_FACTORY_EXISTS;
2638 }
2639
2640 void *mem;
2641 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2642 if (!mem)
2643 return NS_ERROR_OUT_OF_MEMORY;
2644
2645 entry = new (mem) nsFactoryEntry(aClass, aFactory, entry);
2646
2647 if (!entry)
2648 return NS_ERROR_OUT_OF_MEMORY;
2649
2650 factoryTableEntry->mFactoryEntry = entry;
2651
2652 // Update the ContractID->CLSID Map
2653 if (aContractID) {
2654 nsresult rv = HashContractID(aContractID, strlen(aContractID), entry);
2655 if (NS_FAILED(rv)) {
2656 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2657 ("\t\tFactory register succeeded. "
2658 "Hashing contractid (%s) FAILED.", aContractID));
2659 return rv;
2660 }
2661 }
2662
2663 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2664 ("\t\tFactory register succeeded contractid=%s.",
2665 aContractID ? aContractID : "<none>"));
2666
2667 return NS_OK;
2668}
2669
2670nsresult
2671nsComponentManagerImpl::RegisterComponent(const nsCID &aClass,
2672 const char *aClassName,
2673 const char *aContractID,
2674 const char *aPersistentDescriptor,
2675 PRBool aReplace,
2676 PRBool aPersist)
2677{
2678 return RegisterComponentCommon(aClass, aClassName,
2679 aContractID,
2680 aContractID ? strlen(aContractID) : 0,
2681 aPersistentDescriptor,
2682 aPersistentDescriptor ?
2683 strlen(aPersistentDescriptor) : 0,
2684 aReplace, aPersist,
2685 nativeComponentType);
2686}
2687
2688nsresult
2689nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass,
2690 const char *aClassName,
2691 const char *aContractID,
2692 nsIFile *aSpec,
2693 const char *aLocation,
2694 PRBool aReplace,
2695 PRBool aPersist,
2696 const char *aType)
2697{
2698 return RegisterComponentCommon(aClass, aClassName,
2699 aContractID,
2700 aContractID ? strlen(aContractID) : 0,
2701 aLocation,
2702 aLocation ? strlen(aLocation) : 0,
2703 aReplace, aPersist,
2704 aType);
2705}
2706
2707/*
2708 * Register a component, using whatever they stuck in the nsIFile.
2709 */
2710nsresult
2711nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass,
2712 const char *aClassName,
2713 const char *aContractID,
2714 nsIFile *aLibrarySpec,
2715 PRBool aReplace,
2716 PRBool aPersist)
2717{
2718 nsXPIDLCString registryName;
2719 nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName));
2720 if (NS_FAILED(rv))
2721 return rv;
2722
2723 rv = RegisterComponentWithType(aClass, aClassName,
2724 aContractID,
2725 aLibrarySpec,
2726 registryName,
2727 aReplace, aPersist,
2728 nativeComponentType);
2729 return rv;
2730}
2731
2732nsresult
2733nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass,
2734 const char *aClassName,
2735 const char *aContractID,
2736 const char *aDllName,
2737 PRBool aReplace,
2738 PRBool aPersist)
2739{
2740 // deprecated and obsolete.
2741 return NS_ERROR_NOT_IMPLEMENTED;
2742}
2743
2744/*
2745 * Add a component to the known universe of components.
2746
2747 * Once we enter this function, we own aRegistryName, and must free it
2748 * or hand it to nsFactoryEntry. Common exit point ``out'' helps keep us
2749 * sane.
2750 */
2751
2752nsresult
2753nsComponentManagerImpl::RegisterComponentCommon(const nsCID &aClass,
2754 const char *aClassName,
2755 const char *aContractID,
2756 PRUint32 aContractIDLen,
2757 const char *aRegistryName,
2758 PRUint32 aRegistryNameLen,
2759 PRBool aReplace,
2760 PRBool aPersist,
2761 const char *aType)
2762{
2763 nsIDKey key(aClass);
2764 nsAutoMonitor mon(mMon);
2765
2766 nsFactoryEntry *entry = GetFactoryEntry(aClass);
2767
2768 // Normalize proid and classname
2769 const char *contractID = (aContractID && *aContractID) ? aContractID : nsnull;
2770 const char *className = (aClassName && *aClassName) ? aClassName : nsnull;
2771#ifdef PR_LOGGING
2772 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
2773 {
2774 char *buf = aClass.ToString();
2775 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2776 ("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)",
2777 buf,
2778 contractID ? contractID : "(null)",
2779 aRegistryName, aType));
2780 if (buf)
2781 PR_Free(buf);
2782 }
2783#endif
2784 if (entry && !aReplace) {
2785 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
2786 ("\t\tFactory already registered."));
2787 return NS_ERROR_FACTORY_EXISTS;
2788 }
2789
2790 int typeIndex = GetLoaderType(aType);
2791
2792 nsCOMPtr<nsIComponentLoader> loader;
2793 nsresult rv = GetLoaderForType(typeIndex, getter_AddRefs(loader));
2794 if (NS_FAILED(rv)) {
2795 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
2796 ("\t\tgetting loader for %s FAILED\n", aType));
2797 return rv;
2798 }
2799
2800 if (entry) {
2801 entry->ReInit(aClass, aRegistryName, typeIndex);
2802 }
2803 else {
2804
2805 // Arena allocate the nsFactoryEntry
2806 void *mem;
2807 PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
2808 if (!mem)
2809 return NS_ERROR_OUT_OF_MEMORY;
2810
2811 mRegistryDirty = PR_TRUE;
2812 entry = new (mem) nsFactoryEntry(aClass,
2813 aRegistryName, aRegistryNameLen,
2814 typeIndex);
2815 if (!entry)
2816 return NS_ERROR_OUT_OF_MEMORY;
2817
2818 nsFactoryTableEntry* factoryTableEntry =
2819 NS_STATIC_CAST(nsFactoryTableEntry*,
2820 PL_DHashTableOperate(&mFactories, &aClass,
2821 PL_DHASH_ADD));
2822
2823 if (!factoryTableEntry)
2824 return NS_ERROR_OUT_OF_MEMORY;
2825
2826 factoryTableEntry->mFactoryEntry = entry;
2827 }
2828
2829 // Update the ContractID->CLSID Map
2830 if (contractID) {
2831 rv = HashContractID(contractID, aContractIDLen, entry);
2832 if (NS_FAILED(rv)) {
2833 PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
2834 ("\t\tHashContractID(%s) FAILED\n", contractID));
2835 return rv;
2836 }
2837 }
2838 return rv;
2839}
2840
2841
2842nsresult
2843nsComponentManagerImpl::GetLoaderForType(int aType,
2844 nsIComponentLoader **aLoader)
2845{
2846 nsresult rv;
2847
2848 // Make sure we have a valid type
2849 if (aType < 0 || aType >= mNLoaderData)
2850 return NS_ERROR_INVALID_ARG;
2851
2852 *aLoader = mLoaderData[aType].loader;
2853 if (*aLoader) {
2854 NS_ADDREF(*aLoader);
2855 return NS_OK;
2856 }
2857
2858 nsCOMPtr<nsIComponentLoader> loader;
2859 loader = do_GetServiceFromCategory("component-loader", mLoaderData[aType].type, &rv);
2860 if (NS_FAILED(rv))
2861 return rv;
2862
2863 rv = loader->Init(this, nsnull);
2864
2865 if (NS_SUCCEEDED(rv)) {
2866 mLoaderData[aType].loader = loader;
2867 NS_ADDREF(mLoaderData[aType].loader);
2868 *aLoader = loader;
2869 NS_ADDREF(*aLoader);
2870 }
2871 return rv;
2872}
2873
2874
2875
2876// Convert a loader type string into an index into the component data
2877// array. Empty loader types are converted to NATIVE. Returns -1 if
2878// loader type cannot be determined.
2879int
2880nsComponentManagerImpl::GetLoaderType(const char *typeStr)
2881{
2882 if (!typeStr || !*typeStr) {
2883 // Empty type strings are NATIVE
2884 return NS_COMPONENT_TYPE_NATIVE;
2885 }
2886
2887 for (int i=NS_COMPONENT_TYPE_NATIVE; i<mNLoaderData; i++) {
2888 if (!strcmp(typeStr, mLoaderData[i].type))
2889 return i;
2890 }
2891 // Not found
2892 return NS_COMPONENT_TYPE_FACTORY_ONLY;
2893}
2894
2895// Add a loader type if not already known. Out the typeIndex
2896// if the loader type is either added or already there.
2897nsresult
2898nsComponentManagerImpl::AddLoaderType(const char *typeStr, int *aTypeIndex)
2899{
2900 int typeIndex = GetLoaderType(typeStr);
2901 if (typeIndex >= 0) {
2902 *aTypeIndex = typeIndex;
2903 return NS_OK;
2904 }
2905
2906 // Add the loader type
2907 if (mNLoaderData >= mMaxNLoaderData) {
2908 NS_ASSERTION(mNLoaderData == mMaxNLoaderData,
2909 "Memory corruption. nsComponentManagerImpl::mLoaderData array overrun.");
2910 // Need to increase our loader array
2911 nsLoaderdata *new_mLoaderData = (nsLoaderdata *) PR_Realloc(mLoaderData, (mMaxNLoaderData + NS_LOADER_DATA_ALLOC_STEP) * sizeof(nsLoaderdata));
2912 if (!new_mLoaderData)
2913 return NS_ERROR_OUT_OF_MEMORY;
2914 mLoaderData = new_mLoaderData;
2915 mMaxNLoaderData += NS_LOADER_DATA_ALLOC_STEP;
2916 }
2917
2918 typeIndex = mNLoaderData;
2919 mLoaderData[typeIndex].type = PL_strdup(typeStr);
2920 if (!mLoaderData[typeIndex].type) {
2921 // mmh! no memory. return failure.
2922 return NS_ERROR_OUT_OF_MEMORY;
2923 }
2924 mLoaderData[typeIndex].loader = nsnull;
2925 mNLoaderData++;
2926
2927 *aTypeIndex = typeIndex;
2928 return NS_OK;
2929}
2930
2931typedef struct
2932{
2933 const nsCID* cid;
2934 const char* regName;
2935 nsIFactory* factory;
2936} UnregisterConditions;
2937
2938static PLDHashOperator PR_CALLBACK
2939DeleteFoundCIDs(PLDHashTable *aTable,
2940 PLDHashEntryHdr *aHdr,
2941 PRUint32 aNumber,
2942 void *aData)
2943{
2944 nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
2945
2946 if (!entry->mFactoryEntry)
2947 return PL_DHASH_NEXT;
2948
2949 UnregisterConditions* data = (UnregisterConditions*)aData;
2950
2951 nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
2952 if (data->cid->Equals(factoryEntry->mCid) &&
2953 ((data->regName && !PL_strcasecmp(factoryEntry->mLocation, data->regName)) ||
2954 (data->factory && data->factory == factoryEntry->mFactory.get())))
2955 return PL_DHASH_REMOVE;
2956
2957 return PL_DHASH_NEXT;
2958}
2959
2960void
2961nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName)
2962{
2963 UnregisterConditions aData;
2964 aData.cid = aClass;
2965 aData.regName = registryName;
2966 aData.factory = nsnull;
2967 PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData);
2968
2969}
2970
2971void
2972nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory)
2973{
2974 UnregisterConditions aData;
2975 aData.cid = aClass;
2976 aData.regName = nsnull;
2977 aData.factory = factory;
2978 PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData);
2979}
2980
2981nsresult
2982nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass,
2983 nsIFactory *aFactory)
2984{
2985#ifdef PR_LOGGING
2986 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
2987 {
2988 char *buf = aClass.ToString();
2989 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
2990 ("nsComponentManager: UnregisterFactory(%s)", buf));
2991 if (buf)
2992 PR_Free(buf);
2993 }
2994#endif
2995 nsFactoryEntry *old;
2996
2997 // first delete all contract id entries that are registered with this cid.
2998 DeleteContractIDEntriesByCID(&aClass, aFactory);
2999
3000 // next check to see if there is a CID registered
3001 nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
3002 old = GetFactoryEntry(aClass);
3003
3004 if (old && (old->mFactory.get() == aFactory))
3005 {
3006 nsAutoMonitor mon(mMon);
3007 PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
3008 rv = NS_OK;
3009 }
3010
3011 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
3012 ("\t\tUnregisterFactory() %s",
3013 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
3014 return rv;
3015}
3016
3017nsresult
3018nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass,
3019 const char *registryName)
3020{
3021#ifdef PR_LOGGING
3022 if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
3023 {
3024 char *buf = aClass.ToString();
3025 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
3026 ("nsComponentManager: UnregisterComponent(%s)", buf));
3027 if (buf)
3028 PR_Free(buf);
3029 }
3030#endif
3031
3032 NS_ENSURE_ARG_POINTER(registryName);
3033 nsFactoryEntry *old;
3034
3035 // first delete all contract id entries that are registered with this cid.
3036 DeleteContractIDEntriesByCID(&aClass, registryName);
3037
3038 // next check to see if there is a CID registered
3039 old = GetFactoryEntry(aClass);
3040 if (old && old->mLocation && !PL_strcasecmp(old->mLocation, registryName))
3041 {
3042 nsAutoMonitor mon(mMon);
3043 PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
3044 }
3045
3046 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
3047 ("nsComponentManager: Factory unregister(%s) succeeded.", registryName));
3048
3049 return NS_OK;
3050}
3051
3052nsresult
3053nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass,
3054 nsIFile *aLibrarySpec)
3055{
3056 nsXPIDLCString registryName;
3057 nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName));
3058 if (NS_FAILED(rv)) return rv;
3059 return UnregisterComponent(aClass, registryName);
3060}
3061
3062// XXX Need to pass in aWhen and servicemanager
3063nsresult
3064nsComponentManagerImpl::FreeLibraries(void)
3065{
3066 return UnloadLibraries(NS_STATIC_CAST(nsIServiceManager*, this), NS_Timer); // XXX when
3067}
3068
3069// Private implementation of unloading libraries
3070nsresult
3071nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr, PRInt32 aWhen)
3072{
3073 nsresult rv = NS_OK;
3074
3075 nsAutoMonitor mon(mMon);
3076
3077 PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
3078 ("nsComponentManager: Unloading Libraries."));
3079
3080 // UnloadAll the loaders
3081 /* iterate over all known loaders and ask them to autoregister. */
3082 // Skip mNativeComponentLoader
3083 for (int i=NS_COMPONENT_TYPE_NATIVE + 1; i<mNLoaderData; i++) {
3084 if (mLoaderData[i].loader) {
3085 rv = mLoaderData[i].loader->UnloadAll(aWhen);
3086 if (NS_FAILED(rv))
3087 break;
3088 }
3089 }
3090
3091 // UnloadAll the native loader
3092 rv = mNativeComponentLoader->UnloadAll(aWhen);
3093 return rv;
3094}
3095
3096////////////////////////////////////////////////////////////////////////////////
3097
3098/**
3099 * AutoRegister(RegistrationInstant, const char *directory)
3100 *
3101 * Given a directory in the following format, this will ensure proper registration
3102 * of all components. No default directory is looked at.
3103 *
3104 * Directory and fullname are what NSPR will accept. For eg.
3105 * WIN y:/home/dp/mozilla/dist/bin
3106 * UNIX /home/dp/mozilla/dist/bin
3107 * MAC /Hard drive/mozilla/dist/apprunner
3108 *
3109 * This will take care not loading already registered dlls, finding and
3110 * registering new dlls, re-registration of modified dlls
3111 *
3112 */
3113
3114nsresult
3115nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec)
3116{
3117 return AutoRegisterImpl(when, inDirSpec);
3118}
3119
3120nsresult
3121nsComponentManagerImpl::AutoRegisterImpl(PRInt32 when,
3122 nsIFile *inDirSpec,
3123 PRBool fileIsCompDir)
3124{
3125 nsCOMPtr<nsIFile> dir;
3126 nsresult rv;
3127
3128#ifdef DEBUG
3129 // testing release behaviour
3130 if (getenv("XPCOM_NO_AUTOREG"))
3131 return NS_OK;
3132#endif
3133 if (inDirSpec)
3134 {
3135 // Use supplied components' directory
3136 dir = inDirSpec;
3137 }
3138 else
3139 {
3140 mComponentsDir->Clone(getter_AddRefs(dir));
3141 if (!dir)
3142 return NS_ERROR_NOT_INITIALIZED;
3143 }
3144
3145 nsCOMPtr<nsIInterfaceInfoManager> iim =
3146 dont_AddRef(XPTI_GetInterfaceInfoManager());
3147
3148 if (!iim)
3149 return NS_ERROR_UNEXPECTED;
3150
3151 // Notify observers of xpcom autoregistration start
3152 NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
3153 nsnull,
3154 "start");
3155
3156 /* do the native loader first, so we can find other loaders */
3157 rv = mNativeComponentLoader->AutoRegisterComponents((PRInt32)when, dir);
3158 if (NS_FAILED(rv)) return rv;
3159
3160#ifdef ENABLE_STATIC_COMPONENT_LOADER
3161 rv = mStaticComponentLoader->AutoRegisterComponents((PRInt32)when, inDirSpec);
3162 if (NS_FAILED(rv)) return rv;
3163#endif
3164
3165 /* do InterfaceInfoManager after native loader so it can use components. */
3166 rv = iim->AutoRegisterInterfaces();
3167 if (NS_FAILED(rv)) return rv;
3168
3169 if (!mCategoryManager) {
3170 NS_WARNING("mCategoryManager is null");
3171 return NS_ERROR_UNEXPECTED;
3172 }
3173
3174 nsCOMPtr<nsISimpleEnumerator> loaderEnum;
3175 rv = mCategoryManager->EnumerateCategory("component-loader",
3176 getter_AddRefs(loaderEnum));
3177 if (NS_FAILED(rv)) return rv;
3178
3179 PRBool hasMore;
3180 while (NS_SUCCEEDED(loaderEnum->HasMoreElements(&hasMore)) && hasMore) {
3181 nsCOMPtr<nsISupports> supports;
3182 if (NS_FAILED(loaderEnum->GetNext(getter_AddRefs(supports))))
3183 continue;
3184
3185 nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports);
3186 if (!supStr)
3187 continue;
3188
3189 nsCAutoString loaderType;
3190 if (NS_FAILED(supStr->GetData(loaderType)))
3191 continue;
3192
3193 // We depend on the loader being created. Add the loader type and
3194 // create the loader object too.
3195 nsCOMPtr<nsIComponentLoader> loader;
3196 int typeIndex;
3197 rv = AddLoaderType(loaderType.get(), &typeIndex);
3198 if (NS_FAILED(rv))
3199 return rv;
3200 GetLoaderForType(typeIndex, getter_AddRefs(loader));
3201 }
3202
3203 rv = AutoRegisterNonNativeComponents(dir.get());
3204
3205 // Notify observers of xpcom autoregistration completion
3206 NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
3207 nsnull,
3208 "end");
3209
3210 if (mRegistryDirty)
3211 FlushPersistentStore(PR_TRUE);
3212 return rv;
3213}
3214
3215nsresult
3216nsComponentManagerImpl::AutoRegisterNonNativeComponents(nsIFile* spec)
3217{
3218 nsresult rv = NS_OK;
3219 nsCOMPtr<nsIFile> directory = spec;
3220
3221 if (!directory) {
3222 mComponentsDir->Clone(getter_AddRefs(directory));
3223 if (!directory)
3224 return NS_ERROR_NOT_INITIALIZED;
3225 }
3226
3227 for (int i = 1; i < mNLoaderData; i++) {
3228 if (!mLoaderData[i].loader) {
3229 rv = GetLoaderForType(i, &mLoaderData[i].loader);
3230 if (NS_FAILED(rv))
3231 continue;
3232 }
3233 rv = mLoaderData[i].loader->AutoRegisterComponents(0, directory);
3234 if (NS_FAILED(rv))
3235 break;
3236 }
3237
3238 if (NS_SUCCEEDED(rv))
3239 {
3240 PRBool registered;
3241 do {
3242 registered = PR_FALSE;
3243 for (int i = 0; i < mNLoaderData; i++) {
3244 PRBool b = PR_FALSE;
3245 if (mLoaderData[i].loader) {
3246 rv = mLoaderData[i].loader->RegisterDeferredComponents(0, &b);
3247 if (NS_FAILED(rv))
3248 continue;
3249 registered |= b;
3250 }
3251 }
3252 } while (NS_SUCCEEDED(rv) && registered);
3253 }
3254 return rv;
3255}
3256nsresult
3257nsComponentManagerImpl::AutoRegisterComponent(PRInt32 when,
3258 nsIFile *component)
3259{
3260 nsresult rv = NS_OK, res = NS_ERROR_FACTORY_NOT_REGISTERED;
3261 /*
3262 * Do we have to give the native loader first crack at it?
3263 * I vote ``no''.
3264 */
3265 for (int i = 0; i < mNLoaderData; i++) {
3266 PRBool didRegister;
3267 if (!mLoaderData[i].loader) {
3268 nsCOMPtr<nsIComponentLoader> loader;
3269 rv = GetLoaderForType(i, getter_AddRefs(loader));
3270 if (NS_FAILED(rv))
3271 continue;
3272 // |GetLoaderForType| has filled in |mLoaderData[i].loader|:
3273 NS_ASSERTION(loader == mLoaderData[i].loader, "oops");
3274 }
3275 rv = mLoaderData[i].loader->AutoRegisterComponent((int)when, component, &didRegister);
3276 if (NS_FAILED(rv)) {
3277 res = rv;
3278 } else if (didRegister) {
3279 return rv;
3280 }
3281 }
3282 return res;
3283}
3284
3285nsresult
3286nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 when,
3287 nsIFile *component)
3288{
3289 nsresult rv = NS_OK;
3290 for (int i = 0; i < mNLoaderData; i++) {
3291 PRBool didUnRegister;
3292 if (!mLoaderData[i].loader) {
3293 rv = GetLoaderForType(i, &mLoaderData[i].loader);
3294 if (NS_FAILED(rv))
3295 continue;
3296 }
3297 rv = mLoaderData[i].loader->AutoUnregisterComponent(when, component, &didUnRegister);
3298 if (NS_SUCCEEDED(rv) && didUnRegister) {
3299 // we need to remove this file from our list of known libraries.
3300 RemoveFileInfo(component, nsnull);
3301 mRegistryDirty = PR_TRUE;
3302 break;
3303 }
3304 }
3305 return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK;
3306}
3307
3308nsresult
3309nsComponentManagerImpl::IsRegistered(const nsCID &aClass,
3310 PRBool *aRegistered)
3311{
3312 if (!aRegistered)
3313 {
3314 NS_ASSERTION(0, "null ptr");
3315 return NS_ERROR_NULL_POINTER;
3316 }
3317 *aRegistered = (nsnull != GetFactoryEntry(aClass));
3318 return NS_OK;
3319}
3320
3321nsresult
3322nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEnumerator)
3323{
3324 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3325 if (!aEnumerator)
3326 {
3327 return NS_ERROR_NULL_POINTER;
3328 }
3329 *aEnumerator = nsnull;
3330
3331 nsresult rv;
3332
3333 PLDHashTableEnumeratorImpl *aEnum;
3334 rv = PL_NewDHashTableEnumerator(&mFactories,
3335 ConvertFactoryEntryToCID,
3336 (void*)this,
3337 &aEnum);
3338 if (NS_FAILED(rv))
3339 return rv;
3340
3341 *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum);
3342 return NS_OK;
3343}
3344
3345nsresult
3346nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEnumerator)
3347{
3348 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3349 if (!aEnumerator)
3350 {
3351 return NS_ERROR_NULL_POINTER;
3352 }
3353
3354 *aEnumerator = nsnull;
3355
3356 nsresult rv;
3357 PLDHashTableEnumeratorImpl *aEnum;
3358 rv = PL_NewDHashTableEnumerator(&mContractIDs,
3359 ConvertContractIDKeyToString,
3360 (void*)this,
3361 &aEnum);
3362 if (NS_FAILED(rv))
3363 return rv;
3364
3365 *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum);
3366 return NS_OK;
3367}
3368
3369// nsIComponentRegistrar
3370
3371NS_IMETHODIMP
3372nsComponentManagerImpl::AutoRegister(nsIFile *aSpec)
3373{
3374 if (aSpec == nsnull)
3375 return AutoRegisterImpl(0, aSpec);
3376
3377 PRBool directory;
3378 aSpec->IsDirectory(&directory);
3379
3380 if (directory)
3381 return AutoRegisterImpl(0, aSpec, PR_FALSE);
3382
3383 return AutoRegisterComponent(0, aSpec);
3384}
3385
3386NS_IMETHODIMP
3387nsComponentManagerImpl::AutoUnregister(nsIFile *aSpec)
3388{
3389 // unregistering a complete directory is not implmeneted yet...FIX
3390 if (aSpec == nsnull)
3391 return NS_ERROR_NOT_IMPLEMENTED;
3392
3393 PRBool directory;
3394 aSpec->IsDirectory(&directory);
3395
3396 if (directory)
3397 return NS_ERROR_NOT_IMPLEMENTED;
3398
3399 return AutoUnregisterComponent(0, aSpec);
3400}
3401
3402NS_IMETHODIMP
3403nsComponentManagerImpl::RegisterFactory(const nsCID & aClass,
3404 const char *aClassName,
3405 const char *aContractID,
3406 nsIFactory *aFactory)
3407{
3408 return RegisterFactory(aClass,
3409 aClassName,
3410 aContractID,
3411 aFactory,
3412 PR_TRUE);
3413}
3414
3415NS_IMETHODIMP
3416nsComponentManagerImpl::RegisterFactoryLocation(const nsCID & aClass,
3417 const char *aClassName,
3418 const char *aContractID,
3419 nsIFile *aFile,
3420 const char *loaderStr,
3421 const char *aType)
3422{
3423 nsXPIDLCString registryName;
3424
3425 if (!loaderStr)
3426 {
3427 nsresult rv = RegistryLocationForSpec(aFile, getter_Copies(registryName));
3428 if (NS_FAILED(rv))
3429 return rv;
3430 }
3431
3432 nsresult rv;
3433 rv = RegisterComponentWithType(aClass,
3434 aClassName,
3435 aContractID,
3436 aFile,
3437 (loaderStr ? loaderStr : registryName.get()),
3438 PR_TRUE,
3439 PR_TRUE,
3440 (aType ? aType : nativeComponentType));
3441 return rv;
3442}
3443
3444NS_IMETHODIMP
3445nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID & aClass,
3446 nsIFile *aFile)
3447{
3448 return UnregisterComponentSpec(aClass, aFile);
3449}
3450
3451NS_IMETHODIMP
3452nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass,
3453 PRBool *_retval)
3454{
3455 return IsRegistered(aClass, _retval);
3456}
3457
3458NS_IMETHODIMP
3459nsComponentManagerImpl::IsContractIDRegistered(const char *aClass,
3460 PRBool *_retval)
3461{
3462 nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass));
3463
3464 if (entry)
3465 *_retval = PR_TRUE;
3466 else
3467 *_retval = PR_FALSE;
3468 return NS_OK;
3469}
3470
3471NS_IMETHODIMP
3472nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator)
3473{
3474 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3475
3476 if (!aEnumerator)
3477 return NS_ERROR_NULL_POINTER;
3478
3479 *aEnumerator = nsnull;
3480
3481 nsresult rv;
3482 PLDHashTableEnumeratorImpl *aEnum;
3483 rv = PL_NewDHashTableEnumerator(&mFactories,
3484 ConvertFactoryEntryToCID,
3485 (void*)this,
3486 &aEnum);
3487 if (NS_FAILED(rv))
3488 return rv;
3489
3490 *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum);
3491 return NS_OK;
3492}
3493
3494NS_IMETHODIMP
3495nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator)
3496{
3497 NS_ASSERTION(aEnumerator != nsnull, "null ptr");
3498 if (!aEnumerator)
3499 return NS_ERROR_NULL_POINTER;
3500
3501 *aEnumerator = nsnull;
3502
3503 nsresult rv;
3504 PLDHashTableEnumeratorImpl *aEnum;
3505 rv = PL_NewDHashTableEnumerator(&mContractIDs,
3506 ConvertContractIDKeyToString,
3507 (void*)this,
3508 &aEnum);
3509 if (NS_FAILED(rv))
3510 return rv;
3511
3512 *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum);
3513 return NS_OK;
3514}
3515
3516NS_IMETHODIMP
3517nsComponentManagerImpl::CIDToContractID(const nsCID & aClass,
3518 char **_retval)
3519{
3520 return CLSIDToContractID(aClass,
3521 nsnull,
3522 _retval);
3523}
3524
3525NS_IMETHODIMP
3526nsComponentManagerImpl::ContractIDToCID(const char *aContractID,
3527 nsCID * *_retval)
3528{
3529 *_retval = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
3530 if (!*_retval)
3531 return NS_ERROR_OUT_OF_MEMORY;
3532
3533 nsresult rv = ContractIDToClassID(aContractID, *_retval);
3534 if (NS_FAILED(rv)) {
3535 nsMemory::Free(*_retval);
3536 *_retval = nsnull;
3537 }
3538 return rv;
3539}
3540
3541// end nsIComponentRegistrar
3542
3543
3544
3545
3546NS_IMETHODIMP
3547nsComponentManagerImpl::HasFileChanged(nsIFile *file, const char *loaderString, PRInt64 modDate, PRBool *_retval)
3548{
3549 *_retval = PR_TRUE;
3550
3551 nsXPIDLCString registryName;
3552 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3553 if (NS_FAILED(rv))
3554 return rv;
3555
3556 nsCStringKey key(registryName);
3557 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
3558 if (entry)
3559 *_retval = entry->Modified(&modDate);
3560 else
3561 *_retval = PR_TRUE;
3562
3563 return NS_OK;
3564}
3565
3566NS_IMETHODIMP
3567nsComponentManagerImpl::SaveFileInfo(nsIFile *file, const char *loaderString, PRInt64 modDate)
3568{
3569 mRegistryDirty = PR_TRUE;
3570 nsXPIDLCString registryName;
3571 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3572 if (NS_FAILED(rv))
3573 return rv;
3574
3575 // check to see if exists in the array before adding it so that we don't have dups.
3576 nsCStringKey key(registryName);
3577 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
3578
3579 if (entry)
3580 {
3581 entry->SetDate(&modDate);
3582 return NS_OK;
3583 }
3584
3585 entry = new AutoRegEntry(registryName, &modDate);
3586 if (!entry)
3587 return NS_ERROR_OUT_OF_MEMORY;
3588
3589 mAutoRegEntries.Put(&key, entry);
3590 return NS_OK;
3591}
3592
3593NS_IMETHODIMP
3594nsComponentManagerImpl::RemoveFileInfo(nsIFile *file, const char *loaderString)
3595{
3596 mRegistryDirty = PR_TRUE;
3597 nsXPIDLCString registryName;
3598 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3599 if (NS_FAILED(rv))
3600 return rv;
3601
3602 nsCStringKey key(registryName);
3603 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Remove(&key);
3604 if (entry)
3605 delete entry;
3606
3607 return NS_OK;
3608}
3609
3610NS_IMETHODIMP
3611nsComponentManagerImpl::GetOptionalData(nsIFile *file,
3612 const char *loaderString,
3613 char **_retval)
3614{
3615 nsXPIDLCString registryName;
3616 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3617 if (NS_FAILED(rv))
3618 return rv;
3619
3620 nsCStringKey key(registryName);
3621 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
3622 if (!entry) {
3623 return NS_ERROR_NOT_INITIALIZED;
3624 }
3625 const char* opData = entry->GetOptionalData();
3626
3627 if (opData)
3628 *_retval = ToNewCString(nsDependentCString(opData));
3629 else
3630 *_retval = nsnull;
3631 return NS_OK;
3632 }
3633
3634NS_IMETHODIMP
3635nsComponentManagerImpl::SetOptionalData(nsIFile *file,
3636 const char *loaderString,
3637 const char *data)
3638{
3639 nsXPIDLCString registryName;
3640 nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
3641 if (NS_FAILED(rv))
3642 return rv;
3643
3644 nsCStringKey key(registryName);
3645 AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
3646
3647 if (!entry) {
3648 PRInt64 zero = LL_Zero();
3649 entry = new AutoRegEntry(registryName, &zero);
3650 if (!entry)
3651 return NS_ERROR_OUT_OF_MEMORY;
3652
3653 mAutoRegEntries.Put(&key, entry);
3654 }
3655
3656 entry->SetOptionalData(data);
3657
3658 return NS_OK;
3659 }
3660
3661
3662NS_IMETHODIMP
3663nsComponentManagerImpl::FlushPersistentStore(PRBool now)
3664{
3665 mRegistryDirty = PR_TRUE;
3666 if (now)
3667 return WritePersistentRegistry();
3668
3669 return NS_OK;
3670}
3671
3672
3673////////////////////////////////////////////////////////////////////////////////
3674// Static Access Functions
3675////////////////////////////////////////////////////////////////////////////////
3676
3677NS_COM nsresult
3678NS_GetGlobalComponentManager(nsIComponentManager* *result)
3679{
3680#ifdef DEBUG_dougt
3681 // NS_WARNING("DEPRECATED FUNCTION: Use NS_GetComponentManager");
3682#endif
3683 nsresult rv = NS_OK;
3684
3685 if (nsComponentManagerImpl::gComponentManager == nsnull)
3686 {
3687 // XPCOM needs initialization.
3688 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3689 }
3690
3691 if (NS_SUCCEEDED(rv))
3692 {
3693 // NO ADDREF since this is never intended to be released.
3694 // See nsComponentManagerObsolete.h for the reason for such
3695 // casting uglyness
3696 *result = (nsIComponentManager*)(void*)(nsIComponentManagerObsolete*) nsComponentManagerImpl::gComponentManager;
3697 }
3698
3699 return rv;
3700}
3701
3702NS_COM nsresult
3703NS_GetComponentManager(nsIComponentManager* *result)
3704{
3705 if (nsComponentManagerImpl::gComponentManager == nsnull)
3706 {
3707 // XPCOM needs initialization.
3708 nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3709 if (NS_FAILED(rv))
3710 return rv;
3711 }
3712
3713 *result = NS_STATIC_CAST(nsIComponentManager*,
3714 nsComponentManagerImpl::gComponentManager);
3715 NS_IF_ADDREF(*result);
3716 return NS_OK;
3717}
3718
3719NS_COM nsresult
3720NS_GetServiceManager(nsIServiceManager* *result)
3721{
3722 nsresult rv = NS_OK;
3723
3724 if (nsComponentManagerImpl::gComponentManager == nsnull)
3725 {
3726#ifdef VBOX
3727 // While XPCOM might need initialization, we're not in a position
3728 // to pass the right values to this call. This is actually triggered
3729 // on object destruction, so there is no point in re-initializing,
3730 // and actually the attempt would lead to nested calls to
3731 // xptiInterfaceInfoManager::BuildFileSearchPath, which it detects
3732 // as unsafe in debug builds. Just fail, no real problem.
3733#ifdef DEBUG
3734 printf("NS_GetServiceManager: no current instance, suppressed XPCOM initialization!\n");
3735#endif
3736 rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
3737#else /* !VBOX */
3738 // XPCOM needs initialization.
3739 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3740#endif /* !VBOX */
3741 }
3742
3743 if (NS_FAILED(rv))
3744 return rv;
3745
3746 *result = NS_STATIC_CAST(nsIServiceManager*,
3747 nsComponentManagerImpl::gComponentManager);
3748 NS_IF_ADDREF(*result);
3749 return NS_OK;
3750}
3751
3752
3753NS_COM nsresult
3754NS_GetComponentRegistrar(nsIComponentRegistrar* *result)
3755{
3756 nsresult rv = NS_OK;
3757
3758 if (nsComponentManagerImpl::gComponentManager == nsnull)
3759 {
3760 // XPCOM needs initialization.
3761 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3762 }
3763
3764 if (NS_FAILED(rv))
3765 return rv;
3766
3767 *result = NS_STATIC_CAST(nsIComponentRegistrar*,
3768 nsComponentManagerImpl::gComponentManager);
3769 NS_IF_ADDREF(*result);
3770 return NS_OK;
3771}
3772
3773
3774// nsIComponentLoaderManager is not frozen, but is defined here
3775// so that I can use it internally in xpcom.
3776nsresult
3777NS_GetComponentLoaderManager(nsIComponentLoaderManager* *result)
3778{
3779 nsresult rv = NS_OK;
3780
3781 if (nsComponentManagerImpl::gComponentManager == NULL)
3782 {
3783 // XPCOM needs initialization.
3784 rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
3785 }
3786
3787 if (NS_FAILED(rv))
3788 return rv;
3789
3790 *result = NS_STATIC_CAST(nsIComponentLoaderManager*,
3791 nsComponentManagerImpl::gComponentManager);
3792 NS_IF_ADDREF(*result);
3793 return NS_OK;
3794}
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