VirtualBox

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

最後變更 在這個檔案是 104493,由 vboxsync 提交於 11 月 前

libs/xpcom/components: Some smaller cleanups, bugref:3409

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

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