VirtualBox

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

Last change on this file since 102197 was 102197, checked in by vboxsync, 18 months ago

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

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