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-06-02 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            5919 :   BaseStringEnumerator()
     106                 :     : mArray(nsnull),
     107                 :       mCount(0),
     108                 :       mSimpleCurItem(0),
     109            5919 :       mStringCurItem(0) { }
     110                 : 
     111                 :   // A virtual destructor is needed here because subclasses of
     112                 :   // BaseStringEnumerator do not implement their own Release() method.
     113                 : 
     114            5919 :   virtual ~BaseStringEnumerator()
     115            5919 :   {
     116            5919 :     if (mArray)
     117            5919 :       delete[] mArray;
     118           11838 :   }
     119                 : 
     120                 :   void Sort();
     121                 : 
     122                 :   const char** mArray;
     123                 :   PRUint32 mCount;
     124                 :   PRUint32 mSimpleCurItem;
     125                 :   PRUint32 mStringCurItem;
     126                 : };
     127                 : 
     128           44453 : NS_IMPL_ISUPPORTS2(BaseStringEnumerator, nsISimpleEnumerator, nsIUTF8StringEnumerator)
     129                 : 
     130                 : NS_IMETHODIMP
     131            5606 : BaseStringEnumerator::HasMoreElements(bool *_retval)
     132                 : {
     133            5606 :   *_retval = (mSimpleCurItem < mCount);
     134                 : 
     135            5606 :   return NS_OK;
     136                 : }
     137                 : 
     138                 : NS_IMETHODIMP
     139            9026 : BaseStringEnumerator::GetNext(nsISupports **_retval)
     140                 : {
     141            9026 :   if (mSimpleCurItem >= mCount)
     142            1915 :     return NS_ERROR_FAILURE;
     143                 : 
     144                 :   nsSupportsDependentCString* str =
     145           14222 :     new nsSupportsDependentCString(mArray[mSimpleCurItem++]);
     146            7111 :   if (!str)
     147               0 :     return NS_ERROR_OUT_OF_MEMORY;
     148                 : 
     149            7111 :   *_retval = str;
     150            7111 :   NS_ADDREF(*_retval);
     151            7111 :   return NS_OK;
     152                 : }
     153                 : 
     154                 : NS_IMETHODIMP
     155            4257 : BaseStringEnumerator::HasMore(bool *_retval)
     156                 : {
     157            4257 :   *_retval = (mStringCurItem < mCount);
     158                 : 
     159            4257 :   return NS_OK;
     160                 : }
     161                 : 
     162                 : NS_IMETHODIMP
     163            2838 : BaseStringEnumerator::GetNext(nsACString& _retval)
     164                 : {
     165            2838 :   if (mStringCurItem >= mCount)
     166               0 :     return NS_ERROR_FAILURE;
     167                 : 
     168            2838 :   _retval = nsDependentCString(mArray[mStringCurItem++]);
     169            2838 :   return NS_OK;
     170                 : }
     171                 : 
     172                 : int
     173            7400 : BaseStringEnumerator::SortCallback(const void *e1, const void *e2,
     174                 :                                    void * /*unused*/)
     175                 : {
     176            7400 :   char const *const *s1 = reinterpret_cast<char const *const *>(e1);
     177            7400 :   char const *const *s2 = reinterpret_cast<char const *const *>(e2);
     178                 : 
     179            7400 :   return strcmp(*s1, *s2);
     180                 : }
     181                 : 
     182                 : void
     183            5919 : BaseStringEnumerator::Sort()
     184                 : {
     185            5919 :   NS_QuickSort(mArray, mCount, sizeof(mArray[0]), SortCallback, nsnull);
     186            5919 : }
     187                 : 
     188                 : //
     189                 : // EntryEnumerator is the wrapper that allows nsICategoryManager::EnumerateCategory
     190                 : //
     191                 : class EntryEnumerator
     192                 :   : public BaseStringEnumerator
     193           29595 : {
     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            9953 : EntryEnumerator::enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg)
     205                 : {
     206            9953 :   EntryEnumerator* mythis = static_cast<EntryEnumerator*>(userArg);
     207            9953 :   if (aLeaf->value)
     208            9953 :     mythis->mArray[mythis->mCount++] = aLeaf->GetKey();
     209                 : 
     210            9953 :   return PL_DHASH_NEXT;
     211                 : }
     212                 : 
     213                 : EntryEnumerator*
     214            5919 : EntryEnumerator::Create(nsTHashtable<CategoryLeaf>& aTable)
     215                 : {
     216            5919 :   EntryEnumerator* enumObj = new EntryEnumerator();
     217            5919 :   if (!enumObj)
     218               0 :     return nsnull;
     219                 : 
     220           11838 :   enumObj->mArray = new char const* [aTable.Count()];
     221            5919 :   if (!enumObj->mArray) {
     222               0 :     delete enumObj;
     223               0 :     return nsnull;
     224                 :   }
     225                 : 
     226            5919 :   aTable.EnumerateEntries(enumfunc_createenumerator, enumObj);
     227                 : 
     228            5919 :   enumObj->Sort();
     229                 : 
     230            5919 :   return enumObj;
     231                 : }
     232                 : 
     233                 : 
     234                 : //
     235                 : // CategoryNode implementations
     236                 : //
     237                 : 
     238                 : CategoryNode*
     239           48253 : CategoryNode::Create(PLArenaPool* aArena)
     240                 : {
     241           48253 :   CategoryNode* node = new(aArena) CategoryNode();
     242           48253 :   if (!node)
     243               0 :     return nsnull;
     244                 : 
     245           48253 :   if (!node->mTable.Init()) {
     246               0 :     delete node;
     247               0 :     return nsnull;
     248                 :   }
     249                 : 
     250           48253 :   return node;
     251                 : }
     252                 : 
     253           48253 : CategoryNode::~CategoryNode()
     254                 : {
     255           48253 : }
     256                 : 
     257                 : void*
     258           48253 : CategoryNode::operator new(size_t aSize, PLArenaPool* aArena)
     259                 : {
     260                 :   void* p;
     261           48253 :   PL_ARENA_ALLOCATE(p, aArena, aSize);
     262           48253 :   return p;
     263                 : }
     264                 : 
     265                 : NS_METHOD
     266           10332 : CategoryNode::GetLeaf(const char* aEntryName,
     267                 :                       char** _retval)
     268                 : {
     269           20664 :   MutexAutoLock lock(mLock);
     270           10332 :   nsresult rv = NS_ERROR_NOT_AVAILABLE;
     271                 :   CategoryLeaf* ent =
     272           10332 :     mTable.GetEntry(aEntryName);
     273                 : 
     274           10332 :   if (ent && ent->value) {
     275            9718 :     *_retval = NS_strdup(ent->value);
     276            9718 :     if (*_retval)
     277            9718 :       rv = NS_OK;
     278                 :   }
     279                 : 
     280           10332 :   return rv;
     281                 : }
     282                 : 
     283                 : NS_METHOD
     284          418804 : CategoryNode::AddLeaf(const char* aEntryName,
     285                 :                       const char* aValue,
     286                 :                       bool aReplace,
     287                 :                       char** _retval,
     288                 :                       PLArenaPool* aArena)
     289                 : {
     290          418804 :   if (_retval)
     291          418804 :     *_retval = NULL;
     292                 : 
     293          837608 :   MutexAutoLock lock(mLock);
     294                 :   CategoryLeaf* leaf = 
     295          418804 :     mTable.GetEntry(aEntryName);
     296                 : 
     297          418804 :   if (!leaf) {
     298          418803 :     const char* arenaEntryName = ArenaStrdup(aEntryName, aArena);
     299          418803 :     if (!arenaEntryName)
     300               0 :       return NS_ERROR_OUT_OF_MEMORY;
     301                 : 
     302          418803 :     leaf = mTable.PutEntry(arenaEntryName);
     303          418803 :     if (!leaf)
     304               0 :       return NS_ERROR_OUT_OF_MEMORY;
     305                 :   }
     306                 : 
     307          418804 :   if (leaf->value && !aReplace)
     308               0 :     return NS_ERROR_INVALID_ARG;
     309                 : 
     310          418804 :   const char* arenaValue = ArenaStrdup(aValue, aArena);
     311          418804 :   if (!arenaValue)
     312               0 :     return NS_ERROR_OUT_OF_MEMORY;
     313                 : 
     314          418804 :   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          418804 :   leaf->value = arenaValue;
     321          418804 :   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            5919 : CategoryNode::Enumerate(nsISimpleEnumerator **_retval)
     337                 : {
     338            5919 :   NS_ENSURE_ARG_POINTER(_retval);
     339                 : 
     340           11838 :   MutexAutoLock lock(mLock);
     341            5919 :   EntryEnumerator* enumObj = EntryEnumerator::Create(mTable);
     342                 : 
     343            5919 :   if (!enumObj)
     344               0 :     return NS_ERROR_OUT_OF_MEMORY;
     345                 : 
     346            5919 :   *_retval = enumObj;
     347            5919 :   NS_ADDREF(*_retval);
     348            5919 :   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           37429 : NS_IMPL_QUERY_INTERFACE1(nsCategoryManager, nsICategoryManager)
     432                 : 
     433                 : NS_IMETHODIMP_(nsrefcnt)
     434           44856 : nsCategoryManager::AddRef()
     435                 : {
     436           44856 :   return 2;
     437                 : }
     438                 : 
     439                 : NS_IMETHODIMP_(nsrefcnt)
     440           44856 : nsCategoryManager::Release()
     441                 : {
     442           44856 :   return 1;
     443                 : }
     444                 : 
     445                 : nsCategoryManager* nsCategoryManager::gCategoryManager;
     446                 : 
     447                 : /* static */ nsCategoryManager*
     448          422872 : nsCategoryManager::GetSingleton()
     449                 : {
     450          422872 :   if (!gCategoryManager)
     451            1419 :     gCategoryManager = new nsCategoryManager();
     452          422872 :   return gCategoryManager;
     453                 : }
     454                 : 
     455                 : /* static */ void
     456            1419 : nsCategoryManager::Destroy()
     457                 : {
     458            1419 :   delete gCategoryManager;
     459            1419 : }
     460                 : 
     461                 : nsresult
     462            1419 : nsCategoryManager::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
     463                 : {
     464            1419 :   if (aOuter)
     465               0 :     return NS_ERROR_NO_AGGREGATION;
     466                 : 
     467            1419 :   return GetSingleton()->QueryInterface(aIID, aResult);
     468                 : }
     469                 : 
     470            1419 : nsCategoryManager::nsCategoryManager()
     471                 :   : mLock("nsCategoryManager")
     472            1419 :   , mSuppressNotifications(false)
     473                 : {
     474            1419 :   PL_INIT_ARENA_POOL(&mArena, "CategoryManagerArena",
     475            1419 :                      NS_CATEGORYMANAGER_ARENA_SIZE);
     476                 : 
     477            1419 :   mTable.Init();
     478            1419 : }
     479                 : 
     480            2838 : 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            1419 :   mTable.Clear();
     486                 : 
     487            1419 :   PL_FinishArenaPool(&mArena);
     488            1419 : }
     489                 : 
     490                 : inline CategoryNode*
     491          446672 : nsCategoryManager::get_category(const char* aName) {
     492                 :   CategoryNode* node;
     493          446672 :   if (!mTable.Get(aName, &node)) {
     494           59850 :     return nsnull;
     495                 :   }
     496          386822 :   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          418825 : nsCategoryManager::NotifyObservers( const char *aTopic,
     536                 :                                     const char *aCategoryName,
     537                 :                                     const char *aEntryName )
     538                 : {
     539          418825 :   if (mSuppressNotifications)
     540          418605 :     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           10476 : nsCategoryManager::GetCategoryEntry( const char *aCategoryName,
     564                 :                                      const char *aEntryName,
     565                 :                                      char **_retval )
     566                 : {
     567           10476 :   NS_ENSURE_ARG_POINTER(aCategoryName);
     568           10476 :   NS_ENSURE_ARG_POINTER(aEntryName);
     569           10476 :   NS_ENSURE_ARG_POINTER(_retval);
     570                 : 
     571           10476 :   nsresult status = NS_ERROR_NOT_AVAILABLE;
     572                 : 
     573                 :   CategoryNode* category;
     574                 :   {
     575           20952 :     MutexAutoLock lock(mLock);
     576           10476 :     category = get_category(aCategoryName);
     577                 :   }
     578                 : 
     579           10476 :   if (category) {
     580           10332 :     status = category->GetLeaf(aEntryName, _retval);
     581                 :   }
     582                 : 
     583           10476 :   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          418804 : nsCategoryManager::AddCategoryEntry(const char *aCategoryName,
     605                 :                                     const char *aEntryName,
     606                 :                                     const char *aValue,
     607                 :                                     bool aReplace,
     608                 :                                     char** aOldValue)
     609                 : {
     610          418804 :   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          837608 :     MutexAutoLock lock(mLock);
     618          418804 :     category = get_category(aCategoryName);
     619                 : 
     620          418804 :     if (!category) {
     621                 :       // That category doesn't exist yet; let's make it.
     622           48253 :       category = CategoryNode::Create(&mArena);
     623                 :         
     624           48253 :       char* categoryName = ArenaStrdup(aCategoryName, &mArena);
     625           48253 :       mTable.Put(categoryName, category);
     626                 :     }
     627                 :   }
     628                 : 
     629          418804 :   if (!category)
     630               0 :     return;
     631                 : 
     632                 :   // We will need the return value of AddLeaf even if the called doesn't want it
     633          418804 :   char *oldEntry = nsnull;
     634                 : 
     635                 :   nsresult rv = category->AddLeaf(aEntryName,
     636                 :                                   aValue,
     637                 :                                   aReplace,
     638                 :                                   &oldEntry,
     639          418804 :                                   &mArena);
     640                 : 
     641          418804 :   if (NS_SUCCEEDED(rv)) {
     642          418804 :     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          418804 :                     aCategoryName, aEntryName);
     648                 : 
     649          418804 :     if (aOldValue)
     650              15 :       *aOldValue = oldEntry;
     651                 :     else
     652          418789 :       NS_Free(oldEntry);
     653                 :   }
     654                 : }
     655                 : 
     656                 : NS_IMETHODIMP
     657            6726 : nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName,
     658                 :                                         const char *aEntryName,
     659                 :                                         bool aDontPersist)
     660                 : {
     661            6726 :   NS_ENSURE_ARG_POINTER(aCategoryName);
     662            6726 :   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           13452 :     MutexAutoLock lock(mLock);
     673            6726 :     category = get_category(aCategoryName);
     674                 :   }
     675                 : 
     676            6726 :   if (category) {
     677              20 :     category->DeleteLeaf(aEntryName);
     678                 : 
     679                 :     NotifyObservers(NS_XPCOM_CATEGORY_ENTRY_REMOVED_OBSERVER_ID,
     680              20 :                     aCategoryName, aEntryName);
     681                 :   }
     682                 : 
     683            6726 :   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           10666 : nsCategoryManager::EnumerateCategory( const char *aCategoryName,
     712                 :                                       nsISimpleEnumerator **_retval )
     713                 : {
     714           10666 :   NS_ENSURE_ARG_POINTER(aCategoryName);
     715           10666 :   NS_ENSURE_ARG_POINTER(_retval);
     716                 : 
     717                 :   CategoryNode* category;
     718                 :   {
     719           21332 :     MutexAutoLock lock(mLock);
     720           10666 :     category = get_category(aCategoryName);
     721                 :   }
     722                 :   
     723           10666 :   if (!category) {
     724            4747 :     return NS_NewEmptyEnumerator(_retval);
     725                 :   }
     726                 : 
     727            5919 :   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            2838 : nsCategoryManager::SuppressNotifications(bool aSuppress)
     753                 : {
     754            2838 :   mSuppressNotifications = aSuppress;
     755            2838 :   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            3519 : 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            7038 :     do_GetService("@mozilla.org/categorymanager;1");
     779            3519 :   if (!categoryManager)
     780                 :     return;
     781                 : 
     782            7038 :   nsCOMPtr<nsISimpleEnumerator> enumerator;
     783            3519 :   rv = categoryManager->EnumerateCategory(category, 
     784            3519 :                                           getter_AddRefs(enumerator));
     785            3519 :   if (NS_FAILED(rv))
     786                 :     return;
     787                 : 
     788                 :   nsCOMPtr<nsIUTF8StringEnumerator> senumerator =
     789            7038 :     do_QueryInterface(enumerator);
     790            3519 :   if (!senumerator) {
     791               0 :     NS_WARNING("Category enumerator doesn't support nsIUTF8StringEnumerator.");
     792                 :     return;
     793                 :   }
     794                 : 
     795                 :   bool hasMore;
     796            7038 :   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