VirtualBox

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

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

libs/xpcom: Remove public PR_Lock and PR_CondVar APIs as they are not used anywhere outside of NSPR, bugref:10545 [build fix]

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