LCOV - app.info - xpcom/components/nsCategoryManager.cpp

LCOV - code coverage report
| Current view: | directory - xpcom/components - nsCategoryManager.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 287 | 208 | 72.5 %
| Date: | 2012-04-21 | Functions: | 53 | 44 | 83.0 %

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

Generated by: LCOV version 1.7