VirtualBox

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

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

libs/xpcom: Replace PL_strdup/PL_strndup/PL_strfree with IPRT equivalents, bugref:10545

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

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