VirtualBox

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

Last change on this file was 109067, checked in by vboxsync, 3 weeks ago

libs/xpcom,Main/glue,++: Bake the automatic re-registration of XPCOM components (in the components directory) into the NS_InitXPCOM2 call to avoid the problem of VBoxXPCOMIPCC.so/dylib being engaged at the end of NS_InitXPCOM2 and unable to re-register if this is done later by the client code. Added a fFlagsInit parameter to indicate whether this auto reg behaviour is required or not and renamed NS_InitXPCOM2 to NS_InitXPCOM2Ex (the latter to prevent confusion). bugref:10896 ticketref:22193

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

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