LCOV - code coverage report
Current view: top level - modules/libpref - nsPrefBranch.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 281 506 55.5 %
Date: 2017-07-14 16:53:18 Functions: 45 68 66.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/ContentChild.h"
       8             : #include "nsXULAppAPI.h"
       9             : 
      10             : #include "nsPrefBranch.h"
      11             : #include "nsILocalFile.h" // nsILocalFile used for backwards compatibility
      12             : #include "nsIObserverService.h"
      13             : #include "nsXPCOM.h"
      14             : #include "nsISupportsPrimitives.h"
      15             : #include "nsIDirectoryService.h"
      16             : #include "nsString.h"
      17             : #include "nsReadableUtils.h"
      18             : #include "nsXPIDLString.h"
      19             : #include "nsPrintfCString.h"
      20             : #include "nsIStringBundle.h"
      21             : #include "prefapi.h"
      22             : #include "PLDHashTable.h"
      23             : 
      24             : #include "nsCRT.h"
      25             : #include "mozilla/Services.h"
      26             : 
      27             : #include "prefapi_private_data.h"
      28             : 
      29             : #ifdef MOZ_CRASHREPORTER
      30             : #include "nsICrashReporter.h"
      31             : #endif
      32             : 
      33             : #include "nsIConsoleService.h"
      34             : 
      35             : #ifdef DEBUG
      36             : #define ENSURE_MAIN_PROCESS(message, pref) do {                                \
      37             :   if (GetContentChild()) {                                                     \
      38             :     nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref);   \
      39             :     NS_ERROR(msg.get());                                                       \
      40             :     return NS_ERROR_NOT_AVAILABLE;                                             \
      41             :   }                                                                            \
      42             : } while (0);
      43             : #else
      44             : #define ENSURE_MAIN_PROCESS(message, pref)                                     \
      45             :   if (GetContentChild()) {                                                     \
      46             :     return NS_ERROR_NOT_AVAILABLE;                                             \
      47             :   }
      48             : #endif
      49             : 
      50             : using mozilla::dom::ContentChild;
      51             : 
      52             : static ContentChild*
      53          42 : GetContentChild()
      54             : {
      55          42 :   if (XRE_IsContentProcess()) {
      56           0 :     ContentChild* cpc = ContentChild::GetSingleton();
      57           0 :     if (!cpc) {
      58           0 :       MOZ_CRASH("Content Protocol is NULL!  We're going to crash!");
      59             :     }
      60           0 :     return cpc;
      61             :   }
      62          42 :   return nullptr;
      63             : }
      64             : 
      65             : /*
      66             :  * Constructor/Destructor
      67             :  */
      68             : 
      69          41 : nsPrefBranch::nsPrefBranch(const char *aPrefRoot, bool aDefaultBranch)
      70             :   : mPrefRoot(aPrefRoot)
      71             :   , mIsDefault(aDefaultBranch)
      72             :   , mFreeingObserverList(false)
      73          41 :   , mObservers()
      74             : {
      75             :   nsCOMPtr<nsIObserverService> observerService =
      76          82 :     mozilla::services::GetObserverService();
      77          41 :   if (observerService) {
      78          41 :     ++mRefCnt;    // Our refcnt must be > 0 when we call this, or we'll get deleted!
      79             :     // add weak so we don't have to clean up at shutdown
      80          41 :     observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
      81          41 :     --mRefCnt;
      82             :   }
      83          41 : }
      84             : 
      85           6 : nsPrefBranch::~nsPrefBranch()
      86             : {
      87           2 :   freeObserverList();
      88             : 
      89             :   nsCOMPtr<nsIObserverService> observerService =
      90           4 :     mozilla::services::GetObserverService();
      91           2 :   if (observerService)
      92           2 :     observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
      93           6 : }
      94             : 
      95             : 
      96             : /*
      97             :  * nsISupports Implementation
      98             :  */
      99             : 
     100         230 : NS_IMPL_ADDREF(nsPrefBranch)
     101         148 : NS_IMPL_RELEASE(nsPrefBranch)
     102             : 
     103         365 : NS_INTERFACE_MAP_BEGIN(nsPrefBranch)
     104         365 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefBranch)
     105         323 :   NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
     106         269 :   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranch2, !mIsDefault)
     107         269 :   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranchInternal, !mIsDefault)
     108         269 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
     109         267 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     110         224 : NS_INTERFACE_MAP_END
     111             : 
     112             : 
     113             : /*
     114             :  * nsIPrefBranch Implementation
     115             :  */
     116             : 
     117           0 : NS_IMETHODIMP nsPrefBranch::GetRoot(char **aRoot)
     118             : {
     119           0 :   NS_ENSURE_ARG_POINTER(aRoot);
     120           0 :   *aRoot = ToNewCString(mPrefRoot);
     121           0 :   return NS_OK;
     122             : }
     123             : 
     124         710 : NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, int32_t *_retval)
     125             : {
     126         710 :   NS_ENSURE_ARG(aPrefName);
     127        1420 :   const PrefName& pref = getPrefName(aPrefName);
     128         710 :   switch (PREF_GetPrefType(pref.get())) {
     129             :     case PrefType::String:
     130          42 :       *_retval = PREF_STRING;
     131          42 :       break;
     132             :     case PrefType::Int:
     133         106 :       *_retval = PREF_INT;
     134         106 :       break;
     135             :     case PrefType::Bool:
     136         295 :       *_retval = PREF_BOOL;
     137         295 :         break;
     138             :     case PrefType::Invalid:
     139             :     default:
     140         267 :       *_retval = PREF_INVALID;
     141         267 :       break;
     142             :   }
     143         710 :   return NS_OK;
     144             : }
     145             : 
     146         304 : NS_IMETHODIMP nsPrefBranch::GetBoolPrefWithDefault(const char *aPrefName,
     147             :                                                    bool aDefaultValue,
     148             :                                                    uint8_t _argc, bool *_retval)
     149             : {
     150         304 :   nsresult rv = GetBoolPref(aPrefName, _retval);
     151             : 
     152         304 :   if (NS_FAILED(rv) && _argc == 1) {
     153          16 :     *_retval = aDefaultValue;
     154          16 :     return NS_OK;
     155             :   }
     156             : 
     157         288 :   return rv;
     158             : }
     159             : 
     160         432 : NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, bool *_retval)
     161             : {
     162         432 :   NS_ENSURE_ARG(aPrefName);
     163         864 :   const PrefName& pref = getPrefName(aPrefName);
     164         432 :   return PREF_GetBoolPref(pref.get(), _retval, mIsDefault);
     165             : }
     166             : 
     167          15 : NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, bool aValue)
     168             : {
     169          15 :   ENSURE_MAIN_PROCESS("Cannot SetBoolPref from content process:", aPrefName);
     170          15 :   NS_ENSURE_ARG(aPrefName);
     171          30 :   const PrefName& pref = getPrefName(aPrefName);
     172          15 :   return PREF_SetBoolPref(pref.get(), aValue, mIsDefault);
     173             : }
     174             : 
     175           0 : NS_IMETHODIMP nsPrefBranch::GetFloatPrefWithDefault(const char *aPrefName,
     176             :                                                     float aDefaultValue,
     177             :                                                     uint8_t _argc, float *_retval)
     178             : {
     179           0 :   nsresult rv = GetFloatPref(aPrefName, _retval);
     180             : 
     181           0 :   if (NS_FAILED(rv) && _argc == 1) {
     182           0 :     *_retval = aDefaultValue;
     183           0 :     return NS_OK;
     184             :   }
     185             : 
     186           0 :   return rv;
     187             : }
     188             : 
     189           2 : NS_IMETHODIMP nsPrefBranch::GetFloatPref(const char *aPrefName, float *_retval)
     190             : {
     191           2 :   NS_ENSURE_ARG(aPrefName);
     192           4 :   nsAutoCString stringVal;
     193           2 :   nsresult rv = GetCharPref(aPrefName, getter_Copies(stringVal));
     194           2 :   if (NS_SUCCEEDED(rv)) {
     195           2 :     *_retval = stringVal.ToFloat(&rv);
     196             :   }
     197             : 
     198           2 :   return rv;
     199             : }
     200             : 
     201          59 : NS_IMETHODIMP nsPrefBranch::GetCharPrefWithDefault(const char *aPrefName,
     202             :                                                    const char *aDefaultValue,
     203             :                                                    uint8_t _argc, char **_retval)
     204             : {
     205          59 :   nsresult rv = GetCharPref(aPrefName, _retval);
     206             : 
     207          59 :   if (NS_FAILED(rv) && _argc == 1) {
     208           1 :     NS_ENSURE_ARG(aDefaultValue);
     209           1 :     *_retval = NS_strdup(aDefaultValue);
     210           1 :     return NS_OK;
     211             :   }
     212             : 
     213          58 :   return rv;
     214             : }
     215             : 
     216         145 : NS_IMETHODIMP nsPrefBranch::GetCharPref(const char *aPrefName, char **_retval)
     217             : {
     218         145 :   NS_ENSURE_ARG(aPrefName);
     219         290 :   const PrefName& pref = getPrefName(aPrefName);
     220         145 :   return PREF_CopyCharPref(pref.get(), _retval, mIsDefault);
     221             : }
     222             : 
     223           8 : NS_IMETHODIMP nsPrefBranch::SetCharPref(const char *aPrefName, const char *aValue)
     224             : {
     225           8 :   nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
     226           8 :   if (NS_FAILED(rv)) {
     227           0 :     return rv;
     228             :   }
     229           8 :   return SetCharPrefInternal(aPrefName, aValue);
     230             : }
     231             : 
     232           9 : nsresult nsPrefBranch::SetCharPrefInternal(const char *aPrefName, const char *aValue)
     233             : 
     234             : {
     235           9 :   ENSURE_MAIN_PROCESS("Cannot SetCharPref from content process:", aPrefName);
     236           9 :   NS_ENSURE_ARG(aPrefName);
     237           9 :   NS_ENSURE_ARG(aValue);
     238          18 :   const PrefName& pref = getPrefName(aPrefName);
     239           9 :   return PREF_SetCharPref(pref.get(), aValue, mIsDefault);
     240             : }
     241             : 
     242          15 : NS_IMETHODIMP nsPrefBranch::GetStringPref(const char *aPrefName,
     243             :                                           const nsACString& aDefaultValue,
     244             :                                           uint8_t _argc,
     245             :                                           nsACString& _retval)
     246             : {
     247          30 :   nsXPIDLCString utf8String;
     248          15 :   nsresult rv = GetCharPref(aPrefName, getter_Copies(utf8String));
     249          15 :   if (NS_SUCCEEDED(rv)) {
     250           7 :     _retval = utf8String;
     251           7 :     return rv;
     252             :   }
     253             : 
     254           8 :   if (_argc == 1) {
     255           4 :     _retval = aDefaultValue;
     256           4 :     return NS_OK;
     257             :   }
     258             : 
     259           4 :   return rv;
     260             : }
     261             : 
     262           1 : NS_IMETHODIMP nsPrefBranch::SetStringPref(const char *aPrefName, const nsACString& aValue)
     263             : {
     264           1 :   nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
     265           1 :   if (NS_FAILED(rv)) {
     266           0 :     return rv;
     267             :   }
     268             : 
     269           1 :   return SetCharPrefInternal(aPrefName, PromiseFlatCString(aValue).get());
     270             : }
     271             : 
     272          51 : NS_IMETHODIMP nsPrefBranch::GetIntPrefWithDefault(const char *aPrefName,
     273             :                                                   int32_t aDefaultValue,
     274             :                                                   uint8_t _argc, int32_t *_retval)
     275             : {
     276          51 :   nsresult rv = GetIntPref(aPrefName, _retval);
     277             : 
     278          51 :   if (NS_FAILED(rv) && _argc == 1) {
     279           3 :     *_retval = aDefaultValue;
     280           3 :     return NS_OK;
     281             :   }
     282             : 
     283          48 :   return rv;
     284             : }
     285             : 
     286         232 : NS_IMETHODIMP nsPrefBranch::GetIntPref(const char *aPrefName, int32_t *_retval)
     287             : {
     288         232 :   NS_ENSURE_ARG(aPrefName);
     289         464 :   const PrefName& pref = getPrefName(aPrefName);
     290         232 :   return PREF_GetIntPref(pref.get(), _retval, mIsDefault);
     291             : }
     292             : 
     293          12 : NS_IMETHODIMP nsPrefBranch::SetIntPref(const char *aPrefName, int32_t aValue)
     294             : {
     295          12 :   ENSURE_MAIN_PROCESS("Cannot SetIntPref from content process:", aPrefName);
     296          12 :   NS_ENSURE_ARG(aPrefName);
     297          24 :   const PrefName& pref = getPrefName(aPrefName);
     298          12 :   return PREF_SetIntPref(pref.get(), aValue, mIsDefault);
     299             : }
     300             : 
     301          47 : NS_IMETHODIMP nsPrefBranch::GetComplexValue(const char *aPrefName, const nsIID & aType, void **_retval)
     302             : {
     303          47 :   NS_ENSURE_ARG(aPrefName);
     304             : 
     305             :   nsresult       rv;
     306          94 :   nsXPIDLCString utf8String;
     307             : 
     308             :   // we have to do this one first because it's different than all the rest
     309          47 :   if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
     310          50 :     nsCOMPtr<nsIPrefLocalizedString> theString(do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv));
     311          25 :     if (NS_FAILED(rv)) return rv;
     312             : 
     313          50 :     const PrefName& pref = getPrefName(aPrefName);
     314          25 :     bool    bNeedDefault = false;
     315             : 
     316          25 :     if (mIsDefault) {
     317           0 :       bNeedDefault = true;
     318             :     } else {
     319             :       // if there is no user (or locked) value
     320          25 :       if (!PREF_HasUserPref(pref.get()) && !PREF_PrefIsLocked(pref.get())) {
     321          19 :         bNeedDefault = true;
     322             :       }
     323             :     }
     324             : 
     325             :     // if we need to fetch the default value, do that instead, otherwise use the
     326             :     // value we pulled in at the top of this function
     327          25 :     if (bNeedDefault) {
     328          38 :       nsXPIDLString utf16String;
     329          19 :       rv = GetDefaultFromPropertiesFile(pref.get(), getter_Copies(utf16String));
     330          19 :       if (NS_SUCCEEDED(rv)) {
     331          14 :         theString->SetData(utf16String.get());
     332             :       }
     333             :     } else {
     334           6 :       rv = GetCharPref(aPrefName, getter_Copies(utf8String));
     335           6 :       if (NS_SUCCEEDED(rv)) {
     336           6 :         theString->SetData(NS_ConvertUTF8toUTF16(utf8String).get());
     337             :       }
     338             :     }
     339             : 
     340          25 :     if (NS_SUCCEEDED(rv)) {
     341          20 :       theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(_retval));
     342             :     }
     343             : 
     344          25 :     return rv;
     345             :   }
     346             : 
     347             :   // if we can't get the pref, there's no point in being here
     348          22 :   rv = GetCharPref(aPrefName, getter_Copies(utf8String));
     349          22 :   if (NS_FAILED(rv)) {
     350           3 :     return rv;
     351             :   }
     352             : 
     353             :   // also check nsILocalFile, for backwards compatibility
     354          19 :   if (aType.Equals(NS_GET_IID(nsIFile)) || aType.Equals(NS_GET_IID(nsILocalFile))) {
     355           0 :     if (GetContentChild()) {
     356           0 :       NS_ERROR("cannot get nsIFile pref from content process");
     357           0 :       return NS_ERROR_NOT_AVAILABLE;
     358             :     }
     359             : 
     360           0 :     nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
     361             : 
     362           0 :     if (NS_SUCCEEDED(rv)) {
     363           0 :       rv = file->SetPersistentDescriptor(utf8String);
     364           0 :       if (NS_SUCCEEDED(rv)) {
     365           0 :         file.forget(reinterpret_cast<nsIFile**>(_retval));
     366           0 :         return NS_OK;
     367             :       }
     368             :     }
     369           0 :     return rv;
     370             :   }
     371             : 
     372          19 :   if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
     373           0 :     if (GetContentChild()) {
     374           0 :       NS_ERROR("cannot get nsIRelativeFilePref from content process");
     375           0 :       return NS_ERROR_NOT_AVAILABLE;
     376             :     }
     377             : 
     378           0 :     nsACString::const_iterator keyBegin, strEnd;
     379           0 :     utf8String.BeginReading(keyBegin);
     380           0 :     utf8String.EndReading(strEnd);
     381             : 
     382             :     // The pref has the format: [fromKey]a/b/c
     383           0 :     if (*keyBegin++ != '[')
     384           0 :       return NS_ERROR_FAILURE;
     385           0 :     nsACString::const_iterator keyEnd(keyBegin);
     386           0 :     if (!FindCharInReadable(']', keyEnd, strEnd))
     387           0 :       return NS_ERROR_FAILURE;
     388           0 :     nsAutoCString key(Substring(keyBegin, keyEnd));
     389             : 
     390           0 :     nsCOMPtr<nsIFile> fromFile;
     391           0 :     nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
     392           0 :     if (NS_FAILED(rv))
     393           0 :       return rv;
     394           0 :     rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile), getter_AddRefs(fromFile));
     395           0 :     if (NS_FAILED(rv))
     396           0 :       return rv;
     397             : 
     398           0 :     nsCOMPtr<nsIFile> theFile;
     399           0 :     rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(theFile));
     400           0 :     if (NS_FAILED(rv))
     401           0 :       return rv;
     402           0 :     rv = theFile->SetRelativeDescriptor(fromFile, Substring(++keyEnd, strEnd));
     403           0 :     if (NS_FAILED(rv))
     404           0 :       return rv;
     405           0 :     nsCOMPtr<nsIRelativeFilePref> relativePref;
     406           0 :     rv = NS_NewRelativeFilePref(theFile, key, getter_AddRefs(relativePref));
     407           0 :     if (NS_FAILED(rv))
     408           0 :       return rv;
     409             : 
     410           0 :     relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(_retval));
     411           0 :     return NS_OK;
     412             :   }
     413             : 
     414          19 :   if (aType.Equals(NS_GET_IID(nsISupportsString))) {
     415          38 :     nsCOMPtr<nsISupportsString> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
     416             : 
     417          19 :     if (NS_SUCCEEDED(rv)) {
     418             :       // Debugging to see why we end up with very long strings here with
     419             :       // some addons, see bug 836263.
     420          38 :       nsAutoString wdata;
     421          19 :       if (!AppendUTF8toUTF16(utf8String, wdata, mozilla::fallible)) {
     422             : #ifdef MOZ_CRASHREPORTER
     423             :         nsCOMPtr<nsICrashReporter> cr =
     424           0 :           do_GetService("@mozilla.org/toolkit/crash-reporter;1");
     425           0 :         if (cr) {
     426           0 :           cr->AnnotateCrashReport(NS_LITERAL_CSTRING("bug836263-size"),
     427           0 :                                   nsPrintfCString("%x", utf8String.Length()));
     428           0 :           cr->RegisterAppMemory(uint64_t(utf8String.BeginReading()),
     429           0 :                                 std::min(0x1000U, utf8String.Length()));
     430             :         }
     431             : #endif
     432           0 :         MOZ_CRASH("bug836263");
     433             :       }
     434          19 :       theString->SetData(wdata);
     435          19 :       theString.forget(reinterpret_cast<nsISupportsString**>(_retval));
     436             :     }
     437          19 :     return rv;
     438             :   }
     439             : 
     440           0 :   NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type");
     441           0 :   return NS_NOINTERFACE;
     442             : }
     443             : 
     444           8 : nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const char* aValue) {
     445           8 :   if (!aValue) {
     446           0 :     return NS_OK;
     447             :   }
     448           8 :   return CheckSanityOfStringLength(aPrefName, strlen(aValue));
     449             : }
     450             : 
     451           0 : nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const nsAString& aValue) {
     452           0 :   return CheckSanityOfStringLength(aPrefName, aValue.Length());
     453             : }
     454             : 
     455           1 : nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const nsACString& aValue) {
     456           1 :   return CheckSanityOfStringLength(aPrefName, aValue.Length());
     457             : }
     458             : 
     459           9 : nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const uint32_t aLength) {
     460           9 :   if (aLength > MAX_PREF_LENGTH) {
     461           0 :     return NS_ERROR_ILLEGAL_VALUE;
     462             :   }
     463           9 :   if (aLength <= MAX_ADVISABLE_PREF_LENGTH) {
     464           9 :     return NS_OK;
     465             :   }
     466             :   nsresult rv;
     467           0 :   nsCOMPtr<nsIConsoleService> console = do_GetService("@mozilla.org/consoleservice;1", &rv);
     468           0 :   if (NS_FAILED(rv)) {
     469           0 :     return rv;
     470             :   }
     471           0 :   nsAutoCString message(nsPrintfCString("Warning: attempting to write %d bytes to preference %s. This is bad "
     472             :                                         "for general performance and memory usage. Such an amount of data "
     473             :                                         "should rather be written to an external file. This preference will "
     474             :                                         "not be sent to any content processes.",
     475             :                                         aLength,
     476           0 :                                         getPrefName(aPrefName).get()));
     477           0 :   rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get());
     478           0 :   if (NS_FAILED(rv)) {
     479           0 :     return rv;
     480             :   }
     481           0 :   return NS_OK;
     482             : }
     483             : 
     484             : /*static*/
     485           0 : void nsPrefBranch::ReportToConsole(const nsAString& aMessage)
     486             : {
     487             :   nsresult rv;
     488           0 :   nsCOMPtr<nsIConsoleService> console = do_GetService("@mozilla.org/consoleservice;1", &rv);
     489           0 :   if (NS_FAILED(rv)) {
     490           0 :     return;
     491             :   }
     492           0 :   nsAutoString message(aMessage);
     493           0 :   console->LogStringMessage(message.get());
     494             : }
     495             : 
     496           0 : NS_IMETHODIMP nsPrefBranch::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
     497             : {
     498           0 :   ENSURE_MAIN_PROCESS("Cannot SetComplexValue from content process:", aPrefName);
     499           0 :   NS_ENSURE_ARG(aPrefName);
     500             : 
     501           0 :   nsresult   rv = NS_NOINTERFACE;
     502             : 
     503             :   // also check nsILocalFile, for backwards compatibility
     504           0 :   if (aType.Equals(NS_GET_IID(nsIFile)) || aType.Equals(NS_GET_IID(nsILocalFile))) {
     505           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(aValue);
     506           0 :     if (!file)
     507           0 :       return NS_NOINTERFACE;
     508           0 :     nsAutoCString descriptorString;
     509             : 
     510           0 :     rv = file->GetPersistentDescriptor(descriptorString);
     511           0 :     if (NS_SUCCEEDED(rv)) {
     512           0 :       rv = SetCharPrefInternal(aPrefName, descriptorString.get());
     513             :     }
     514           0 :     return rv;
     515             :   }
     516             : 
     517           0 :   if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
     518           0 :     nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue);
     519           0 :     if (!relFilePref)
     520           0 :       return NS_NOINTERFACE;
     521             : 
     522           0 :     nsCOMPtr<nsIFile> file;
     523           0 :     relFilePref->GetFile(getter_AddRefs(file));
     524           0 :     if (!file)
     525           0 :       return NS_NOINTERFACE;
     526           0 :     nsAutoCString relativeToKey;
     527           0 :     (void) relFilePref->GetRelativeToKey(relativeToKey);
     528             : 
     529           0 :     nsCOMPtr<nsIFile> relativeToFile;
     530           0 :     nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
     531           0 :     if (NS_FAILED(rv))
     532           0 :       return rv;
     533           0 :     rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile), getter_AddRefs(relativeToFile));
     534           0 :     if (NS_FAILED(rv))
     535           0 :       return rv;
     536             : 
     537           0 :     nsAutoCString relDescriptor;
     538           0 :     rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor);
     539           0 :     if (NS_FAILED(rv))
     540           0 :       return rv;
     541             : 
     542           0 :     nsAutoCString descriptorString;
     543           0 :     descriptorString.Append('[');
     544           0 :     descriptorString.Append(relativeToKey);
     545           0 :     descriptorString.Append(']');
     546           0 :     descriptorString.Append(relDescriptor);
     547           0 :     return SetCharPrefInternal(aPrefName, descriptorString.get());
     548             :   }
     549             : 
     550           0 :   if (aType.Equals(NS_GET_IID(nsISupportsString))) {
     551           0 :     nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
     552             : 
     553           0 :     if (theString) {
     554           0 :       nsString wideString;
     555             : 
     556           0 :       rv = theString->GetData(wideString);
     557           0 :       if (NS_SUCCEEDED(rv)) {
     558             :         // Check sanity of string length before any lengthy conversion
     559           0 :         rv = CheckSanityOfStringLength(aPrefName, wideString);
     560           0 :         if (NS_FAILED(rv)) {
     561           0 :           return rv;
     562             :         }
     563           0 :         rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
     564             :       }
     565             :     }
     566           0 :     return rv;
     567             :   }
     568             : 
     569           0 :   if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
     570           0 :     nsCOMPtr<nsIPrefLocalizedString> theString = do_QueryInterface(aValue);
     571             : 
     572           0 :     if (theString) {
     573           0 :       nsXPIDLString wideString;
     574             : 
     575           0 :       rv = theString->GetData(getter_Copies(wideString));
     576           0 :       if (NS_SUCCEEDED(rv)) {
     577             :         // Check sanity of string length before any lengthy conversion
     578           0 :         rv = CheckSanityOfStringLength(aPrefName, wideString);
     579           0 :         if (NS_FAILED(rv)) {
     580           0 :           return rv;
     581             :         }
     582           0 :         rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
     583             :       }
     584             :     }
     585           0 :     return rv;
     586             :   }
     587             : 
     588           0 :   NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type");
     589           0 :   return NS_NOINTERFACE;
     590             : }
     591             : 
     592           5 : NS_IMETHODIMP nsPrefBranch::ClearUserPref(const char *aPrefName)
     593             : {
     594           5 :   ENSURE_MAIN_PROCESS("Cannot ClearUserPref from content process:", aPrefName);
     595           5 :   NS_ENSURE_ARG(aPrefName);
     596          10 :   const PrefName& pref = getPrefName(aPrefName);
     597           5 :   return PREF_ClearUserPref(pref.get());
     598             : }
     599             : 
     600          87 : NS_IMETHODIMP nsPrefBranch::PrefHasUserValue(const char *aPrefName, bool *_retval)
     601             : {
     602          87 :   NS_ENSURE_ARG_POINTER(_retval);
     603          87 :   NS_ENSURE_ARG(aPrefName);
     604         174 :   const PrefName& pref = getPrefName(aPrefName);
     605          87 :   *_retval = PREF_HasUserPref(pref.get());
     606          87 :   return NS_OK;
     607             : }
     608             : 
     609           0 : NS_IMETHODIMP nsPrefBranch::LockPref(const char *aPrefName)
     610             : {
     611           0 :   ENSURE_MAIN_PROCESS("Cannot LockPref from content process:", aPrefName);
     612           0 :   NS_ENSURE_ARG(aPrefName);
     613           0 :   const PrefName& pref = getPrefName(aPrefName);
     614           0 :   return PREF_LockPref(pref.get(), true);
     615             : }
     616             : 
     617           1 : NS_IMETHODIMP nsPrefBranch::PrefIsLocked(const char *aPrefName, bool *_retval)
     618             : {
     619           1 :   ENSURE_MAIN_PROCESS("Cannot check PrefIsLocked from content process:", aPrefName);
     620           1 :   NS_ENSURE_ARG_POINTER(_retval);
     621           1 :   NS_ENSURE_ARG(aPrefName);
     622           2 :   const PrefName& pref = getPrefName(aPrefName);
     623           1 :   *_retval = PREF_PrefIsLocked(pref.get());
     624           1 :   return NS_OK;
     625             : }
     626             : 
     627           0 : NS_IMETHODIMP nsPrefBranch::UnlockPref(const char *aPrefName)
     628             : {
     629           0 :   ENSURE_MAIN_PROCESS("Cannot UnlockPref from content process:", aPrefName);
     630           0 :   NS_ENSURE_ARG(aPrefName);
     631           0 :   const PrefName& pref = getPrefName(aPrefName);
     632           0 :   return PREF_LockPref(pref.get(), false);
     633             : }
     634             : 
     635           0 : NS_IMETHODIMP nsPrefBranch::ResetBranch(const char *aStartingAt)
     636             : {
     637           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     638             : }
     639             : 
     640           0 : NS_IMETHODIMP nsPrefBranch::DeleteBranch(const char *aStartingAt)
     641             : {
     642           0 :   ENSURE_MAIN_PROCESS("Cannot DeleteBranch from content process:", aStartingAt);
     643           0 :   NS_ENSURE_ARG(aStartingAt);
     644           0 :   const PrefName& pref = getPrefName(aStartingAt);
     645           0 :   return PREF_DeleteBranch(pref.get());
     646             : }
     647             : 
     648          28 : NS_IMETHODIMP nsPrefBranch::GetChildList(const char *aStartingAt, uint32_t *aCount, char ***aChildArray)
     649             : {
     650             :   char            **outArray;
     651             :   int32_t         numPrefs;
     652             :   int32_t         dwIndex;
     653          56 :   AutoTArray<nsCString, 32> prefArray;
     654             : 
     655          28 :   NS_ENSURE_ARG(aStartingAt);
     656          28 :   NS_ENSURE_ARG_POINTER(aCount);
     657          28 :   NS_ENSURE_ARG_POINTER(aChildArray);
     658             : 
     659          28 :   *aChildArray = nullptr;
     660          28 :   *aCount = 0;
     661             : 
     662             :   // this will contain a list of all the pref name strings
     663             :   // allocate on the stack for speed
     664             : 
     665          56 :   const PrefName& parent = getPrefName(aStartingAt);
     666          28 :   size_t parentLen = parent.Length();
     667       84528 :   for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
     668       84500 :     auto entry = static_cast<PrefHashEntry*>(iter.Get());
     669       84500 :     if (strncmp(entry->key, parent.get(), parentLen) == 0) {
     670         818 :       prefArray.AppendElement(entry->key);
     671             :     }
     672             :   }
     673             : 
     674             :   // now that we've built up the list, run the callback on
     675             :   // all the matching elements
     676          28 :   numPrefs = prefArray.Length();
     677             : 
     678          28 :   if (numPrefs) {
     679          23 :     outArray = (char **)moz_xmalloc(numPrefs * sizeof(char *));
     680          23 :     if (!outArray)
     681           0 :       return NS_ERROR_OUT_OF_MEMORY;
     682             : 
     683         841 :     for (dwIndex = 0; dwIndex < numPrefs; ++dwIndex) {
     684             :       // we need to lop off mPrefRoot in case the user is planning to pass this
     685             :       // back to us because if they do we are going to add mPrefRoot again.
     686         818 :       const nsCString& element = prefArray[dwIndex];
     687        2454 :       outArray[dwIndex] = (char *)nsMemory::Clone(
     688        1636 :         element.get() + mPrefRoot.Length(), element.Length() - mPrefRoot.Length() + 1);
     689             : 
     690         818 :       if (!outArray[dwIndex]) {
     691             :         // we ran out of memory... this is annoying
     692           0 :         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(dwIndex, outArray);
     693           0 :         return NS_ERROR_OUT_OF_MEMORY;
     694             :       }
     695             :     }
     696          23 :     *aChildArray = outArray;
     697             :   }
     698          28 :   *aCount = numPrefs;
     699             : 
     700          28 :   return NS_OK;
     701             : }
     702             : 
     703         925 : NS_IMETHODIMP nsPrefBranch::AddObserver(const char *aDomain, nsIObserver *aObserver, bool aHoldWeak)
     704             : {
     705             :   PrefCallback *pCallback;
     706             : 
     707         925 :   NS_ENSURE_ARG(aDomain);
     708         925 :   NS_ENSURE_ARG(aObserver);
     709             : 
     710             :   // hold a weak reference to the observer if so requested
     711         925 :   if (aHoldWeak) {
     712         288 :     nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver);
     713         144 :     if (!weakRefFactory) {
     714             :       // the caller didn't give us a object that supports weak reference... tell them
     715           0 :       return NS_ERROR_INVALID_ARG;
     716             :     }
     717             : 
     718             :     // Construct a PrefCallback with a weak reference to the observer.
     719         288 :     pCallback = new PrefCallback(aDomain, weakRefFactory, this);
     720             : 
     721             :   } else {
     722             :     // Construct a PrefCallback with a strong reference to the observer.
     723         781 :     pCallback = new PrefCallback(aDomain, aObserver, this);
     724             :   }
     725             : 
     726        1850 :   auto p = mObservers.LookupForAdd(pCallback);
     727         925 :   if (p) {
     728           0 :     NS_WARNING("Ignoring duplicate observer.");
     729           0 :     delete pCallback;
     730           0 :     return NS_OK;
     731             :   }
     732             : 
     733         925 :   p.OrInsert([&pCallback]() {
     734             :     return pCallback;
     735        1850 :   });
     736             : 
     737             :   // We must pass a fully qualified preference name to the callback
     738             :   // aDomain == nullptr is the only possible failure, and we trapped it with
     739             :   // NS_ENSURE_ARG above.
     740        1850 :   const PrefName& pref = getPrefName(aDomain);
     741         925 :   PREF_RegisterCallback(pref.get(), NotifyObserver, pCallback);
     742         925 :   return NS_OK;
     743             : }
     744             : 
     745           3 : NS_IMETHODIMP nsPrefBranch::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
     746             : {
     747           3 :   NS_ENSURE_ARG(aDomain);
     748           3 :   NS_ENSURE_ARG(aObserver);
     749             : 
     750           3 :   nsresult rv = NS_OK;
     751             : 
     752             :   // If we're in the middle of a call to freeObserverList, don't process this
     753             :   // RemoveObserver call -- the observer in question will be removed soon, if
     754             :   // it hasn't been already.
     755             :   //
     756             :   // It's important that we don't touch mObservers in any way -- even a Get()
     757             :   // which returns null might cause the hashtable to resize itself, which will
     758             :   // break the iteration in freeObserverList.
     759           3 :   if (mFreeingObserverList)
     760           0 :     return NS_OK;
     761             : 
     762             :   // Remove the relevant PrefCallback from mObservers and get an owning
     763             :   // pointer to it.  Unregister the callback first, and then let the owning
     764             :   // pointer go out of scope and destroy the callback.
     765           6 :   PrefCallback key(aDomain, aObserver, this);
     766           6 :   nsAutoPtr<PrefCallback> pCallback;
     767           3 :   mObservers.Remove(&key, &pCallback);
     768           3 :   if (pCallback) {
     769             :     // aDomain == nullptr is the only possible failure, trapped above
     770           6 :     const PrefName& pref = getPrefName(aDomain);
     771           3 :     rv = PREF_UnregisterCallback(pref.get(), NotifyObserver, pCallback);
     772             :   }
     773             : 
     774           3 :   return rv;
     775             : }
     776             : 
     777           0 : NS_IMETHODIMP nsPrefBranch::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
     778             : {
     779             :   // watch for xpcom shutdown and free our observers to eliminate any cyclic references
     780           0 :   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     781           0 :     freeObserverList();
     782             :   }
     783           0 :   return NS_OK;
     784             : }
     785             : 
     786             : /* static */
     787          49 : void nsPrefBranch::NotifyObserver(const char *newpref, void *data)
     788             : {
     789          49 :   PrefCallback *pCallback = (PrefCallback *)data;
     790             : 
     791          98 :   nsCOMPtr<nsIObserver> observer = pCallback->GetObserver();
     792          49 :   if (!observer) {
     793             :     // The observer has expired.  Let's remove this callback.
     794           0 :     pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback);
     795           0 :     return;
     796             :   }
     797             : 
     798             :   // remove any root this string may contain so as to not confuse the observer
     799             :   // by passing them something other than what they passed us as a topic
     800          49 :   uint32_t len = pCallback->GetPrefBranch()->GetRootLength();
     801          98 :   nsAutoCString suffix(newpref + len);
     802             : 
     803          98 :   observer->Observe(static_cast<nsIPrefBranch *>(pCallback->GetPrefBranch()),
     804             :                     NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
     805          98 :                     NS_ConvertASCIItoUTF16(suffix).get());
     806             : }
     807             : 
     808             : size_t
     809           0 : nsPrefBranch::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     810             : {
     811           0 :   size_t n = aMallocSizeOf(this);
     812           0 :   n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     813           0 :   n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
     814           0 :   return n;
     815             : }
     816             : 
     817           2 : void nsPrefBranch::freeObserverList(void)
     818             : {
     819             :   // We need to prevent anyone from modifying mObservers while we're iterating
     820             :   // over it. In particular, some clients will call RemoveObserver() when
     821             :   // they're removed and destructed via the iterator; we set
     822             :   // mFreeingObserverList to keep those calls from touching mObservers.
     823           2 :   mFreeingObserverList = true;
     824           2 :   for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) {
     825           0 :     nsAutoPtr<PrefCallback>& callback = iter.Data();
     826           0 :     nsPrefBranch *prefBranch = callback->GetPrefBranch();
     827           0 :     const PrefName& pref = prefBranch->getPrefName(callback->GetDomain().get());
     828           0 :     PREF_UnregisterCallback(pref.get(), nsPrefBranch::NotifyObserver, callback);
     829           0 :     iter.Remove();
     830             :   }
     831           2 :   mFreeingObserverList = false;
     832           2 : }
     833             : 
     834             : void
     835           0 : nsPrefBranch::RemoveExpiredCallback(PrefCallback *aCallback)
     836             : {
     837           0 :   NS_PRECONDITION(aCallback->IsExpired(), "Callback should be expired.");
     838           0 :   mObservers.Remove(aCallback);
     839           0 : }
     840             : 
     841          19 : nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char *aPrefName, char16_t **return_buf)
     842             : {
     843             :   nsresult rv;
     844             : 
     845             :   // the default value contains a URL to a .properties file
     846             : 
     847          38 :   nsXPIDLCString propertyFileURL;
     848          19 :   rv = PREF_CopyCharPref(aPrefName, getter_Copies(propertyFileURL), true);
     849          19 :   if (NS_FAILED(rv))
     850           0 :     return rv;
     851             : 
     852             :   nsCOMPtr<nsIStringBundleService> bundleService =
     853          38 :     mozilla::services::GetStringBundleService();
     854          19 :   if (!bundleService)
     855           0 :     return NS_ERROR_FAILURE;
     856             : 
     857          38 :   nsCOMPtr<nsIStringBundle> bundle;
     858          38 :   rv = bundleService->CreateBundle(propertyFileURL,
     859          38 :                                    getter_AddRefs(bundle));
     860          19 :   if (NS_FAILED(rv))
     861           0 :     return rv;
     862             : 
     863             :   // string names are in unicode
     864          38 :   nsAutoString stringId;
     865          19 :   stringId.AssignASCII(aPrefName);
     866             : 
     867          19 :   return bundle->GetStringFromName(stringId.get(), return_buf);
     868             : }
     869             : 
     870             : nsPrefBranch::PrefName
     871        2629 : nsPrefBranch::getPrefName(const char *aPrefName) const
     872             : {
     873        2629 :   NS_ASSERTION(aPrefName, "null pref name!");
     874             : 
     875             :   // for speed, avoid strcpy if we can:
     876        2629 :   if (mPrefRoot.IsEmpty())
     877        2415 :     return PrefName(aPrefName);
     878             : 
     879         214 :   return PrefName(mPrefRoot + nsDependentCString(aPrefName));
     880             : }
     881             : 
     882             : //----------------------------------------------------------------------------
     883             : // nsPrefLocalizedString
     884             : //----------------------------------------------------------------------------
     885             : 
     886          25 : nsPrefLocalizedString::nsPrefLocalizedString()
     887             : {
     888          25 : }
     889             : 
     890          28 : nsPrefLocalizedString::~nsPrefLocalizedString()
     891             : {
     892          42 : }
     893             : 
     894             : 
     895             : /*
     896             :  * nsISupports Implementation
     897             :  */
     898             : 
     899         117 : NS_IMPL_ADDREF(nsPrefLocalizedString)
     900          95 : NS_IMPL_RELEASE(nsPrefLocalizedString)
     901             : 
     902         147 : NS_INTERFACE_MAP_BEGIN(nsPrefLocalizedString)
     903         147 :     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefLocalizedString)
     904         136 :     NS_INTERFACE_MAP_ENTRY(nsIPrefLocalizedString)
     905          66 :     NS_INTERFACE_MAP_ENTRY(nsISupportsString)
     906          66 : NS_INTERFACE_MAP_END
     907             : 
     908          25 : nsresult nsPrefLocalizedString::Init()
     909             : {
     910             :   nsresult rv;
     911          25 :   mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
     912             : 
     913          25 :   return rv;
     914             : }
     915             : 
     916             : NS_IMETHODIMP
     917          20 : nsPrefLocalizedString::GetData(char16_t **_retval)
     918             : {
     919          40 :   nsAutoString data;
     920             : 
     921          20 :   nsresult rv = GetData(data);
     922          20 :   if (NS_FAILED(rv))
     923           0 :     return rv;
     924             : 
     925          20 :   *_retval = ToNewUnicode(data);
     926          20 :   if (!*_retval)
     927           0 :     return NS_ERROR_OUT_OF_MEMORY;
     928             : 
     929          20 :   return NS_OK;
     930             : }
     931             : 
     932             : NS_IMETHODIMP
     933          20 : nsPrefLocalizedString::SetData(const char16_t *aData)
     934             : {
     935          20 :   if (!aData)
     936           0 :     return SetData(EmptyString());
     937          20 :   return SetData(nsDependentString(aData));
     938             : }
     939             : 
     940             : NS_IMETHODIMP
     941           0 : nsPrefLocalizedString::SetDataWithLength(uint32_t aLength,
     942             :                                          const char16_t *aData)
     943             : {
     944           0 :   if (!aData)
     945           0 :     return SetData(EmptyString());
     946           0 :   return SetData(Substring(aData, aLength));
     947             : }
     948             : 
     949             : //----------------------------------------------------------------------------
     950             : // nsRelativeFilePref
     951             : //----------------------------------------------------------------------------
     952             : 
     953           0 : NS_IMPL_ISUPPORTS(nsRelativeFilePref, nsIRelativeFilePref)
     954             : 
     955           0 : nsRelativeFilePref::nsRelativeFilePref()
     956             : {
     957           0 : }
     958             : 
     959           0 : nsRelativeFilePref::~nsRelativeFilePref()
     960             : {
     961           0 : }
     962             : 
     963           0 : NS_IMETHODIMP nsRelativeFilePref::GetFile(nsIFile **aFile)
     964             : {
     965           0 :   NS_ENSURE_ARG_POINTER(aFile);
     966           0 :   *aFile = mFile;
     967           0 :   NS_IF_ADDREF(*aFile);
     968           0 :   return NS_OK;
     969             : }
     970             : 
     971           0 : NS_IMETHODIMP nsRelativeFilePref::SetFile(nsIFile *aFile)
     972             : {
     973           0 :   mFile = aFile;
     974           0 :   return NS_OK;
     975             : }
     976             : 
     977           0 : NS_IMETHODIMP nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey)
     978             : {
     979           0 :   aRelativeToKey.Assign(mRelativeToKey);
     980           0 :   return NS_OK;
     981             : }
     982             : 
     983           0 : NS_IMETHODIMP nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey)
     984             : {
     985           0 :   mRelativeToKey.Assign(aRelativeToKey);
     986           0 :   return NS_OK;
     987             : }
     988             : 
     989             : #undef ENSURE_MAIN_PROCESS

Generated by: LCOV version 1.13