VirtualBox

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

Last change on this file was 109066, checked in by vboxsync, 4 weeks ago

libs/xpcom: More logging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.3 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 "nsCOMPtr.h"
46#include "nsTHashtable.h"
47#include "nsClassHashtable.h"
48#include "nsIFactory.h"
49#include "nsIStringEnumerator.h"
50#include "nsSupportsPrimitives.h"
51#include "nsIServiceManagerUtils.h"
52#include "nsIObserver.h"
53#include "nsReadableUtils.h"
54#include "nsCRT.h"
55#include "nsEnumeratorUtils.h"
56
57#include <iprt/assert.h>
58#include <iprt/errcore.h>
59#include <VBox/log.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 LogFlowFunc(("aCategoryName=%s aEntryName=%s aValue=%s aPresists=%d aReplace=%d\n",
540 aCategoryName, aEntryName, aValue, aPersist, aReplace));
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 LogFlowFunc(("aCategoryName=%s aEntryName=%s aDontPresists=%d\n", aCategoryName, aEntryName, aDontPersist));
575
576 /*
577 Note: no errors are reported since failure to delete
578 probably won't hurt you, and returning errors seriously
579 inconveniences JS clients
580 */
581
582 RTSemFastMutexRequest(mLock);
583 CategoryNode* category = get_category(aCategoryName);
584 RTSemFastMutexRelease(mLock);
585
586 if (!category)
587 return NS_OK;
588
589 return category->DeleteLeaf(aEntryName,
590 aDontPersist);
591}
592
593NS_IMETHODIMP
594nsCategoryManager::DeleteCategory( const char *aCategoryName )
595{
596 NS_ENSURE_ARG_POINTER(aCategoryName);
597 LogFlowFunc(("aCategoryName=%s\n", aCategoryName));
598
599 // the categories are arena-allocated, so we don't
600 // actually delete them. We just remove all of the
601 // leaf nodes.
602
603 RTSemFastMutexRequest(mLock);
604 CategoryNode* category = get_category(aCategoryName);
605 RTSemFastMutexRelease(mLock);
606
607 if (category)
608 category->Clear();
609
610 return NS_OK;
611}
612
613NS_IMETHODIMP
614nsCategoryManager::EnumerateCategory( const char *aCategoryName,
615 nsISimpleEnumerator **_retval )
616{
617 NS_ENSURE_ARG_POINTER(aCategoryName);
618 NS_ENSURE_ARG_POINTER(_retval);
619
620 RTSemFastMutexRequest(mLock);
621 CategoryNode* category = get_category(aCategoryName);
622 RTSemFastMutexRelease(mLock);
623
624 if (!category) {
625 return NS_NewEmptyEnumerator(_retval);
626 }
627
628 return category->Enumerate(_retval);
629}
630
631NS_IMETHODIMP
632nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval)
633{
634 NS_ENSURE_ARG_POINTER(_retval);
635
636 RTSemFastMutexRequest(mLock);
637 CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable);
638 RTSemFastMutexRelease(mLock);
639
640 if (!enumObj)
641 return NS_ERROR_OUT_OF_MEMORY;
642
643 *_retval = enumObj;
644 NS_ADDREF(*_retval);
645 return NS_OK;
646}
647
648struct writecat_struct {
649 PRTSTREAM fd;
650 PRBool success;
651};
652
653PLDHashOperator PR_CALLBACK
654enumfunc_categories(const char* aKey, CategoryNode* aCategory, void* userArg)
655{
656 writecat_struct* args = NS_STATIC_CAST(writecat_struct*, userArg);
657
658 PLDHashOperator result = PL_DHASH_NEXT;
659
660 if (!aCategory->WritePersistentEntries(args->fd, aKey)) {
661 args->success = PR_FALSE;
662 result = PL_DHASH_STOP;
663 }
664
665 return result;
666}
667
668NS_METHOD
669nsCategoryManager::WriteCategoryManagerToRegistry(PRTSTREAM fd)
670{
671 writecat_struct args = {
672 fd,
673 PR_TRUE
674 };
675
676 RTSemFastMutexRequest(mLock);
677 mTable.EnumerateRead(enumfunc_categories, &args);
678 RTSemFastMutexRelease(mLock);
679
680 if (!args.success) {
681 return NS_ERROR_UNEXPECTED;
682 }
683
684 return NS_OK;
685}
686
687class nsCategoryManagerFactory : public nsIFactory
688 {
689 public:
690 nsCategoryManagerFactory() { }
691
692 NS_DECL_ISUPPORTS
693 NS_DECL_NSIFACTORY
694 };
695
696NS_IMPL_ISUPPORTS1(nsCategoryManagerFactory, nsIFactory)
697
698NS_IMETHODIMP
699nsCategoryManagerFactory::CreateInstance( nsISupports* aOuter, const nsIID& aIID, void** aResult )
700 {
701 NS_ENSURE_ARG_POINTER(aResult);
702
703 *aResult = 0;
704
705 nsresult status = NS_OK;
706 if ( aOuter )
707 status = NS_ERROR_NO_AGGREGATION;
708 else
709 {
710 nsCategoryManager* raw_category_manager = nsCategoryManager::Create();
711 nsCOMPtr<nsICategoryManager> new_category_manager = raw_category_manager;
712 if ( new_category_manager )
713 status = new_category_manager->QueryInterface(aIID, aResult);
714 else
715 status = NS_ERROR_OUT_OF_MEMORY;
716 }
717
718 return status;
719 }
720
721NS_IMETHODIMP
722nsCategoryManagerFactory::LockFactory( PRBool )
723 {
724 // Not implemented...
725 return NS_OK;
726 }
727
728nsresult
729NS_CategoryManagerGetFactory( nsIFactory** aFactory )
730 {
731 // assert(aFactory);
732
733 nsresult status;
734
735 *aFactory = 0;
736 nsIFactory* new_factory = NS_STATIC_CAST(nsIFactory*, new nsCategoryManagerFactory);
737 if (new_factory)
738 {
739 *aFactory = new_factory;
740 NS_ADDREF(*aFactory);
741 status = NS_OK;
742 }
743 else
744 status = NS_ERROR_OUT_OF_MEMORY;
745
746 return status;
747 }
748
749
750
751/*
752 * CreateServicesFromCategory()
753 *
754 * Given a category, this convenience functions enumerates the category and
755 * creates a service of every CID or ContractID registered under the category.
756 * If observerTopic is non null and the service implements nsIObserver,
757 * this will attempt to notify the observer with the origin, observerTopic string
758 * as parameter.
759 */
760NS_COM nsresult
761NS_CreateServicesFromCategory(const char *category,
762 nsISupports *origin,
763 const char *observerTopic)
764{
765 LogFlowFunc(("category=%s origin=%p observerTopic=%s\n", category, origin, observerTopic));
766 nsresult rv = NS_OK;
767
768 int nFailed = 0;
769 nsCOMPtr<nsICategoryManager> categoryManager =
770 do_GetService("@mozilla.org/categorymanager;1", &rv);
771 if (!categoryManager) return rv;
772
773 nsCOMPtr<nsISimpleEnumerator> enumerator;
774 rv = categoryManager->EnumerateCategory(category,
775 getter_AddRefs(enumerator));
776 if (NS_FAILED(rv)) return rv;
777
778 nsCOMPtr<nsISupports> entry;
779 while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) {
780 // From here on just skip any error we get.
781 nsCOMPtr<nsISupportsCString> catEntry = do_QueryInterface(entry, &rv);
782 if (NS_FAILED(rv)) {
783 nFailed++;
784 continue;
785 }
786 nsCAutoString entryString;
787 rv = catEntry->GetData(entryString);
788 if (NS_FAILED(rv)) {
789 nFailed++;
790 continue;
791 }
792 nsXPIDLCString contractID;
793 rv = categoryManager->GetCategoryEntry(category,entryString.get(), getter_Copies(contractID));
794 if (NS_FAILED(rv)) {
795 nFailed++;
796 continue;
797 }
798 LogFlowFunc(("Entry: entryString=%s contractID=%s\n", entryString.get(), contractID.get()));
799
800 nsCOMPtr<nsISupports> instance = do_GetService(contractID, &rv);
801 if (NS_FAILED(rv)) {
802 nFailed++;
803 continue;
804 }
805
806 if (observerTopic) {
807 // try an observer, if it implements it.
808 nsCOMPtr<nsIObserver> observer = do_QueryInterface(instance, &rv);
809 if (NS_SUCCEEDED(rv) && observer)
810 observer->Observe(origin, observerTopic, EmptyString().get());
811 }
812 }
813 return (nFailed ? NS_ERROR_FAILURE : NS_OK);
814}
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