VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp@ 101976

Last change on this file since 101976 was 101976, checked in by vboxsync, 13 months ago

libs/xpcom/xpcom/components: Convert some code from using PRLock to IPRT's RTSEMFASTMUTEX locks, bugref:10545

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.8 KB
Line 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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) 2000
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Scott Collins <[email protected]>
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
39#define PL_ARENA_CONST_ALIGN_MASK 7
40
41#include "nsICategoryManager.h"
42#include "nsCategoryManager.h"
43
44#include "plarena.h"
45#include "prio.h"
46#include "prprf.h"
47#include "prlock.h"
48#include "nsCOMPtr.h"
49#include "nsTHashtable.h"
50#include "nsClassHashtable.h"
51#include "nsIFactory.h"
52#include "nsIStringEnumerator.h"
53#include "nsSupportsPrimitives.h"
54#include "nsIServiceManagerUtils.h"
55#include "nsIObserver.h"
56#include "nsReadableUtils.h"
57#include "nsCRT.h"
58#include "nsEnumeratorUtils.h"
59
60#include <iprt/assert.h>
61#include <iprt/errcore.h>
62
63class nsIComponentLoaderManager;
64
65/*
66 CategoryDatabase
67 contains 0 or more 1-1 mappings of string to Category
68 each Category contains 0 or more 1-1 mappings of string keys to string values
69
70 In other words, the CategoryDatabase is a tree, whose root is a hashtable.
71 Internal nodes (or Categories) are hashtables. Leaf nodes are strings.
72
73 The leaf strings are allocated in an arena, because we assume they're not
74 going to change much ;)
75*/
76
77#define NS_CATEGORYMANAGER_ARENA_SIZE (1024 * 8)
78
79// pulled in from nsComponentManager.cpp
80char* ArenaStrdup(const char* s, PLArenaPool* aArena);
81
82//
83// BaseStringEnumerator is subclassed by EntryEnumerator and
84// CategoryEnumerator
85//
86class BaseStringEnumerator
87 : public nsISimpleEnumerator,
88 nsIUTF8StringEnumerator
89{
90public:
91 NS_DECL_ISUPPORTS
92 NS_DECL_NSISIMPLEENUMERATOR
93 NS_DECL_NSIUTF8STRINGENUMERATOR
94
95protected:
96 BaseStringEnumerator()
97 : mArray(nsnull),
98 mCount(0),
99 mSimpleCurItem(0),
100 mStringCurItem(0) { }
101
102 // A virtual destructor is needed here because subclasses of
103 // BaseStringEnumerator do not implement their own Release() method.
104
105 virtual ~BaseStringEnumerator()
106 {
107 if (mArray)
108 delete[] mArray;
109 }
110
111 const char** mArray;
112 PRUint32 mCount;
113 PRUint32 mSimpleCurItem;
114 PRUint32 mStringCurItem;
115};
116
117NS_IMPL_ISUPPORTS2(BaseStringEnumerator, nsISimpleEnumerator, nsIUTF8StringEnumerator)
118
119NS_IMETHODIMP
120BaseStringEnumerator::HasMoreElements(PRBool *_retval)
121{
122 *_retval = (mSimpleCurItem < mCount);
123
124 return NS_OK;
125}
126
127NS_IMETHODIMP
128BaseStringEnumerator::GetNext(nsISupports **_retval)
129{
130 if (mSimpleCurItem >= mCount)
131 return NS_ERROR_FAILURE;
132
133 nsSupportsDependentCString* str =
134 new nsSupportsDependentCString(mArray[mSimpleCurItem++]);
135 if (!str)
136 return NS_ERROR_OUT_OF_MEMORY;
137
138 *_retval = str;
139 NS_ADDREF(*_retval);
140 return NS_OK;
141}
142
143NS_IMETHODIMP
144BaseStringEnumerator::HasMore(PRBool *_retval)
145{
146 *_retval = (mStringCurItem < mCount);
147
148 return NS_OK;
149}
150
151NS_IMETHODIMP
152BaseStringEnumerator::GetNext(nsACString& _retval)
153{
154 if (mStringCurItem >= mCount)
155 return NS_ERROR_FAILURE;
156
157 _retval = nsDependentCString(mArray[mStringCurItem++]);
158 return NS_OK;
159}
160
161
162//
163// EntryEnumerator is the wrapper that allows nsICategoryManager::EnumerateCategory
164//
165class EntryEnumerator
166 : public BaseStringEnumerator
167{
168public:
169 static EntryEnumerator* Create(nsTHashtable<CategoryLeaf>& aTable);
170
171private:
172 static PLDHashOperator PR_CALLBACK
173 enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg);
174};
175
176
177PLDHashOperator PR_CALLBACK
178EntryEnumerator::enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg)
179{
180 EntryEnumerator* mythis = NS_STATIC_CAST(EntryEnumerator*, userArg);
181 mythis->mArray[mythis->mCount++] = aLeaf->GetKey();
182
183 return PL_DHASH_NEXT;
184}
185
186EntryEnumerator*
187EntryEnumerator::Create(nsTHashtable<CategoryLeaf>& aTable)
188{
189 EntryEnumerator* enumObj = new EntryEnumerator();
190 if (!enumObj)
191 return nsnull;
192
193 enumObj->mArray = new char const* [aTable.Count()];
194 if (!enumObj->mArray) {
195 delete enumObj;
196 return nsnull;
197 }
198
199 aTable.EnumerateEntries(enumfunc_createenumerator, enumObj);
200
201 return enumObj;
202}
203
204
205//
206// CategoryNode implementations
207//
208
209CategoryNode*
210CategoryNode::Create(PLArenaPool* aArena)
211{
212 CategoryNode* node = new(aArena) CategoryNode();
213 if (!node)
214 return nsnull;
215
216 if (!node->mTable.Init()) {
217 delete node;
218 return nsnull;
219 }
220
221 node->mLock = NIL_RTSEMFASTMUTEX;
222 int vrc = RTSemFastMutexCreate(&node->mLock);
223 if (RT_FAILURE(vrc)) {
224 delete node;
225 return nsnull;
226 }
227
228 return node;
229}
230
231CategoryNode::~CategoryNode()
232{
233 if (mLock != NIL_RTSEMFASTMUTEX)
234 {
235 RTSemFastMutexDestroy(mLock);
236 mLock = NIL_RTSEMFASTMUTEX;
237 }
238}
239
240void*
241CategoryNode::operator new(size_t aSize, PLArenaPool* aArena)
242{
243 void* p;
244 PL_ARENA_ALLOCATE(p, aArena, aSize);
245 return p;
246}
247
248NS_METHOD
249CategoryNode::GetLeaf(const char* aEntryName,
250 char** _retval)
251{
252 RTSemFastMutexRequest(mLock);
253 nsresult rv = NS_ERROR_NOT_AVAILABLE;
254 CategoryLeaf* ent =
255 mTable.GetEntry(aEntryName);
256
257 // we only want the non-persistent value
258 if (ent && ent->nonpValue) {
259 *_retval = nsCRT::strdup(ent->nonpValue);
260 if (*_retval)
261 rv = NS_OK;
262 }
263 RTSemFastMutexRelease(mLock);
264
265 return rv;
266}
267
268NS_METHOD
269CategoryNode::AddLeaf(const char* aEntryName,
270 const char* aValue,
271 PRBool aPersist,
272 PRBool aReplace,
273 char** _retval,
274 PLArenaPool* aArena)
275{
276 RTSemFastMutexRequest(mLock);
277 CategoryLeaf* leaf =
278 mTable.GetEntry(aEntryName);
279
280 nsresult rv = NS_OK;
281 if (leaf) {
282 //if the entry was found, aReplace must be specified
283 if (!aReplace && (leaf->nonpValue || (aPersist && leaf->pValue )))
284 rv = NS_ERROR_INVALID_ARG;
285 } else {
286 const char* arenaEntryName = ArenaStrdup(aEntryName, aArena);
287 if (!arenaEntryName) {
288 rv = NS_ERROR_OUT_OF_MEMORY;
289 } else {
290 leaf = mTable.PutEntry(arenaEntryName);
291 if (!leaf)
292 rv = NS_ERROR_OUT_OF_MEMORY;
293 }
294 }
295
296 if (NS_SUCCEEDED(rv)) {
297 const char* arenaValue = ArenaStrdup(aValue, aArena);
298 if (!arenaValue) {
299 rv = NS_ERROR_OUT_OF_MEMORY;
300 } else {
301 leaf->nonpValue = arenaValue;
302 if (aPersist)
303 leaf->pValue = arenaValue;
304 }
305 }
306
307 RTSemFastMutexRelease(mLock);
308 return rv;
309}
310
311NS_METHOD
312CategoryNode::DeleteLeaf(const char* aEntryName,
313 PRBool aDontPersist)
314{
315 // we don't throw any errors, because it normally doesn't matter
316 // and it makes JS a lot cleaner
317 RTSemFastMutexRequest(mLock);
318
319 if (aDontPersist) {
320 // we can just remove the entire hash entry without introspection
321 mTable.RemoveEntry(aEntryName);
322 } else {
323 // if we are keeping the persistent value, we need to look at
324 // the contents of the current entry
325 CategoryLeaf* leaf = mTable.GetEntry(aEntryName);
326 if (leaf) {
327 if (leaf->pValue) {
328 leaf->nonpValue = nsnull;
329 } else {
330 // if there is no persistent value, just remove the entry
331 mTable.RawRemoveEntry(leaf);
332 }
333 }
334 }
335 RTSemFastMutexRelease(mLock);
336
337 return NS_OK;
338}
339
340NS_METHOD
341CategoryNode::Enumerate(nsISimpleEnumerator **_retval)
342{
343 NS_ENSURE_ARG_POINTER(_retval);
344
345 RTSemFastMutexRequest(mLock);
346 EntryEnumerator* enumObj = EntryEnumerator::Create(mTable);
347 RTSemFastMutexRelease(mLock);
348
349 if (!enumObj)
350 return NS_ERROR_OUT_OF_MEMORY;
351
352 *_retval = enumObj;
353 NS_ADDREF(*_retval);
354 return NS_OK;
355}
356
357struct persistent_userstruct {
358 PRFileDesc* fd;
359 const char* categoryName;
360 PRBool success;
361};
362
363PLDHashOperator PR_CALLBACK
364enumfunc_pentries(CategoryLeaf* aLeaf, void* userArg)
365{
366 persistent_userstruct* args =
367 NS_STATIC_CAST(persistent_userstruct*, userArg);
368
369 PLDHashOperator status = PL_DHASH_NEXT;
370
371 if (aLeaf->pValue) {
372 if (PR_fprintf(args->fd,
373 "%s,%s,%s\n",
374 args->categoryName,
375 aLeaf->GetKey(),
376 aLeaf->pValue) == (PRUint32) -1) {
377 args->success = PR_FALSE;
378 status = PL_DHASH_STOP;
379 }
380 }
381
382 return status;
383}
384
385PRBool
386CategoryNode::WritePersistentEntries(PRFileDesc* fd, const char* aCategoryName)
387{
388 persistent_userstruct args = {
389 fd,
390 aCategoryName,
391 PR_TRUE
392 };
393
394 RTSemFastMutexRequest(mLock);
395 mTable.EnumerateEntries(enumfunc_pentries, &args);
396 RTSemFastMutexRelease(mLock);
397
398 return args.success;
399}
400
401
402//
403// CategoryEnumerator class
404//
405
406class CategoryEnumerator
407 : public BaseStringEnumerator
408{
409public:
410 static CategoryEnumerator* Create(nsClassHashtable<nsDepCharHashKey, CategoryNode>& aTable);
411
412private:
413 static PLDHashOperator PR_CALLBACK
414 enumfunc_createenumerator(const char* aStr,
415 CategoryNode* aNode,
416 void* userArg);
417};
418
419CategoryEnumerator*
420CategoryEnumerator::Create(nsClassHashtable<nsDepCharHashKey, CategoryNode>& aTable)
421{
422 CategoryEnumerator* enumObj = new CategoryEnumerator();
423 if (!enumObj)
424 return nsnull;
425
426 enumObj->mArray = new const char* [aTable.Count()];
427 if (!enumObj->mArray) {
428 delete enumObj;
429 return nsnull;
430 }
431
432 aTable.EnumerateRead(enumfunc_createenumerator, enumObj);
433
434 return enumObj;
435}
436
437PLDHashOperator PR_CALLBACK
438CategoryEnumerator::enumfunc_createenumerator(const char* aStr, CategoryNode* aNode, void* userArg)
439{
440 CategoryEnumerator* mythis = NS_STATIC_CAST(CategoryEnumerator*, userArg);
441
442 // if a category has no entries, we pretend it doesn't exist
443 if (aNode->Count())
444 mythis->mArray[mythis->mCount++] = aStr;
445
446 return PL_DHASH_NEXT;
447}
448
449
450//
451// nsCategoryManager implementations
452//
453
454NS_IMPL_THREADSAFE_ISUPPORTS1(nsCategoryManager, nsICategoryManager)
455
456nsCategoryManager*
457nsCategoryManager::Create()
458{
459 nsCategoryManager* manager = new nsCategoryManager();
460
461 if (!manager)
462 return nsnull;
463
464 PL_INIT_ARENA_POOL(&(manager->mArena), "CategoryManagerArena",
465 NS_CATEGORYMANAGER_ARENA_SIZE); // this never fails
466
467 if (!manager->mTable.Init()) {
468 delete manager;
469 return nsnull;
470 }
471
472 manager->mLock = NIL_RTSEMFASTMUTEX;
473 int vrc = RTSemFastMutexCreate(&manager->mLock);
474 if (RT_FAILURE(vrc))
475 {
476 delete manager;
477 return nsnull;
478 }
479
480 return manager;
481}
482
483nsCategoryManager::~nsCategoryManager()
484{
485 if (mLock != NIL_RTSEMFASTMUTEX)
486 {
487 RTSemFastMutexDestroy(mLock);
488 mLock = NIL_RTSEMFASTMUTEX;
489 }
490
491 // the hashtable contains entries that must be deleted before the arena is
492 // destroyed, or else you will have PRLocks undestroyed and other Really
493 // Bad Stuff (TM)
494 mTable.Clear();
495
496 PL_FinishArenaPool(&mArena);
497}
498
499inline CategoryNode*
500nsCategoryManager::get_category(const char* aName) {
501 CategoryNode* node;
502 if (!mTable.Get(aName, &node)) {
503 return nsnull;
504 }
505 return node;
506}
507
508NS_IMETHODIMP
509nsCategoryManager::GetCategoryEntry( const char *aCategoryName,
510 const char *aEntryName,
511 char **_retval )
512{
513 NS_ENSURE_ARG_POINTER(aCategoryName);
514 NS_ENSURE_ARG_POINTER(aEntryName);
515 NS_ENSURE_ARG_POINTER(_retval);
516
517 nsresult status = NS_ERROR_NOT_AVAILABLE;
518
519 RTSemFastMutexRequest(mLock);
520 CategoryNode* category = get_category(aCategoryName);
521 RTSemFastMutexRelease(mLock);
522
523 if (category) {
524 status = category->GetLeaf(aEntryName, _retval);
525 }
526
527 return status;
528}
529
530NS_IMETHODIMP
531nsCategoryManager::AddCategoryEntry( const char *aCategoryName,
532 const char *aEntryName,
533 const char *aValue,
534 PRBool aPersist,
535 PRBool aReplace,
536 char **_retval )
537{
538 NS_ENSURE_ARG_POINTER(aCategoryName);
539 NS_ENSURE_ARG_POINTER(aEntryName);
540 NS_ENSURE_ARG_POINTER(aValue);
541
542 // Before we can insert a new entry, we'll need to
543 // find the |CategoryNode| to put it in...
544 RTSemFastMutexRequest(mLock);
545 CategoryNode* category = get_category(aCategoryName);
546
547 if (!category) {
548 // That category doesn't exist yet; let's make it.
549 category = CategoryNode::Create(&mArena);
550
551 char* categoryName = ArenaStrdup(aCategoryName, &mArena);
552 mTable.Put(categoryName, category);
553 }
554 RTSemFastMutexRelease(mLock);
555
556 if (!category)
557 return NS_ERROR_OUT_OF_MEMORY;
558
559 return category->AddLeaf(aEntryName,
560 aValue,
561 aPersist,
562 aReplace,
563 _retval,
564 &mArena);
565}
566
567NS_IMETHODIMP
568nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName,
569 const char *aEntryName,
570 PRBool aDontPersist)
571{
572 NS_ENSURE_ARG_POINTER(aCategoryName);
573 NS_ENSURE_ARG_POINTER(aEntryName);
574
575 /*
576 Note: no errors are reported since failure to delete
577 probably won't hurt you, and returning errors seriously
578 inconveniences JS clients
579 */
580
581 RTSemFastMutexRequest(mLock);
582 CategoryNode* category = get_category(aCategoryName);
583 RTSemFastMutexRelease(mLock);
584
585 if (!category)
586 return NS_OK;
587
588 return category->DeleteLeaf(aEntryName,
589 aDontPersist);
590}
591
592NS_IMETHODIMP
593nsCategoryManager::DeleteCategory( const char *aCategoryName )
594{
595 NS_ENSURE_ARG_POINTER(aCategoryName);
596
597 // the categories are arena-allocated, so we don't
598 // actually delete them. We just remove all of the
599 // leaf nodes.
600
601 RTSemFastMutexRequest(mLock);
602 CategoryNode* category = get_category(aCategoryName);
603 RTSemFastMutexRelease(mLock);
604
605 if (category)
606 category->Clear();
607
608 return NS_OK;
609}
610
611NS_IMETHODIMP
612nsCategoryManager::EnumerateCategory( const char *aCategoryName,
613 nsISimpleEnumerator **_retval )
614{
615 NS_ENSURE_ARG_POINTER(aCategoryName);
616 NS_ENSURE_ARG_POINTER(_retval);
617
618 RTSemFastMutexRequest(mLock);
619 CategoryNode* category = get_category(aCategoryName);
620 RTSemFastMutexRelease(mLock);
621
622 if (!category) {
623 return NS_NewEmptyEnumerator(_retval);
624 }
625
626 return category->Enumerate(_retval);
627}
628
629NS_IMETHODIMP
630nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval)
631{
632 NS_ENSURE_ARG_POINTER(_retval);
633
634 RTSemFastMutexRequest(mLock);
635 CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable);
636 RTSemFastMutexRelease(mLock);
637
638 if (!enumObj)
639 return NS_ERROR_OUT_OF_MEMORY;
640
641 *_retval = enumObj;
642 NS_ADDREF(*_retval);
643 return NS_OK;
644}
645
646struct writecat_struct {
647 PRFileDesc* fd;
648 PRBool success;
649};
650
651PLDHashOperator PR_CALLBACK
652enumfunc_categories(const char* aKey, CategoryNode* aCategory, void* userArg)
653{
654 writecat_struct* args = NS_STATIC_CAST(writecat_struct*, userArg);
655
656 PLDHashOperator result = PL_DHASH_NEXT;
657
658 if (!aCategory->WritePersistentEntries(args->fd, aKey)) {
659 args->success = PR_FALSE;
660 result = PL_DHASH_STOP;
661 }
662
663 return result;
664}
665
666NS_METHOD
667nsCategoryManager::WriteCategoryManagerToRegistry(PRFileDesc* fd)
668{
669 writecat_struct args = {
670 fd,
671 PR_TRUE
672 };
673
674 RTSemFastMutexRequest(mLock);
675 mTable.EnumerateRead(enumfunc_categories, &args);
676 RTSemFastMutexRelease(mLock);
677
678 if (!args.success) {
679 return NS_ERROR_UNEXPECTED;
680 }
681
682 return NS_OK;
683}
684
685class nsCategoryManagerFactory : public nsIFactory
686 {
687 public:
688 nsCategoryManagerFactory() { }
689
690 NS_DECL_ISUPPORTS
691 NS_DECL_NSIFACTORY
692 };
693
694NS_IMPL_ISUPPORTS1(nsCategoryManagerFactory, nsIFactory)
695
696NS_IMETHODIMP
697nsCategoryManagerFactory::CreateInstance( nsISupports* aOuter, const nsIID& aIID, void** aResult )
698 {
699 NS_ENSURE_ARG_POINTER(aResult);
700
701 *aResult = 0;
702
703 nsresult status = NS_OK;
704 if ( aOuter )
705 status = NS_ERROR_NO_AGGREGATION;
706 else
707 {
708 nsCategoryManager* raw_category_manager = nsCategoryManager::Create();
709 nsCOMPtr<nsICategoryManager> new_category_manager = raw_category_manager;
710 if ( new_category_manager )
711 status = new_category_manager->QueryInterface(aIID, aResult);
712 else
713 status = NS_ERROR_OUT_OF_MEMORY;
714 }
715
716 return status;
717 }
718
719NS_IMETHODIMP
720nsCategoryManagerFactory::LockFactory( PRBool )
721 {
722 // Not implemented...
723 return NS_OK;
724 }
725
726nsresult
727NS_CategoryManagerGetFactory( nsIFactory** aFactory )
728 {
729 // assert(aFactory);
730
731 nsresult status;
732
733 *aFactory = 0;
734 nsIFactory* new_factory = NS_STATIC_CAST(nsIFactory*, new nsCategoryManagerFactory);
735 if (new_factory)
736 {
737 *aFactory = new_factory;
738 NS_ADDREF(*aFactory);
739 status = NS_OK;
740 }
741 else
742 status = NS_ERROR_OUT_OF_MEMORY;
743
744 return status;
745 }
746
747
748
749/*
750 * CreateServicesFromCategory()
751 *
752 * Given a category, this convenience functions enumerates the category and
753 * creates a service of every CID or ContractID registered under the category.
754 * If observerTopic is non null and the service implements nsIObserver,
755 * this will attempt to notify the observer with the origin, observerTopic string
756 * as parameter.
757 */
758NS_COM nsresult
759NS_CreateServicesFromCategory(const char *category,
760 nsISupports *origin,
761 const char *observerTopic)
762{
763 nsresult rv = NS_OK;
764
765 int nFailed = 0;
766 nsCOMPtr<nsICategoryManager> categoryManager =
767 do_GetService("@mozilla.org/categorymanager;1", &rv);
768 if (!categoryManager) return rv;
769
770 nsCOMPtr<nsISimpleEnumerator> enumerator;
771 rv = categoryManager->EnumerateCategory(category,
772 getter_AddRefs(enumerator));
773 if (NS_FAILED(rv)) return rv;
774
775 nsCOMPtr<nsISupports> entry;
776 while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
777 // From here on just skip any error we get.
778 nsCOMPtr<nsISupportsCString> catEntry = do_QueryInterface(entry, &rv);
779 if (NS_FAILED(rv)) {
780 nFailed++;
781 continue;
782 }
783 nsCAutoString entryString;
784 rv = catEntry->GetData(entryString);
785 if (NS_FAILED(rv)) {
786 nFailed++;
787 continue;
788 }
789 nsXPIDLCString contractID;
790 rv = categoryManager->GetCategoryEntry(category,entryString.get(), getter_Copies(contractID));
791 if (NS_FAILED(rv)) {
792 nFailed++;
793 continue;
794 }
795
796 nsCOMPtr<nsISupports> instance = do_GetService(contractID, &rv);
797 if (NS_FAILED(rv)) {
798 nFailed++;
799 continue;
800 }
801
802 if (observerTopic) {
803 // try an observer, if it implements it.
804 nsCOMPtr<nsIObserver> observer = do_QueryInterface(instance, &rv);
805 if (NS_SUCCEEDED(rv) && observer)
806 observer->Observe(origin, observerTopic, EmptyString().get());
807 }
808 }
809 return (nFailed ? NS_ERROR_FAILURE : NS_OK);
810}
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