VirtualBox

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

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

libs/xpcom/xpcom: Convert nsComponentManager registry reading from nsprpub to IPRT streams, bugref:10545 [fix]

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