VirtualBox

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

Last change on this file since 102186 was 102186, checked in by vboxsync, 15 months ago

libs/xpcom/xpcom: Convert nsComponentManager and nsCategoryManager registry writing from nsprpub to IPRT streams, bugref:10545

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

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