VirtualBox

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

最後變更 在這個檔案從102204是 102197,由 vboxsync 提交於 14 月 前

libs/xpcom: Remove unused prio.h includes, bugref:10545

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

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