"Fossies" - the Fresh Open Source Software Archive

Member "UXP-2019.06.08/modules/libpref/Preferences.cpp" (8 Jun 2019, 57342 Bytes) of package /linux/www/UXP-2019.06.08.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "Preferences.cpp": 2019.03.27_vs_2019.06.08.

    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/MemoryReporting.h"
    8 #include "mozilla/dom/ContentChild.h"
    9 
   10 #include "mozilla/ArrayUtils.h"
   11 #include "mozilla/Attributes.h"
   12 #include "mozilla/HashFunctions.h"
   13 #include "mozilla/UniquePtrExtensions.h"
   14 
   15 #include "nsXULAppAPI.h"
   16 
   17 #include "mozilla/Preferences.h"
   18 #include "nsAppDirectoryServiceDefs.h"
   19 #include "nsDataHashtable.h"
   20 #include "nsDirectoryServiceDefs.h"
   21 #include "nsICategoryManager.h"
   22 #include "nsCategoryManagerUtils.h"
   23 #include "nsNetUtil.h"
   24 #include "nsIFile.h"
   25 #include "nsIInputStream.h"
   26 #include "nsIObserverService.h"
   27 #include "nsIOutputStream.h"
   28 #include "nsISafeOutputStream.h"
   29 #include "nsISimpleEnumerator.h"
   30 #include "nsIStringEnumerator.h"
   31 #include "nsIZipReader.h"
   32 #include "nsPrefBranch.h"
   33 #include "nsXPIDLString.h"
   34 #include "nsCRT.h"
   35 #include "nsCOMArray.h"
   36 #include "nsXPCOMCID.h"
   37 #include "nsAutoPtr.h"
   38 #include "nsPrintfCString.h"
   39 
   40 #include "nsQuickSort.h"
   41 #include "PLDHashTable.h"
   42 
   43 #include "prefapi.h"
   44 #include "prefread.h"
   45 #include "prefapi_private_data.h"
   46 
   47 #include "mozilla/Omnijar.h"
   48 #include "nsZipArchive.h"
   49 
   50 #include "nsTArray.h"
   51 #include "nsRefPtrHashtable.h"
   52 #include "nsIMemoryReporter.h"
   53 #include "nsThreadUtils.h"
   54 
   55 #ifdef DEBUG
   56 #define ENSURE_MAIN_PROCESS(message, pref) do {                                \
   57   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {        \
   58     nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref);   \
   59     NS_WARNING(msg.get());                                                     \
   60     return NS_ERROR_NOT_AVAILABLE;                                             \
   61   }                                                                            \
   62 } while (0);
   63 #else
   64 #define ENSURE_MAIN_PROCESS(message, pref)                                     \
   65   if (MOZ_UNLIKELY(!XRE_IsParentProcess())) {        \
   66     return NS_ERROR_NOT_AVAILABLE;                                             \
   67   }
   68 #endif
   69 
   70 class PrefCallback;
   71 
   72 namespace mozilla {
   73 
   74 // Definitions
   75 #define INITIAL_PREF_FILES 10
   76 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
   77 
   78 void
   79 Preferences::DirtyCallback()
   80 {
   81   if (gHashTable && sPreferences && !sPreferences->mDirty) {
   82     sPreferences->mDirty = true;
   83   }
   84 }
   85 
   86 // Prototypes
   87 static nsresult openPrefFile(nsIFile* aFile);
   88 static nsresult pref_InitInitialObjects(void);
   89 static nsresult pref_LoadPrefsInDirList(const char *listId);
   90 static nsresult ReadExtensionPrefs(nsIFile *aFile);
   91 
   92 static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
   93 static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease";
   94 static const char kChannelPref[] = "app.update.channel";
   95 
   96 static const char kPrefFileHeader[] =
   97   "# Mozilla User Preferences"
   98   NS_LINEBREAK
   99   NS_LINEBREAK
  100   "/* Do not edit this file."
  101   NS_LINEBREAK
  102   " *"
  103   NS_LINEBREAK
  104   " * If you make changes to this file while the application is running,"
  105   NS_LINEBREAK
  106   " * the changes will be overwritten when the application exits."
  107   NS_LINEBREAK
  108   " *"
  109   NS_LINEBREAK
  110   " * To make a manual change to preferences, you can visit the URL about:config"
  111   NS_LINEBREAK
  112   " */"
  113   NS_LINEBREAK
  114   NS_LINEBREAK;
  115 
  116 Preferences* Preferences::sPreferences = nullptr;
  117 nsIPrefBranch* Preferences::sRootBranch = nullptr;
  118 nsIPrefBranch* Preferences::sDefaultRootBranch = nullptr;
  119 bool Preferences::sShutdown = false;
  120 
  121 class ValueObserverHashKey : public PLDHashEntryHdr {
  122 public:
  123   typedef ValueObserverHashKey* KeyType;
  124   typedef const ValueObserverHashKey* KeyTypePointer;
  125 
  126   static const ValueObserverHashKey* KeyToPointer(ValueObserverHashKey *aKey)
  127   {
  128     return aKey;
  129   }
  130 
  131   static PLDHashNumber HashKey(const ValueObserverHashKey *aKey)
  132   {
  133     PLDHashNumber hash = HashString(aKey->mPrefName);
  134     hash = AddToHash(hash, aKey->mMatchKind);
  135     return AddToHash(hash, aKey->mCallback);
  136   }
  137 
  138   ValueObserverHashKey(const char *aPref, PrefChangedFunc aCallback, Preferences::MatchKind aMatchKind) :
  139     mPrefName(aPref), mCallback(aCallback), mMatchKind(aMatchKind) { }
  140 
  141   explicit ValueObserverHashKey(const ValueObserverHashKey *aOther) :
  142     mPrefName(aOther->mPrefName),
  143     mCallback(aOther->mCallback),
  144     mMatchKind(aOther->mMatchKind)
  145   { }
  146 
  147   bool KeyEquals(const ValueObserverHashKey *aOther) const
  148   {
  149     return mCallback == aOther->mCallback &&
  150            mPrefName == aOther->mPrefName &&
  151            mMatchKind == aOther->mMatchKind;
  152   }
  153 
  154   ValueObserverHashKey *GetKey() const
  155   {
  156     return const_cast<ValueObserverHashKey*>(this);
  157   }
  158 
  159   enum { ALLOW_MEMMOVE = true };
  160 
  161   nsCString mPrefName;
  162   PrefChangedFunc mCallback;
  163   Preferences::MatchKind mMatchKind;
  164 };
  165 
  166 class ValueObserver final : public nsIObserver,
  167                             public ValueObserverHashKey
  168 {
  169   ~ValueObserver() {
  170     Preferences::RemoveObserver(this, mPrefName.get());
  171   }
  172 
  173 public:
  174   NS_DECL_ISUPPORTS
  175   NS_DECL_NSIOBSERVER
  176 
  177   ValueObserver(const char *aPref, PrefChangedFunc aCallback, Preferences::MatchKind aMatchKind)
  178     : ValueObserverHashKey(aPref, aCallback, aMatchKind) { }
  179 
  180   void AppendClosure(void *aClosure) {
  181     mClosures.AppendElement(aClosure);
  182   }
  183 
  184   void RemoveClosure(void *aClosure) {
  185     mClosures.RemoveElement(aClosure);
  186   }
  187 
  188   bool HasNoClosures() {
  189     return mClosures.Length() == 0;
  190   }
  191 
  192   nsTArray<void*> mClosures;
  193 };
  194 
  195 NS_IMPL_ISUPPORTS(ValueObserver, nsIObserver)
  196 
  197 NS_IMETHODIMP
  198 ValueObserver::Observe(nsISupports     *aSubject,
  199                        const char      *aTopic,
  200                        const char16_t *aData)
  201 {
  202   NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
  203                "invalid topic");
  204   NS_ConvertUTF16toUTF8 data(aData);
  205   if (mMatchKind == Preferences::ExactMatch && !mPrefName.EqualsASCII(data.get())) {
  206     return NS_OK;
  207   }
  208   for (uint32_t i = 0; i < mClosures.Length(); i++) {
  209     mCallback(data.get(), mClosures.ElementAt(i));
  210   }
  211 
  212   return NS_OK;
  213 }
  214 
  215 struct CacheData {
  216   void* cacheLocation;
  217   union {
  218     bool defaultValueBool;
  219     int32_t defaultValueInt;
  220     uint32_t defaultValueUint;
  221     float defaultValueFloat;
  222   };
  223 };
  224 
  225 static nsTArray<nsAutoPtr<CacheData> >* gCacheData = nullptr;
  226 static nsRefPtrHashtable<ValueObserverHashKey,
  227                          ValueObserver>* gObserverTable = nullptr;
  228 
  229 #ifdef DEBUG
  230 static bool
  231 HaveExistingCacheFor(void* aPtr)
  232 {
  233   MOZ_ASSERT(NS_IsMainThread());
  234   if (gCacheData) {
  235     for (size_t i = 0, count = gCacheData->Length(); i < count; ++i) {
  236       if ((*gCacheData)[i]->cacheLocation == aPtr) {
  237         return true;
  238       }
  239     }
  240   }
  241   return false;
  242 }
  243 
  244 static void
  245 AssertNotAlreadyCached(const char* aPrefType,
  246                        const char* aPref,
  247                        void* aPtr)
  248 {
  249   if (HaveExistingCacheFor(aPtr)) {
  250     fprintf_stderr(stderr,
  251       "Attempt to add a %s pref cache for preference '%s' at address '%p'"
  252       "was made. However, a pref was already cached at this address.\n",
  253       aPrefType, aPref, aPtr);
  254     MOZ_ASSERT(false, "Should not have an existing pref cache for this address");
  255   }
  256 }
  257 #endif
  258 
  259 static void
  260 ReportToConsole(const char* aMessage, int aLine, bool aError)
  261 {
  262   nsPrintfCString message("** Preference parsing %s (line %d) = %s **\n",
  263                           (aError ? "error" : "warning"), aLine, aMessage);
  264   nsPrefBranch::ReportToConsole(NS_ConvertUTF8toUTF16(message.get()));
  265 }
  266 
  267 // Although this is a member of Preferences, it measures sPreferences and
  268 // several other global structures.
  269 /* static */ int64_t
  270 Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf)
  271 {
  272   NS_ENSURE_TRUE(InitStaticMembers(), 0);
  273 
  274   size_t n = aMallocSizeOf(sPreferences);
  275   if (gHashTable) {
  276     // pref keys are allocated in a private arena, which we count elsewhere.
  277     // pref stringvals are allocated out of the same private arena.
  278     n += gHashTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
  279   }
  280   if (gCacheData) {
  281     n += gCacheData->ShallowSizeOfIncludingThis(aMallocSizeOf);
  282     for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
  283       n += aMallocSizeOf((*gCacheData)[i]);
  284     }
  285   }
  286   if (gObserverTable) {
  287     n += gObserverTable->ShallowSizeOfIncludingThis(aMallocSizeOf);
  288     for (auto iter = gObserverTable->Iter(); !iter.Done(); iter.Next()) {
  289       n += iter.Key()->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  290       n += iter.Data()->mClosures.ShallowSizeOfExcludingThis(aMallocSizeOf);
  291     }
  292   }
  293   if (sRootBranch) {
  294     n += reinterpret_cast<nsPrefBranch*>(sRootBranch)->SizeOfIncludingThis(aMallocSizeOf);
  295   }
  296   if (sDefaultRootBranch) {
  297     n += reinterpret_cast<nsPrefBranch*>(sDefaultRootBranch)->SizeOfIncludingThis(aMallocSizeOf);
  298   }
  299   n += pref_SizeOfPrivateData(aMallocSizeOf);
  300   return n;
  301 }
  302 
  303 class PreferenceServiceReporter final : public nsIMemoryReporter
  304 {
  305   ~PreferenceServiceReporter() {}
  306 
  307 public:
  308   NS_DECL_ISUPPORTS
  309   NS_DECL_NSIMEMORYREPORTER
  310 
  311 protected:
  312   static const uint32_t kSuspectReferentCount = 1000;
  313 };
  314 
  315 NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)
  316 
  317 MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
  318 
  319 NS_IMETHODIMP
  320 PreferenceServiceReporter::CollectReports(
  321   nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
  322 {
  323   MOZ_COLLECT_REPORT(
  324     "explicit/preferences", KIND_HEAP, UNITS_BYTES,
  325     Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf),
  326     "Memory used by the preferences system.");
  327 
  328   nsPrefBranch* rootBranch =
  329     static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
  330   if (!rootBranch) {
  331     return NS_OK;
  332   }
  333 
  334   size_t numStrong = 0;
  335   size_t numWeakAlive = 0;
  336   size_t numWeakDead = 0;
  337   nsTArray<nsCString> suspectPreferences;
  338   // Count of the number of referents for each preference.
  339   nsDataHashtable<nsCStringHashKey, uint32_t> prefCounter;
  340 
  341   for (auto iter = rootBranch->mObservers.Iter(); !iter.Done(); iter.Next()) {
  342     nsAutoPtr<PrefCallback>& callback = iter.Data();
  343     nsPrefBranch* prefBranch = callback->GetPrefBranch();
  344     const char* pref = prefBranch->getPrefName(callback->GetDomain().get());
  345 
  346     if (callback->IsWeak()) {
  347       nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef);
  348       if (callbackRef) {
  349         numWeakAlive++;
  350       } else {
  351         numWeakDead++;
  352       }
  353     } else {
  354       numStrong++;
  355     }
  356 
  357     nsDependentCString prefString(pref);
  358     uint32_t oldCount = 0;
  359     prefCounter.Get(prefString, &oldCount);
  360     uint32_t currentCount = oldCount + 1;
  361     prefCounter.Put(prefString, currentCount);
  362 
  363     // Keep track of preferences that have a suspiciously large number of
  364     // referents (a symptom of a leak).
  365     if (currentCount == kSuspectReferentCount) {
  366       suspectPreferences.AppendElement(prefString);
  367     }
  368   }
  369 
  370   for (uint32_t i = 0; i < suspectPreferences.Length(); i++) {
  371     nsCString& suspect = suspectPreferences[i];
  372     uint32_t totalReferentCount = 0;
  373     prefCounter.Get(suspect, &totalReferentCount);
  374 
  375     nsPrintfCString suspectPath("preference-service-suspect/"
  376                                 "referent(pref=%s)", suspect.get());
  377 
  378     aHandleReport->Callback(
  379       /* process = */ EmptyCString(),
  380       suspectPath, KIND_OTHER, UNITS_COUNT, totalReferentCount,
  381       NS_LITERAL_CSTRING(
  382         "A preference with a suspiciously large number referents (symptom of a "
  383         "leak)."),
  384       aData);
  385   }
  386 
  387   MOZ_COLLECT_REPORT(
  388     "preference-service/referent/strong", KIND_OTHER, UNITS_COUNT,
  389     numStrong,
  390     "The number of strong referents held by the preference service.");
  391 
  392   MOZ_COLLECT_REPORT(
  393     "preference-service/referent/weak/alive", KIND_OTHER, UNITS_COUNT,
  394     numWeakAlive,
  395     "The number of weak referents held by the preference service that are "
  396     "still alive.");
  397 
  398   MOZ_COLLECT_REPORT(
  399     "preference-service/referent/weak/dead", KIND_OTHER, UNITS_COUNT,
  400     numWeakDead,
  401     "The number of weak referents held by the preference service that are "
  402     "dead.");
  403 
  404   return NS_OK;
  405 }
  406 
  407 namespace {
  408 class AddPreferencesMemoryReporterRunnable : public Runnable
  409 {
  410   NS_IMETHOD Run() override
  411   {
  412     return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
  413   }
  414 };
  415 } // namespace
  416 
  417 // static
  418 Preferences*
  419 Preferences::GetInstanceForService()
  420 {
  421   if (sPreferences) {
  422     NS_ADDREF(sPreferences);
  423     return sPreferences;
  424   }
  425 
  426   NS_ENSURE_TRUE(!sShutdown, nullptr);
  427 
  428   sRootBranch = new nsPrefBranch("", false);
  429   NS_ADDREF(sRootBranch);
  430   sDefaultRootBranch = new nsPrefBranch("", true);
  431   NS_ADDREF(sDefaultRootBranch);
  432 
  433   sPreferences = new Preferences();
  434   NS_ADDREF(sPreferences);
  435 
  436   if (NS_FAILED(sPreferences->Init())) {
  437     // The singleton instance will delete sRootBranch and sDefaultRootBranch.
  438     NS_RELEASE(sPreferences);
  439     return nullptr;
  440   }
  441 
  442   gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
  443 
  444   gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
  445 
  446   // Preferences::GetInstanceForService() can be called from GetService(), and
  447   // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter).  To
  448   // avoid a potential recursive GetService() call, we can't register the
  449   // memory reporter here; instead, do it off a runnable.
  450   RefPtr<AddPreferencesMemoryReporterRunnable> runnable =
  451     new AddPreferencesMemoryReporterRunnable();
  452   NS_DispatchToMainThread(runnable);
  453 
  454   NS_ADDREF(sPreferences);
  455   return sPreferences;
  456 }
  457 
  458 // static
  459 bool
  460 Preferences::IsServiceAvailable()
  461 {
  462   return !!sPreferences;
  463 }
  464 
  465 // static
  466 bool
  467 Preferences::InitStaticMembers()
  468 {
  469   MOZ_ASSERT(NS_IsMainThread());
  470 
  471   if (!sShutdown && !sPreferences) {
  472     nsCOMPtr<nsIPrefService> prefService =
  473       do_GetService(NS_PREFSERVICE_CONTRACTID);
  474   }
  475 
  476   return sPreferences != nullptr;
  477 }
  478 
  479 // static
  480 void
  481 Preferences::Shutdown()
  482 {
  483   if (!sShutdown) {
  484     sShutdown = true; // Don't create the singleton instance after here.
  485 
  486     // Don't set sPreferences to nullptr here.  The instance may be grabbed by
  487     // other modules.  The utility methods of Preferences should be available
  488     // until the singleton instance actually released.
  489     if (sPreferences) {
  490       sPreferences->Release();
  491     }
  492   }
  493 }
  494 
  495 //-----------------------------------------------------------------------------
  496 
  497 /*
  498  * Constructor/Destructor
  499  */
  500 
  501 Preferences::Preferences()
  502   : mDirty(false)
  503 {
  504 }
  505 
  506 Preferences::~Preferences()
  507 {
  508   NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?");
  509 
  510   delete gObserverTable;
  511   gObserverTable = nullptr;
  512 
  513   delete gCacheData;
  514   gCacheData = nullptr;
  515 
  516   NS_RELEASE(sRootBranch);
  517   NS_RELEASE(sDefaultRootBranch);
  518 
  519   sPreferences = nullptr;
  520 
  521   PREF_Cleanup();
  522 }
  523 
  524 
  525 /*
  526  * nsISupports Implementation
  527  */
  528 
  529 NS_IMPL_ADDREF(Preferences)
  530 NS_IMPL_RELEASE(Preferences)
  531 
  532 NS_INTERFACE_MAP_BEGIN(Preferences)
  533     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
  534     NS_INTERFACE_MAP_ENTRY(nsIPrefService)
  535     NS_INTERFACE_MAP_ENTRY(nsIObserver)
  536     NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
  537     NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
  538     NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
  539     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  540 NS_INTERFACE_MAP_END
  541 
  542 
  543 /*
  544  * nsIPrefService Implementation
  545  */
  546 
  547 nsresult
  548 Preferences::Init()
  549 {
  550   nsresult rv;
  551 
  552   PREF_SetDirtyCallback(&DirtyCallback);
  553   PREF_Init();
  554 
  555   rv = pref_InitInitialObjects();
  556   NS_ENSURE_SUCCESS(rv, rv);
  557 
  558   using mozilla::dom::ContentChild;
  559   if (XRE_IsContentProcess()) {
  560     InfallibleTArray<PrefSetting> prefs;
  561     ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
  562 
  563     // Store the array
  564     for (uint32_t i = 0; i < prefs.Length(); ++i) {
  565       pref_SetPref(prefs[i]);
  566     }
  567     return NS_OK;
  568   }
  569 
  570   nsXPIDLCString lockFileName;
  571   /*
  572    * The following is a small hack which will allow us to only load the library
  573    * which supports the netscape.cfg file if the preference is defined. We
  574    * test for the existence of the pref, set in the all.js (mozilla) or
  575    * all-ns.js (netscape 6), and if it exists we startup the pref config
  576    * category which will do the rest.
  577    */
  578 
  579   rv = PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName), false);
  580   if (NS_SUCCEEDED(rv))
  581     NS_CreateServicesFromCategory("pref-config-startup",
  582                                   static_cast<nsISupports *>(static_cast<void *>(this)),
  583                                   "pref-config-startup");    
  584 
  585   nsCOMPtr<nsIObserverService> observerService =
  586     mozilla::services::GetObserverService();
  587   if (!observerService)
  588     return NS_ERROR_FAILURE;
  589 
  590   rv = observerService->AddObserver(this, "profile-before-change", true);
  591 
  592   observerService->AddObserver(this, "load-extension-defaults", true);
  593   observerService->AddObserver(this, "suspend_process_notification", true);
  594 
  595   return(rv);
  596 }
  597 
  598 // static
  599 nsresult
  600 Preferences::ResetAndReadUserPrefs()
  601 {
  602   sPreferences->ResetUserPrefs();
  603   return sPreferences->ReadUserPrefs(nullptr);
  604 }
  605 
  606 NS_IMETHODIMP
  607 Preferences::Observe(nsISupports *aSubject, const char *aTopic,
  608                      const char16_t *someData)
  609 {
  610   if (XRE_IsContentProcess())
  611     return NS_ERROR_NOT_AVAILABLE;
  612 
  613   nsresult rv = NS_OK;
  614 
  615   if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
  616     rv = SavePrefFile(nullptr);
  617   } else if (!strcmp(aTopic, "load-extension-defaults")) {
  618     pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
  619   } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
  620     // Reload the default prefs from file.
  621     pref_InitInitialObjects();
  622   } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) {
  623     // Our process is being suspended. The OS may wake our process later,
  624     // or it may kill the process. In case our process is going to be killed
  625     // from the suspended state, we save preferences before suspending.
  626     rv = SavePrefFile(nullptr);
  627   }
  628   return rv;
  629 }
  630 
  631 
  632 NS_IMETHODIMP
  633 Preferences::ReadUserPrefs(nsIFile *aFile)
  634 {
  635   if (XRE_IsContentProcess()) {
  636     NS_ERROR("cannot load prefs from content process");
  637     return NS_ERROR_NOT_AVAILABLE;
  638   }
  639 
  640   nsresult rv;
  641 
  642   if (nullptr == aFile) {
  643     rv = UseDefaultPrefFile();
  644     // A user pref file is optional.
  645     // Ignore all errors related to it, so we retain 'rv' value :-|
  646     (void) UseUserPrefFile();
  647 
  648     // Migrate the old prerelease telemetry pref
  649     if (!Preferences::GetBool(kOldTelemetryPref, true)) {
  650       Preferences::SetBool(kTelemetryPref, false);
  651       Preferences::ClearUser(kOldTelemetryPref);
  652     }
  653 
  654     NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
  655   } else {
  656     rv = ReadAndOwnUserPrefFile(aFile);
  657   }
  658 
  659   return rv;
  660 }
  661 
  662 NS_IMETHODIMP
  663 Preferences::ResetPrefs()
  664 {
  665   if (XRE_IsContentProcess()) {
  666     NS_ERROR("cannot reset prefs from content process");
  667     return NS_ERROR_NOT_AVAILABLE;
  668   }
  669 
  670   NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
  671   PREF_CleanupPrefs();
  672 
  673   PREF_Init();
  674 
  675   return pref_InitInitialObjects();
  676 }
  677 
  678 NS_IMETHODIMP
  679 Preferences::ResetUserPrefs()
  680 {
  681   if (XRE_IsContentProcess()) {
  682     NS_ERROR("cannot reset user prefs from content process");
  683     return NS_ERROR_NOT_AVAILABLE;
  684   }
  685 
  686   PREF_ClearAllUserPrefs();
  687   return NS_OK;    
  688 }
  689 
  690 NS_IMETHODIMP
  691 Preferences::SavePrefFile(nsIFile *aFile)
  692 {
  693   if (XRE_IsContentProcess()) {
  694     NS_ERROR("cannot save pref file from content process");
  695     return NS_ERROR_NOT_AVAILABLE;
  696   }
  697 
  698   return SavePrefFileInternal(aFile);
  699 }
  700 
  701 static nsresult
  702 ReadExtensionPrefs(nsIFile *aFile)
  703 {
  704   nsresult rv;
  705   nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv);
  706   NS_ENSURE_SUCCESS(rv, rv);
  707 
  708   rv = reader->Open(aFile);
  709   NS_ENSURE_SUCCESS(rv, rv);
  710 
  711   nsCOMPtr<nsIUTF8StringEnumerator> files;
  712   rv = reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),
  713                            getter_AddRefs(files));
  714   NS_ENSURE_SUCCESS(rv, rv);
  715 
  716   char buffer[4096];
  717 
  718   bool more;
  719   while (NS_SUCCEEDED(rv = files->HasMore(&more)) && more) {
  720     nsAutoCString entry;
  721     rv = files->GetNext(entry);
  722     NS_ENSURE_SUCCESS(rv, rv);
  723 
  724     nsCOMPtr<nsIInputStream> stream;
  725     rv = reader->GetInputStream(entry, getter_AddRefs(stream));
  726     NS_ENSURE_SUCCESS(rv, rv);
  727 
  728     uint64_t avail;
  729     uint32_t read;
  730 
  731     PrefParseState ps;
  732     PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
  733     while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) {
  734       rv = stream->Read(buffer, 4096, &read);
  735       if (NS_FAILED(rv)) {
  736         NS_WARNING("Pref stream read failed");
  737         break;
  738       }
  739 
  740       PREF_ParseBuf(&ps, buffer, read);
  741     }
  742     PREF_FinalizeParseState(&ps);
  743   }
  744   return rv;
  745 }
  746 
  747 void
  748 Preferences::SetPreference(const PrefSetting& aPref)
  749 {
  750   pref_SetPref(aPref);
  751 }
  752 
  753 void
  754 Preferences::GetPreference(PrefSetting* aPref)
  755 {
  756   PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get());
  757   if (!entry)
  758     return;
  759 
  760   if (pref_EntryHasAdvisablySizedValues(entry)) {
  761     pref_GetPrefFromEntry(entry, aPref);
  762   }
  763 }
  764 
  765 void
  766 Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
  767 {
  768   aPrefs->SetCapacity(gHashTable->Capacity());
  769   for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
  770     auto entry = static_cast<PrefHashEntry*>(iter.Get());
  771 
  772     if (!pref_EntryHasAdvisablySizedValues(entry)) {
  773       continue;
  774     }
  775 
  776     dom::PrefSetting *pref = aPrefs->AppendElement();
  777     pref_GetPrefFromEntry(entry, pref);
  778   }
  779 }
  780 
  781 NS_IMETHODIMP
  782 Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
  783 {
  784   nsresult rv;
  785 
  786   if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
  787     // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
  788     RefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, false);
  789     prefBranch.forget(_retval);
  790     rv = NS_OK;
  791   } else {
  792     // special case caching the default root
  793     nsCOMPtr<nsIPrefBranch> root(sRootBranch);
  794     root.forget(_retval);
  795     rv = NS_OK;
  796   }
  797   return rv;
  798 }
  799 
  800 NS_IMETHODIMP
  801 Preferences::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
  802 {
  803   if (!aPrefRoot || !aPrefRoot[0]) {
  804     nsCOMPtr<nsIPrefBranch> root(sDefaultRootBranch);
  805     root.forget(_retval);
  806     return NS_OK;
  807   }
  808 
  809   // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
  810   RefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, true);
  811   if (!prefBranch)
  812     return NS_ERROR_OUT_OF_MEMORY;
  813 
  814   prefBranch.forget(_retval);
  815   return NS_OK;
  816 }
  817 
  818 NS_IMETHODIMP
  819 Preferences::GetDirty(bool *_retval) {
  820   *_retval = mDirty;
  821   return NS_OK;
  822 }
  823 
  824 nsresult
  825 Preferences::NotifyServiceObservers(const char *aTopic)
  826 {
  827   nsCOMPtr<nsIObserverService> observerService = 
  828     mozilla::services::GetObserverService();  
  829   if (!observerService)
  830     return NS_ERROR_FAILURE;
  831 
  832   nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
  833   observerService->NotifyObservers(subject, aTopic, nullptr);
  834   
  835   return NS_OK;
  836 }
  837 
  838 nsresult
  839 Preferences::UseDefaultPrefFile()
  840 {
  841   nsCOMPtr<nsIFile> aFile;
  842   nsresult rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
  843 
  844   if (NS_SUCCEEDED(rv)) {
  845     rv = ReadAndOwnUserPrefFile(aFile);
  846     // Most likely cause of failure here is that the file didn't
  847     // exist, so save a new one. mUserPrefReadFailed will be
  848     // used to catch an error in actually reading the file.
  849     if (NS_FAILED(rv)) {
  850       if (NS_FAILED(SavePrefFileInternal(aFile)))
  851         NS_ERROR("Failed to save new shared pref file");
  852       else
  853         rv = NS_OK;
  854     }
  855   }
  856   
  857   return rv;
  858 }
  859 
  860 nsresult
  861 Preferences::UseUserPrefFile()
  862 {
  863   nsresult rv = NS_OK;
  864   nsCOMPtr<nsIFile> aFile;
  865   nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR);
  866 
  867   rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile));
  868   if (NS_SUCCEEDED(rv) && aFile) {
  869     rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
  870     if (NS_SUCCEEDED(rv)) {
  871       bool exists = false;
  872       aFile->Exists(&exists);
  873       if (exists) {
  874         rv = openPrefFile(aFile);
  875       } else {
  876         rv = NS_ERROR_FILE_NOT_FOUND;
  877       }
  878     }
  879   }
  880   return rv;
  881 }
  882 
  883 nsresult
  884 Preferences::MakeBackupPrefFile(nsIFile *aFile)
  885 {
  886   // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
  887   // "Invalidprefs.js" is removed if it exists, prior to making the copy.
  888   nsAutoString newFilename;
  889   nsresult rv = aFile->GetLeafName(newFilename);
  890   NS_ENSURE_SUCCESS(rv, rv);
  891   newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0);
  892   nsCOMPtr<nsIFile> newFile;
  893   rv = aFile->GetParent(getter_AddRefs(newFile));
  894   NS_ENSURE_SUCCESS(rv, rv);
  895   rv = newFile->Append(newFilename);
  896   NS_ENSURE_SUCCESS(rv, rv);
  897   bool exists = false;
  898   newFile->Exists(&exists);
  899   if (exists) {
  900     rv = newFile->Remove(false);
  901     NS_ENSURE_SUCCESS(rv, rv);
  902   }
  903   rv = aFile->CopyTo(nullptr, newFilename);
  904   NS_ENSURE_SUCCESS(rv, rv);
  905   return rv;
  906 }
  907 
  908 nsresult
  909 Preferences::ReadAndOwnUserPrefFile(nsIFile *aFile)
  910 {
  911   NS_ENSURE_ARG(aFile);
  912   
  913   if (mCurrentFile == aFile)
  914     return NS_OK;
  915   mCurrentFile = aFile;
  916 
  917   nsresult rv = NS_OK;
  918   bool exists = false;
  919   mCurrentFile->Exists(&exists);
  920   if (exists) {
  921     rv = openPrefFile(mCurrentFile);
  922     if (NS_FAILED(rv)) {
  923       // Save a backup copy of the current (invalid) prefs file, since all prefs
  924       // from the error line to the end of the file will be lost (bug 361102).
  925       // TODO we should notify the user about it (bug 523725).
  926       MakeBackupPrefFile(mCurrentFile);
  927     }
  928   } else {
  929     rv = NS_ERROR_FILE_NOT_FOUND;
  930   }
  931 
  932   return rv;
  933 }
  934 
  935 nsresult
  936 Preferences::SavePrefFileInternal(nsIFile *aFile)
  937 {
  938   if (nullptr == aFile) {
  939     // the mDirty flag tells us if we should write to mCurrentFile
  940     // we only check this flag when the caller wants to write to the default
  941     if (!mDirty) {
  942       return NS_OK;
  943     }
  944 
  945     // It's possible that we never got a prefs file.
  946     nsresult rv = NS_OK;
  947     if (mCurrentFile)
  948       rv = WritePrefFile(mCurrentFile);
  949 
  950     return rv;
  951   } else {
  952     return WritePrefFile(aFile);
  953   }
  954 }
  955 
  956 nsresult
  957 Preferences::WritePrefFile(nsIFile* aFile)
  958 {
  959   nsCOMPtr<nsIOutputStream> outStreamSink;
  960   nsCOMPtr<nsIOutputStream> outStream;
  961   uint32_t                  writeAmount;
  962   nsresult                  rv;
  963 
  964   if (!gHashTable)
  965     return NS_ERROR_NOT_INITIALIZED;
  966 
  967   // execute a "safe" save by saving through a tempfile
  968   rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
  969                                        aFile,
  970                                        -1,
  971                                        0600);
  972   if (NS_FAILED(rv)) 
  973       return rv;
  974   rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
  975   if (NS_FAILED(rv)) 
  976       return rv;  
  977 
  978   // get the lines that we're supposed to be writing to the file
  979   uint32_t prefCount;
  980   UniquePtr<char*[]> valueArray = pref_savePrefs(gHashTable, &prefCount);
  981 
  982   /* Sort the preferences to make a readable file on disk */
  983   NS_QuickSort(valueArray.get(), prefCount, sizeof(char *),
  984                pref_CompareStrings, nullptr);
  985 
  986   // write out the file header
  987   outStream->Write(kPrefFileHeader, sizeof(kPrefFileHeader) - 1, &writeAmount);
  988 
  989   for (uint32_t valueIdx = 0; valueIdx < prefCount; valueIdx++) {
  990     char*& pref = valueArray[valueIdx];
  991     MOZ_ASSERT(pref);
  992     outStream->Write(pref, strlen(pref), &writeAmount);
  993     outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
  994     free(pref);
  995     pref = nullptr;
  996   }
  997 
  998   // tell the safe output stream to overwrite the real prefs file
  999   // (it'll abort if there were any errors during writing)
 1000   nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
 1001   NS_ASSERTION(safeStream, "expected a safe output stream!");
 1002   if (safeStream) {
 1003     rv = safeStream->Finish();
 1004     if (NS_FAILED(rv)) {
 1005       NS_WARNING("failed to save prefs file! possible data loss");
 1006       return rv;
 1007     }
 1008   }
 1009 
 1010   mDirty = false;
 1011   return NS_OK;
 1012 }
 1013 
 1014 static nsresult openPrefFile(nsIFile* aFile)
 1015 {
 1016   nsCOMPtr<nsIInputStream> inStr;
 1017 
 1018   nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
 1019   if (NS_FAILED(rv)) 
 1020     return rv;        
 1021 
 1022   int64_t fileSize64;
 1023   rv = aFile->GetFileSize(&fileSize64);
 1024   if (NS_FAILED(rv))
 1025     return rv;
 1026   NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
 1027 
 1028   uint32_t fileSize = (uint32_t)fileSize64;
 1029   auto fileBuffer = MakeUniqueFallible<char[]>(fileSize);
 1030   if (fileBuffer == nullptr)
 1031     return NS_ERROR_OUT_OF_MEMORY;
 1032 
 1033   PrefParseState ps;
 1034   PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
 1035 
 1036   // Read is not guaranteed to return a buf the size of fileSize,
 1037   // but usually will.
 1038   nsresult rv2 = NS_OK;
 1039   uint32_t offset = 0;
 1040   for (;;) {
 1041     uint32_t amtRead = 0;
 1042     rv = inStr->Read(fileBuffer.get(), fileSize, &amtRead);
 1043     if (NS_FAILED(rv) || amtRead == 0)
 1044       break;
 1045     if (!PREF_ParseBuf(&ps, fileBuffer.get(), amtRead))
 1046       rv2 = NS_ERROR_FILE_CORRUPTED;
 1047     offset += amtRead;
 1048     if (offset == fileSize) {
 1049       break;
 1050     }
 1051   }
 1052 
 1053   PREF_FinalizeParseState(&ps);
 1054 
 1055   return NS_FAILED(rv) ? rv : rv2;
 1056 }
 1057 
 1058 /*
 1059  * some stuff that gets called from Pref_Init()
 1060  */
 1061 
 1062 static int
 1063 pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
 1064 {
 1065   nsAutoCString filename1, filename2;
 1066   aFile1->GetNativeLeafName(filename1);
 1067   aFile2->GetNativeLeafName(filename2);
 1068 
 1069   return Compare(filename2, filename1);
 1070 }
 1071 
 1072 /**
 1073  * Load default pref files from a directory. The files in the
 1074  * directory are sorted reverse-alphabetically; a set of "special file
 1075  * names" may be specified which are loaded after all the others.
 1076  */
 1077 static nsresult
 1078 pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, uint32_t aSpecialFilesCount)
 1079 {
 1080   nsresult rv, rv2;
 1081   bool hasMoreElements;
 1082 
 1083   nsCOMPtr<nsISimpleEnumerator> dirIterator;
 1084 
 1085   // this may fail in some normal cases, such as embedders who do not use a GRE
 1086   rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
 1087   if (NS_FAILED(rv)) {
 1088     // If the directory doesn't exist, then we have no reason to complain.  We
 1089     // loaded everything (and nothing) successfully.
 1090     if (rv == NS_ERROR_FILE_NOT_FOUND || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
 1091       rv = NS_OK;
 1092     return rv;
 1093   }
 1094 
 1095   rv = dirIterator->HasMoreElements(&hasMoreElements);
 1096   NS_ENSURE_SUCCESS(rv, rv);
 1097 
 1098   nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
 1099   nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
 1100   nsCOMPtr<nsIFile> prefFile;
 1101 
 1102   while (hasMoreElements && NS_SUCCEEDED(rv)) {
 1103     nsAutoCString leafName;
 1104 
 1105     nsCOMPtr<nsISupports> supports;
 1106     rv = dirIterator->GetNext(getter_AddRefs(supports));
 1107     prefFile = do_QueryInterface(supports);
 1108     if (NS_FAILED(rv)) {
 1109       break;
 1110     }
 1111 
 1112     prefFile->GetNativeLeafName(leafName);
 1113     NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
 1114 
 1115     // Skip non-js files
 1116     if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
 1117                        nsCaseInsensitiveCStringComparator())) {
 1118       bool shouldParse = true;
 1119       // separate out special files
 1120       for (uint32_t i = 0; i < aSpecialFilesCount; ++i) {
 1121         if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
 1122           shouldParse = false;
 1123           // special files should be process in order; we put them into
 1124           // the array by index; this can make the array sparse
 1125           specialFiles.ReplaceObjectAt(prefFile, i);
 1126         }
 1127       }
 1128 
 1129       if (shouldParse) {
 1130         prefFiles.AppendObject(prefFile);
 1131       }
 1132     }
 1133 
 1134     rv = dirIterator->HasMoreElements(&hasMoreElements);
 1135   }
 1136 
 1137   if (prefFiles.Count() + specialFiles.Count() == 0) {
 1138     NS_WARNING("No default pref files found.");
 1139     if (NS_SUCCEEDED(rv)) {
 1140       rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
 1141     }
 1142     return rv;
 1143   }
 1144 
 1145   prefFiles.Sort(pref_CompareFileNames, nullptr);
 1146   
 1147   uint32_t arrayCount = prefFiles.Count();
 1148   uint32_t i;
 1149   for (i = 0; i < arrayCount; ++i) {
 1150     rv2 = openPrefFile(prefFiles[i]);
 1151     if (NS_FAILED(rv2)) {
 1152       NS_ERROR("Default pref file not parsed successfully.");
 1153       rv = rv2;
 1154     }
 1155   }
 1156 
 1157   arrayCount = specialFiles.Count();
 1158   for (i = 0; i < arrayCount; ++i) {
 1159     // this may be a sparse array; test before parsing
 1160     nsIFile* file = specialFiles[i];
 1161     if (file) {
 1162       rv2 = openPrefFile(file);
 1163       if (NS_FAILED(rv2)) {
 1164         NS_ERROR("Special default pref file not parsed successfully.");
 1165         rv = rv2;
 1166       }
 1167     }
 1168   }
 1169 
 1170   return rv;
 1171 }
 1172 
 1173 static nsresult pref_LoadPrefsInDirList(const char *listId)
 1174 {
 1175   nsresult rv;
 1176   nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
 1177   if (NS_FAILED(rv))
 1178     return rv;
 1179 
 1180   nsCOMPtr<nsISimpleEnumerator> list;
 1181   dirSvc->Get(listId,
 1182               NS_GET_IID(nsISimpleEnumerator),
 1183               getter_AddRefs(list));
 1184   if (!list)
 1185     return NS_OK;
 1186 
 1187   bool hasMore;
 1188   while (NS_SUCCEEDED(list->HasMoreElements(&hasMore)) && hasMore) {
 1189     nsCOMPtr<nsISupports> elem;
 1190     list->GetNext(getter_AddRefs(elem));
 1191     if (!elem)
 1192       continue;
 1193 
 1194     nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
 1195     if (!path)
 1196       continue;
 1197 
 1198     nsAutoCString leaf;
 1199     path->GetNativeLeafName(leaf);
 1200 
 1201     // Do we care if a file provided by this process fails to load?
 1202     if (Substring(leaf, leaf.Length() - 4).EqualsLiteral(".xpi"))
 1203       ReadExtensionPrefs(path);
 1204     else
 1205       pref_LoadPrefsInDir(path, nullptr, 0);
 1206   }
 1207   return NS_OK;
 1208 }
 1209 
 1210 static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
 1211 {
 1212   nsZipItemPtr<char> manifest(jarReader, name, true);
 1213   NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
 1214 
 1215   PrefParseState ps;
 1216   PREF_InitParseState(&ps, PREF_ReaderCallback, ReportToConsole, nullptr);
 1217   PREF_ParseBuf(&ps, manifest, manifest.Length());
 1218   PREF_FinalizeParseState(&ps);
 1219 
 1220   return NS_OK;
 1221 }
 1222 
 1223 //----------------------------------------------------------------------------------------
 1224 // Initialize default preference JavaScript buffers from
 1225 // appropriate TEXT resources
 1226 //----------------------------------------------------------------------------------------
 1227 static nsresult pref_InitInitialObjects()
 1228 {
 1229   nsresult rv;
 1230 
 1231   // In omni.jar case, we load the following prefs:
 1232   // - jar:$gre/omni.jar!/greprefs.js
 1233   // - jar:$gre/omni.jar!/defaults/pref/*.js
 1234   // In non omni.jar case, we load:
 1235   // - $gre/greprefs.js
 1236   //
 1237   // In both cases, we also load:
 1238   // - $gre/defaults/pref/*.js
 1239   // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
 1240   // on $app == $gre case ; we load all files instead of channel-prefs.js only
 1241   // to have the same behaviour as $app != $gre, where this is required as
 1242   // a supported location for GRE preferences.
 1243   //
 1244   // When $app != $gre, we additionally load, in omni.jar case:
 1245   // - jar:$app/omni.jar!/defaults/preferences/*.js
 1246   // - $app/defaults/preferences/*.js
 1247   // and in non omni.jar case:
 1248   // - $app/defaults/preferences/*.js
 1249   // When $app == $gre, we additionally load, in omni.jar case:
 1250   // - jar:$gre/omni.jar!/defaults/preferences/*.js
 1251   // Thus, in omni.jar case, we always load app-specific default preferences
 1252   // from omni.jar, whether or not $app == $gre.
 1253 
 1254   nsZipFind *findPtr;
 1255   nsAutoPtr<nsZipFind> find;
 1256   nsTArray<nsCString> prefEntries;
 1257   const char *entryName;
 1258   uint16_t entryNameLen;
 1259 
 1260   RefPtr<nsZipArchive> jarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
 1261   if (jarReader) {
 1262     // Load jar:$gre/omni.jar!/greprefs.js
 1263     rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
 1264     NS_ENSURE_SUCCESS(rv, rv);
 1265 
 1266     // Load jar:$gre/omni.jar!/defaults/pref/*.js
 1267     rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr);
 1268     NS_ENSURE_SUCCESS(rv, rv);
 1269 
 1270     find = findPtr;
 1271     while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
 1272       prefEntries.AppendElement(Substring(entryName, entryNameLen));
 1273     }
 1274 
 1275     prefEntries.Sort();
 1276     for (uint32_t i = prefEntries.Length(); i--; ) {
 1277       rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
 1278       if (NS_FAILED(rv))
 1279         NS_WARNING("Error parsing preferences.");
 1280     }
 1281   } else {
 1282     // Load $gre/greprefs.js
 1283     nsCOMPtr<nsIFile> greprefsFile;
 1284     rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greprefsFile));
 1285     NS_ENSURE_SUCCESS(rv, rv);
 1286 
 1287     rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
 1288     NS_ENSURE_SUCCESS(rv, rv);
 1289 
 1290     rv = openPrefFile(greprefsFile);
 1291     if (NS_FAILED(rv))
 1292       NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
 1293   }
 1294 
 1295   // Load $gre/defaults/pref/*.js
 1296   nsCOMPtr<nsIFile> defaultPrefDir;
 1297 
 1298   rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
 1299   NS_ENSURE_SUCCESS(rv, rv);
 1300 
 1301   /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
 1302   static const char* specialFiles[] = {
 1303 #if defined(XP_MACOSX)
 1304     "macprefs.js"
 1305 #elif defined(XP_WIN)
 1306     "winpref.js"
 1307 #elif defined(XP_UNIX)
 1308     "unix.js"
 1309 #endif
 1310   };
 1311 
 1312   rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
 1313   if (NS_FAILED(rv))
 1314     NS_WARNING("Error parsing application default preferences.");
 1315 
 1316   // Load jar:$app/omni.jar!/defaults/preferences/*.js
 1317   // or jar:$gre/omni.jar!/defaults/preferences/*.js.
 1318   RefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
 1319   // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
 1320   // case we look for app-specific default preferences in $gre.
 1321   if (!appJarReader)
 1322     appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
 1323   if (appJarReader) {
 1324     rv = appJarReader->FindInit("defaults/preferences/*.js$", &findPtr);
 1325     NS_ENSURE_SUCCESS(rv, rv);
 1326     find = findPtr;
 1327     prefEntries.Clear();
 1328     while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
 1329       prefEntries.AppendElement(Substring(entryName, entryNameLen));
 1330     }
 1331     prefEntries.Sort();
 1332     for (uint32_t i = prefEntries.Length(); i--; ) {
 1333       rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
 1334       if (NS_FAILED(rv))
 1335         NS_WARNING("Error parsing preferences.");
 1336     }
 1337   }
 1338 
 1339   rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
 1340   NS_ENSURE_SUCCESS(rv, rv);
 1341 
 1342   // Set up the correct default for toolkit.telemetry.enabled.
 1343   // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta
 1344   // channel, telemetry is on by default, otherwise not. This is necessary
 1345   // so that beta users who are testing final release builds don't flipflop
 1346   // defaults.
 1347   if (Preferences::GetDefaultType(kTelemetryPref) == nsIPrefBranch::PREF_INVALID) {
 1348     bool prerelease = false;
 1349 #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
 1350     prerelease = true;
 1351 #else
 1352     if (Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")) {
 1353       prerelease = true;
 1354     }
 1355 #endif
 1356     PREF_SetBoolPref(kTelemetryPref, prerelease, true);
 1357   }
 1358 
 1359   NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
 1360                                 nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
 1361 
 1362   nsCOMPtr<nsIObserverService> observerService =
 1363     mozilla::services::GetObserverService();
 1364   if (!observerService)
 1365     return NS_ERROR_FAILURE;
 1366 
 1367   observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr);
 1368 
 1369   return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
 1370 }
 1371 
 1372 
 1373 /******************************************************************************
 1374  *
 1375  * static utilities
 1376  *
 1377  ******************************************************************************/
 1378 
 1379 // static
 1380 nsresult
 1381 Preferences::GetBool(const char* aPref, bool* aResult)
 1382 {
 1383   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1384   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1385   return PREF_GetBoolPref(aPref, aResult, false);
 1386 }
 1387 
 1388 // static
 1389 nsresult
 1390 Preferences::GetInt(const char* aPref, int32_t* aResult)
 1391 {
 1392   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1393   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1394   return PREF_GetIntPref(aPref, aResult, false);
 1395 }
 1396 
 1397 // static
 1398 nsresult
 1399 Preferences::GetFloat(const char* aPref, float* aResult)
 1400 {
 1401   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1402   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1403   nsAutoCString result;
 1404   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
 1405   if (NS_SUCCEEDED(rv)) {
 1406     *aResult = result.ToFloat(&rv);
 1407   }
 1408 
 1409   return rv;
 1410 }
 1411 
 1412 // static
 1413 nsAdoptingCString
 1414 Preferences::GetCString(const char* aPref)
 1415 {
 1416   nsAdoptingCString result;
 1417   PREF_CopyCharPref(aPref, getter_Copies(result), false);
 1418   return result;
 1419 }
 1420 
 1421 // static
 1422 nsAdoptingString
 1423 Preferences::GetString(const char* aPref)
 1424 {
 1425   nsAdoptingString result;
 1426   GetString(aPref, &result);
 1427   return result;
 1428 }
 1429 
 1430 // static
 1431 nsresult
 1432 Preferences::GetCString(const char* aPref, nsACString* aResult)
 1433 {
 1434   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1435   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1436   nsAutoCString result;
 1437   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
 1438   if (NS_SUCCEEDED(rv)) {
 1439     *aResult = result;
 1440   }
 1441   return rv;
 1442 }
 1443 
 1444 // static
 1445 nsresult
 1446 Preferences::GetString(const char* aPref, nsAString* aResult)
 1447 {
 1448   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1449   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1450   nsAutoCString result;
 1451   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
 1452   if (NS_SUCCEEDED(rv)) {
 1453     CopyUTF8toUTF16(result, *aResult);
 1454   }
 1455   return rv;
 1456 }
 1457 
 1458 // static
 1459 nsAdoptingCString
 1460 Preferences::GetLocalizedCString(const char* aPref)
 1461 {
 1462   nsAdoptingCString result;
 1463   GetLocalizedCString(aPref, &result);
 1464   return result;
 1465 }
 1466 
 1467 // static
 1468 nsAdoptingString
 1469 Preferences::GetLocalizedString(const char* aPref)
 1470 {
 1471   nsAdoptingString result;
 1472   GetLocalizedString(aPref, &result);
 1473   return result;
 1474 }
 1475 
 1476 // static
 1477 nsresult
 1478 Preferences::GetLocalizedCString(const char* aPref, nsACString* aResult)
 1479 {
 1480   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1481   nsAutoString result;
 1482   nsresult rv = GetLocalizedString(aPref, &result);
 1483   if (NS_SUCCEEDED(rv)) {
 1484     CopyUTF16toUTF8(result, *aResult);
 1485   }
 1486   return rv;
 1487 }
 1488 
 1489 // static
 1490 nsresult
 1491 Preferences::GetLocalizedString(const char* aPref, nsAString* aResult)
 1492 {
 1493   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1494   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1495   nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
 1496   nsresult rv = sRootBranch->GetComplexValue(aPref,
 1497                                              NS_GET_IID(nsIPrefLocalizedString),
 1498                                              getter_AddRefs(prefLocalString));
 1499   if (NS_SUCCEEDED(rv)) {
 1500     NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
 1501     prefLocalString->GetData(getter_Copies(*aResult));
 1502   }
 1503   return rv;
 1504 }
 1505 
 1506 // static
 1507 nsresult
 1508 Preferences::GetComplex(const char* aPref, const nsIID &aType, void** aResult)
 1509 {
 1510   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1511   return sRootBranch->GetComplexValue(aPref, aType, aResult);
 1512 }
 1513 
 1514 // static
 1515 nsresult
 1516 Preferences::SetCString(const char* aPref, const char* aValue)
 1517 {
 1518   ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
 1519   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1520   return PREF_SetCharPref(aPref, aValue, false);
 1521 }
 1522 
 1523 // static
 1524 nsresult
 1525 Preferences::SetCString(const char* aPref, const nsACString &aValue)
 1526 {
 1527   ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
 1528   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1529   return PREF_SetCharPref(aPref, PromiseFlatCString(aValue).get(), false);
 1530 }
 1531 
 1532 // static
 1533 nsresult
 1534 Preferences::SetString(const char* aPref, const char16ptr_t aValue)
 1535 {
 1536   ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
 1537   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1538   return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
 1539 }
 1540 
 1541 // static
 1542 nsresult
 1543 Preferences::SetString(const char* aPref, const nsAString &aValue)
 1544 {
 1545   ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
 1546   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1547   return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
 1548 }
 1549 
 1550 // static
 1551 nsresult
 1552 Preferences::SetBool(const char* aPref, bool aValue)
 1553 {
 1554   ENSURE_MAIN_PROCESS("Cannot SetBool from content process:", aPref);
 1555   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1556   return PREF_SetBoolPref(aPref, aValue, false);
 1557 }
 1558 
 1559 // static
 1560 nsresult
 1561 Preferences::SetInt(const char* aPref, int32_t aValue)
 1562 {
 1563   ENSURE_MAIN_PROCESS("Cannot SetInt from content process:", aPref);
 1564   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1565   return PREF_SetIntPref(aPref, aValue, false);
 1566 }
 1567 
 1568 // static
 1569 nsresult
 1570 Preferences::SetFloat(const char* aPref, float aValue)
 1571 {
 1572   return SetCString(aPref, nsPrintfCString("%f", aValue).get());
 1573 }
 1574 
 1575 // static
 1576 nsresult
 1577 Preferences::SetComplex(const char* aPref, const nsIID &aType,
 1578                         nsISupports* aValue)
 1579 {
 1580   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1581   return sRootBranch->SetComplexValue(aPref, aType, aValue);
 1582 }
 1583 
 1584 // static
 1585 nsresult
 1586 Preferences::ClearUser(const char* aPref)
 1587 {
 1588   ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:", aPref);
 1589   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1590   return PREF_ClearUserPref(aPref);
 1591 }
 1592 
 1593 // static
 1594 bool
 1595 Preferences::HasUserValue(const char* aPref)
 1596 {
 1597   NS_ENSURE_TRUE(InitStaticMembers(), false);
 1598   return PREF_HasUserPref(aPref);
 1599 }
 1600 
 1601 // static
 1602 int32_t
 1603 Preferences::GetType(const char* aPref)
 1604 {
 1605   NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
 1606   int32_t result;
 1607   return NS_SUCCEEDED(sRootBranch->GetPrefType(aPref, &result)) ?
 1608     result : nsIPrefBranch::PREF_INVALID;
 1609 }
 1610 
 1611 // static
 1612 nsresult
 1613 Preferences::AddStrongObserver(nsIObserver* aObserver,
 1614                                const char* aPref)
 1615 {
 1616   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1617   return sRootBranch->AddObserver(aPref, aObserver, false);
 1618 }
 1619 
 1620 // static
 1621 nsresult
 1622 Preferences::AddWeakObserver(nsIObserver* aObserver,
 1623                              const char* aPref)
 1624 {
 1625   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1626   return sRootBranch->AddObserver(aPref, aObserver, true);
 1627 }
 1628 
 1629 // static
 1630 nsresult
 1631 Preferences::RemoveObserver(nsIObserver* aObserver,
 1632                             const char* aPref)
 1633 {
 1634   if (!sPreferences && sShutdown) {
 1635     return NS_OK; // Observers have been released automatically.
 1636   }
 1637   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
 1638   return sRootBranch->RemoveObserver(aPref, aObserver);
 1639 }
 1640 
 1641 // static
 1642 nsresult
 1643 Preferences::AddStrongObservers(nsIObserver* aObserver,
 1644                                 const char** aPrefs)
 1645 {
 1646   for (uint32_t i = 0; aPrefs[i]; i++) {
 1647     nsresult rv = AddStrongObserver(aObserver, aPrefs[i]);
 1648     NS_ENSURE_SUCCESS(rv, rv);
 1649   }
 1650   return NS_OK;
 1651 }
 1652 
 1653 // static
 1654 nsresult
 1655 Preferences::AddWeakObservers(nsIObserver* aObserver,
 1656                               const char** aPrefs)
 1657 {
 1658   for (uint32_t i = 0; aPrefs[i]; i++) {
 1659     nsresult rv = AddWeakObserver(aObserver, aPrefs[i]);
 1660     NS_ENSURE_SUCCESS(rv, rv);
 1661   }
 1662   return NS_OK;
 1663 }
 1664 
 1665 // static
 1666 nsresult
 1667 Preferences::RemoveObservers(nsIObserver* aObserver,
 1668                              const char** aPrefs)
 1669 {
 1670   if (!sPreferences && sShutdown) {
 1671     return NS_OK; // Observers have been released automatically.
 1672   }
 1673   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
 1674 
 1675   for (uint32_t i = 0; aPrefs[i]; i++) {
 1676     nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
 1677     NS_ENSURE_SUCCESS(rv, rv);
 1678   }
 1679   return NS_OK;
 1680 }
 1681 
 1682 // static
 1683 nsresult
 1684 Preferences::RegisterCallback(PrefChangedFunc aCallback,
 1685                               const char* aPref,
 1686                               void* aClosure,
 1687                               MatchKind aMatchKind)
 1688 {
 1689   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1690 
 1691   ValueObserverHashKey hashKey(aPref, aCallback, aMatchKind);
 1692   RefPtr<ValueObserver> observer;
 1693   gObserverTable->Get(&hashKey, getter_AddRefs(observer));
 1694   if (observer) {
 1695     observer->AppendClosure(aClosure);
 1696     return NS_OK;
 1697   }
 1698 
 1699   observer = new ValueObserver(aPref, aCallback, aMatchKind);
 1700   observer->AppendClosure(aClosure);
 1701   nsresult rv = AddStrongObserver(observer, aPref);
 1702   NS_ENSURE_SUCCESS(rv, rv);
 1703   gObserverTable->Put(observer, observer);
 1704   return NS_OK;
 1705 }
 1706 
 1707 // static
 1708 nsresult
 1709 Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
 1710                                      const char* aPref,
 1711                                      void* aClosure,
 1712                                      MatchKind aMatchKind)
 1713 {
 1714   nsresult rv = RegisterCallback(aCallback, aPref, aClosure, aMatchKind);
 1715   if (NS_SUCCEEDED(rv)) {
 1716     (*aCallback)(aPref, aClosure);
 1717   }
 1718   return rv;
 1719 }
 1720 
 1721 // static
 1722 nsresult
 1723 Preferences::UnregisterCallback(PrefChangedFunc aCallback,
 1724                                 const char* aPref,
 1725                                 void* aClosure,
 1726                                 MatchKind aMatchKind)
 1727 {
 1728   if (!sPreferences && sShutdown) {
 1729     return NS_OK; // Observers have been released automatically.
 1730   }
 1731   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
 1732 
 1733   ValueObserverHashKey hashKey(aPref, aCallback, aMatchKind);
 1734   RefPtr<ValueObserver> observer;
 1735   gObserverTable->Get(&hashKey, getter_AddRefs(observer));
 1736   if (!observer) {
 1737     return NS_OK;
 1738   }
 1739 
 1740   observer->RemoveClosure(aClosure);
 1741   if (observer->HasNoClosures()) {
 1742     // Delete the callback since its list of closures is empty.
 1743     gObserverTable->Remove(observer);
 1744   }
 1745   return NS_OK;
 1746 }
 1747 
 1748 static void BoolVarChanged(const char* aPref, void* aClosure)
 1749 {
 1750   CacheData* cache = static_cast<CacheData*>(aClosure);
 1751   *((bool*)cache->cacheLocation) =
 1752     Preferences::GetBool(aPref, cache->defaultValueBool);
 1753 }
 1754 
 1755 // static
 1756 nsresult
 1757 Preferences::AddBoolVarCache(bool* aCache,
 1758                              const char* aPref,
 1759                              bool aDefault)
 1760 {
 1761   NS_ASSERTION(aCache, "aCache must not be NULL");
 1762 #ifdef DEBUG
 1763   AssertNotAlreadyCached("bool", aPref, aCache);
 1764 #endif
 1765   *aCache = GetBool(aPref, aDefault);
 1766   CacheData* data = new CacheData();
 1767   data->cacheLocation = aCache;
 1768   data->defaultValueBool = aDefault;
 1769   gCacheData->AppendElement(data);
 1770   return RegisterCallback(BoolVarChanged, aPref, data, ExactMatch);
 1771 }
 1772 
 1773 static void IntVarChanged(const char* aPref, void* aClosure)
 1774 {
 1775   CacheData* cache = static_cast<CacheData*>(aClosure);
 1776   *((int32_t*)cache->cacheLocation) =
 1777     Preferences::GetInt(aPref, cache->defaultValueInt);
 1778 }
 1779 
 1780 // static
 1781 nsresult
 1782 Preferences::AddIntVarCache(int32_t* aCache,
 1783                             const char* aPref,
 1784                             int32_t aDefault)
 1785 {
 1786   NS_ASSERTION(aCache, "aCache must not be NULL");
 1787 #ifdef DEBUG
 1788   AssertNotAlreadyCached("int", aPref, aCache);
 1789 #endif
 1790   *aCache = Preferences::GetInt(aPref, aDefault);
 1791   CacheData* data = new CacheData();
 1792   data->cacheLocation = aCache;
 1793   data->defaultValueInt = aDefault;
 1794   gCacheData->AppendElement(data);
 1795   return RegisterCallback(IntVarChanged, aPref, data, ExactMatch);
 1796 }
 1797 
 1798 static void UintVarChanged(const char* aPref, void* aClosure)
 1799 {
 1800   CacheData* cache = static_cast<CacheData*>(aClosure);
 1801   *((uint32_t*)cache->cacheLocation) =
 1802     Preferences::GetUint(aPref, cache->defaultValueUint);
 1803 }
 1804 
 1805 // static
 1806 nsresult
 1807 Preferences::AddUintVarCache(uint32_t* aCache,
 1808                              const char* aPref,
 1809                              uint32_t aDefault)
 1810 {
 1811   NS_ASSERTION(aCache, "aCache must not be NULL");
 1812 #ifdef DEBUG
 1813   AssertNotAlreadyCached("uint", aPref, aCache);
 1814 #endif
 1815   *aCache = Preferences::GetUint(aPref, aDefault);
 1816   CacheData* data = new CacheData();
 1817   data->cacheLocation = aCache;
 1818   data->defaultValueUint = aDefault;
 1819   gCacheData->AppendElement(data);
 1820   return RegisterCallback(UintVarChanged, aPref, data, ExactMatch);
 1821 }
 1822 
 1823 template <MemoryOrdering Order>
 1824 static void AtomicUintVarChanged(const char* aPref, void* aClosure)
 1825 {
 1826   CacheData* cache = static_cast<CacheData*>(aClosure);
 1827   *((Atomic<uint32_t, Order>*)cache->cacheLocation) =
 1828     Preferences::GetUint(aPref, cache->defaultValueUint);
 1829 }
 1830 
 1831 template <MemoryOrdering Order>
 1832 // static
 1833 nsresult
 1834 Preferences::AddAtomicUintVarCache(Atomic<uint32_t, Order>* aCache,
 1835                                    const char* aPref,
 1836                                    uint32_t aDefault)
 1837 {
 1838   NS_ASSERTION(aCache, "aCache must not be NULL");
 1839 #ifdef DEBUG
 1840   AssertNotAlreadyCached("uint", aPref, aCache);
 1841 #endif
 1842   *aCache = Preferences::GetUint(aPref, aDefault);
 1843   CacheData* data = new CacheData();
 1844   data->cacheLocation = aCache;
 1845   data->defaultValueUint = aDefault;
 1846   gCacheData->AppendElement(data);
 1847   return RegisterCallback(AtomicUintVarChanged<Order>, aPref, data, ExactMatch);
 1848 }
 1849 
 1850 // Since the definition of this template function is not in a header file,
 1851 // we need to explicitly specify the instantiations that are required.
 1852 // Currently only the order=Relaxed variant is needed.
 1853 template
 1854 nsresult Preferences::AddAtomicUintVarCache(Atomic<uint32_t,Relaxed>*,
 1855                                             const char*, uint32_t);
 1856 
 1857 static void FloatVarChanged(const char* aPref, void* aClosure)
 1858 {
 1859   CacheData* cache = static_cast<CacheData*>(aClosure);
 1860   *((float*)cache->cacheLocation) =
 1861     Preferences::GetFloat(aPref, cache->defaultValueFloat);
 1862 }
 1863 
 1864 // static
 1865 nsresult
 1866 Preferences::AddFloatVarCache(float* aCache,
 1867                              const char* aPref,
 1868                              float aDefault)
 1869 {
 1870   NS_ASSERTION(aCache, "aCache must not be NULL");
 1871 #ifdef DEBUG
 1872   AssertNotAlreadyCached("float", aPref, aCache);
 1873 #endif
 1874   *aCache = Preferences::GetFloat(aPref, aDefault);
 1875   CacheData* data = new CacheData();
 1876   data->cacheLocation = aCache;
 1877   data->defaultValueFloat = aDefault;
 1878   gCacheData->AppendElement(data);
 1879   return RegisterCallback(FloatVarChanged, aPref, data, ExactMatch);
 1880 }
 1881 
 1882 // static
 1883 nsresult
 1884 Preferences::GetDefaultBool(const char* aPref, bool* aResult)
 1885 {
 1886   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1887   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1888   return PREF_GetBoolPref(aPref, aResult, true);
 1889 }
 1890 
 1891 // static
 1892 nsresult
 1893 Preferences::GetDefaultInt(const char* aPref, int32_t* aResult)
 1894 {
 1895   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1896   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1897   return PREF_GetIntPref(aPref, aResult, true);
 1898 }
 1899 
 1900 // static
 1901 nsresult
 1902 Preferences::GetDefaultCString(const char* aPref, nsACString* aResult)
 1903 {
 1904   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1905   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1906   nsAutoCString result;
 1907   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
 1908   if (NS_SUCCEEDED(rv)) {
 1909     *aResult = result;
 1910   }
 1911   return rv;
 1912 }
 1913 
 1914 // static
 1915 nsresult
 1916 Preferences::GetDefaultString(const char* aPref, nsAString* aResult)
 1917 {
 1918   NS_PRECONDITION(aResult, "aResult must not be NULL");
 1919   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1920   nsAutoCString result;
 1921   nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
 1922   if (NS_SUCCEEDED(rv)) {
 1923     CopyUTF8toUTF16(result, *aResult);
 1924   }
 1925   return rv;
 1926 }
 1927 
 1928 // static
 1929 nsresult
 1930 Preferences::GetDefaultLocalizedCString(const char* aPref,
 1931                                         nsACString* aResult)
 1932 {
 1933   nsAutoString result;
 1934   nsresult rv = GetDefaultLocalizedString(aPref, &result);
 1935   if (NS_SUCCEEDED(rv)) {
 1936     CopyUTF16toUTF8(result, *aResult);
 1937   }
 1938   return rv;
 1939 }
 1940 
 1941 // static
 1942 nsresult
 1943 Preferences::GetDefaultLocalizedString(const char* aPref,
 1944                                        nsAString* aResult)
 1945 {
 1946   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 1947   nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
 1948   nsresult rv =
 1949     sDefaultRootBranch->GetComplexValue(aPref,
 1950                                         NS_GET_IID(nsIPrefLocalizedString),
 1951                                         getter_AddRefs(prefLocalString));
 1952   if (NS_SUCCEEDED(rv)) {
 1953     NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
 1954     prefLocalString->GetData(getter_Copies(*aResult));
 1955   }
 1956   return rv;
 1957 }
 1958 
 1959 // static
 1960 nsAdoptingString
 1961 Preferences::GetDefaultString(const char* aPref)
 1962 {
 1963   nsAdoptingString result;
 1964   GetDefaultString(aPref, &result);
 1965   return result;
 1966 }
 1967 
 1968 // static
 1969 nsAdoptingCString
 1970 Preferences::GetDefaultCString(const char* aPref)
 1971 {
 1972   nsAdoptingCString result;
 1973   PREF_CopyCharPref(aPref, getter_Copies(result), true);
 1974   return result;
 1975 }
 1976 
 1977 // static
 1978 nsAdoptingString
 1979 Preferences::GetDefaultLocalizedString(const char* aPref)
 1980 {
 1981   nsAdoptingString result;
 1982   GetDefaultLocalizedString(aPref, &result);
 1983   return result;
 1984 }
 1985 
 1986 // static
 1987 nsAdoptingCString
 1988 Preferences::GetDefaultLocalizedCString(const char* aPref)
 1989 {
 1990   nsAdoptingCString result;
 1991   GetDefaultLocalizedCString(aPref, &result);
 1992   return result;
 1993 }
 1994 
 1995 // static
 1996 nsresult
 1997 Preferences::GetDefaultComplex(const char* aPref, const nsIID &aType,
 1998                                void** aResult)
 1999 {
 2000   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 2001   return sDefaultRootBranch->GetComplexValue(aPref, aType, aResult);
 2002 }
 2003 
 2004 // static
 2005 int32_t
 2006 Preferences::GetDefaultType(const char* aPref)
 2007 {
 2008   NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
 2009   int32_t result;
 2010   return NS_SUCCEEDED(sDefaultRootBranch->GetPrefType(aPref, &result)) ?
 2011     result : nsIPrefBranch::PREF_INVALID;
 2012 }
 2013 
 2014 } // namespace mozilla
 2015 
 2016 #undef ENSURE_MAIN_PROCESS