modules/libpref/src/Preferences.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/modules/libpref/src/Preferences.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1929 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "mozilla/MemoryReporting.h"
    1.11 +#include "mozilla/dom/ContentChild.h"
    1.12 +
    1.13 +#include "mozilla/ArrayUtils.h"
    1.14 +#include "mozilla/Attributes.h"
    1.15 +#include "mozilla/HashFunctions.h"
    1.16 +
    1.17 +#include "nsXULAppAPI.h"
    1.18 +
    1.19 +#include "mozilla/Preferences.h"
    1.20 +#include "nsAppDirectoryServiceDefs.h"
    1.21 +#include "nsDataHashtable.h"
    1.22 +#include "nsDirectoryServiceDefs.h"
    1.23 +#include "nsICategoryManager.h"
    1.24 +#include "nsCategoryManagerUtils.h"
    1.25 +#include "nsNetUtil.h"
    1.26 +#include "nsIFile.h"
    1.27 +#include "nsIInputStream.h"
    1.28 +#include "nsIObserverService.h"
    1.29 +#include "nsIStringEnumerator.h"
    1.30 +#include "nsIZipReader.h"
    1.31 +#include "nsPrefBranch.h"
    1.32 +#include "nsXPIDLString.h"
    1.33 +#include "nsCRT.h"
    1.34 +#include "nsCOMArray.h"
    1.35 +#include "nsXPCOMCID.h"
    1.36 +#include "nsAutoPtr.h"
    1.37 +#include "nsPrintfCString.h"
    1.38 +
    1.39 +#include "nsQuickSort.h"
    1.40 +#include "pldhash.h"
    1.41 +
    1.42 +#include "prefapi.h"
    1.43 +#include "prefread.h"
    1.44 +#include "prefapi_private_data.h"
    1.45 +
    1.46 +#include "mozilla/Omnijar.h"
    1.47 +#include "nsZipArchive.h"
    1.48 +
    1.49 +#include "nsTArray.h"
    1.50 +#include "nsRefPtrHashtable.h"
    1.51 +#include "nsIMemoryReporter.h"
    1.52 +#include "nsThreadUtils.h"
    1.53 +
    1.54 +#ifdef DEBUG
    1.55 +#define ENSURE_MAIN_PROCESS(message, pref) do {                                \
    1.56 +  if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) {        \
    1.57 +    nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref);   \
    1.58 +    NS_WARNING(msg.get());                                                     \
    1.59 +    return NS_ERROR_NOT_AVAILABLE;                                             \
    1.60 +  }                                                                            \
    1.61 +} while (0);
    1.62 +#else
    1.63 +#define ENSURE_MAIN_PROCESS(message, pref)                                     \
    1.64 +  if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) {        \
    1.65 +    return NS_ERROR_NOT_AVAILABLE;                                             \
    1.66 +  }
    1.67 +#endif
    1.68 +
    1.69 +class PrefCallback;
    1.70 +
    1.71 +namespace mozilla {
    1.72 +
    1.73 +// Definitions
    1.74 +#define INITIAL_PREF_FILES 10
    1.75 +static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
    1.76 +
    1.77 +// Prototypes
    1.78 +static nsresult openPrefFile(nsIFile* aFile);
    1.79 +static nsresult pref_InitInitialObjects(void);
    1.80 +static nsresult pref_LoadPrefsInDirList(const char *listId);
    1.81 +static nsresult ReadExtensionPrefs(nsIFile *aFile);
    1.82 +
    1.83 +static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
    1.84 +static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease";
    1.85 +static const char kChannelPref[] = "app.update.channel";
    1.86 +
    1.87 +Preferences* Preferences::sPreferences = nullptr;
    1.88 +nsIPrefBranch* Preferences::sRootBranch = nullptr;
    1.89 +nsIPrefBranch* Preferences::sDefaultRootBranch = nullptr;
    1.90 +bool Preferences::sShutdown = false;
    1.91 +
    1.92 +class ValueObserverHashKey : public PLDHashEntryHdr {
    1.93 +public:
    1.94 +  typedef ValueObserverHashKey* KeyType;
    1.95 +  typedef const ValueObserverHashKey* KeyTypePointer;
    1.96 +
    1.97 +  static const ValueObserverHashKey* KeyToPointer(ValueObserverHashKey *aKey)
    1.98 +  {
    1.99 +    return aKey;
   1.100 +  }
   1.101 +
   1.102 +  static PLDHashNumber HashKey(const ValueObserverHashKey *aKey)
   1.103 +  {
   1.104 +    PLDHashNumber hash = HashString(aKey->mPrefName);
   1.105 +    return AddToHash(hash, aKey->mCallback);
   1.106 +  }
   1.107 +
   1.108 +  ValueObserverHashKey(const char *aPref, PrefChangedFunc aCallback) :
   1.109 +    mPrefName(aPref), mCallback(aCallback) { }
   1.110 +
   1.111 +  ValueObserverHashKey(const ValueObserverHashKey *aOther) :
   1.112 +    mPrefName(aOther->mPrefName), mCallback(aOther->mCallback)
   1.113 +  { }
   1.114 +
   1.115 +  bool KeyEquals(const ValueObserverHashKey *aOther) const
   1.116 +  {
   1.117 +    return mCallback == aOther->mCallback && mPrefName == aOther->mPrefName;
   1.118 +  }
   1.119 +
   1.120 +  ValueObserverHashKey *GetKey() const
   1.121 +  {
   1.122 +    return const_cast<ValueObserverHashKey*>(this);
   1.123 +  }
   1.124 +
   1.125 +  enum { ALLOW_MEMMOVE = true };
   1.126 +
   1.127 +  nsCString mPrefName;
   1.128 +  PrefChangedFunc mCallback;
   1.129 +};
   1.130 +
   1.131 +class ValueObserver MOZ_FINAL : public nsIObserver,
   1.132 +                                public ValueObserverHashKey
   1.133 +{
   1.134 +public:
   1.135 +  NS_DECL_ISUPPORTS
   1.136 +  NS_DECL_NSIOBSERVER
   1.137 +
   1.138 +  ValueObserver(const char *aPref, PrefChangedFunc aCallback)
   1.139 +    : ValueObserverHashKey(aPref, aCallback) { }
   1.140 +
   1.141 +  ~ValueObserver() {
   1.142 +    Preferences::RemoveObserver(this, mPrefName.get());
   1.143 +  }
   1.144 +
   1.145 +  void AppendClosure(void *aClosure) {
   1.146 +    mClosures.AppendElement(aClosure);
   1.147 +  }
   1.148 +
   1.149 +  void RemoveClosure(void *aClosure) {
   1.150 +    mClosures.RemoveElement(aClosure);
   1.151 +  }
   1.152 +
   1.153 +  bool HasNoClosures() {
   1.154 +    return mClosures.Length() == 0;
   1.155 +  }
   1.156 +
   1.157 +  nsTArray<void*> mClosures;
   1.158 +};
   1.159 +
   1.160 +NS_IMPL_ISUPPORTS(ValueObserver, nsIObserver)
   1.161 +
   1.162 +NS_IMETHODIMP
   1.163 +ValueObserver::Observe(nsISupports     *aSubject,
   1.164 +                       const char      *aTopic,
   1.165 +                       const char16_t *aData)
   1.166 +{
   1.167 +  NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
   1.168 +               "invalid topic");
   1.169 +  NS_ConvertUTF16toUTF8 data(aData);
   1.170 +  for (uint32_t i = 0; i < mClosures.Length(); i++) {
   1.171 +    mCallback(data.get(), mClosures.ElementAt(i));
   1.172 +  }
   1.173 +
   1.174 +  return NS_OK;
   1.175 +}
   1.176 +
   1.177 +struct CacheData {
   1.178 +  void* cacheLocation;
   1.179 +  union {
   1.180 +    bool defaultValueBool;
   1.181 +    int32_t defaultValueInt;
   1.182 +    uint32_t defaultValueUint;
   1.183 +    float defaultValueFloat;
   1.184 +  };
   1.185 +};
   1.186 +
   1.187 +static nsTArray<nsAutoPtr<CacheData> >* gCacheData = nullptr;
   1.188 +static nsRefPtrHashtable<ValueObserverHashKey,
   1.189 +                         ValueObserver>* gObserverTable = nullptr;
   1.190 +
   1.191 +static size_t
   1.192 +SizeOfObserverEntryExcludingThis(ValueObserverHashKey* aKey,
   1.193 +                                 const nsRefPtr<ValueObserver>& aData,
   1.194 +                                 mozilla::MallocSizeOf aMallocSizeOf,
   1.195 +                                 void*)
   1.196 +{
   1.197 +  size_t n = 0;
   1.198 +  n += aKey->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   1.199 +  n += aData->mClosures.SizeOfExcludingThis(aMallocSizeOf);
   1.200 +  return n;
   1.201 +}
   1.202 +
   1.203 +// Although this is a member of Preferences, it measures sPreferences and
   1.204 +// several other global structures.
   1.205 +/* static */ int64_t
   1.206 +Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf)
   1.207 +{
   1.208 +  NS_ENSURE_TRUE(InitStaticMembers(), 0);
   1.209 +
   1.210 +  size_t n = aMallocSizeOf(sPreferences);
   1.211 +  if (gHashTable.ops) {
   1.212 +    // pref keys are allocated in a private arena, which we count elsewhere.
   1.213 +    // pref stringvals are allocated out of the same private arena.
   1.214 +    n += PL_DHashTableSizeOfExcludingThis(&gHashTable, nullptr, aMallocSizeOf);
   1.215 +  }
   1.216 +  if (gCacheData) {
   1.217 +    n += gCacheData->SizeOfIncludingThis(aMallocSizeOf);
   1.218 +    for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
   1.219 +      n += aMallocSizeOf((*gCacheData)[i]);
   1.220 +    }
   1.221 +  }
   1.222 +  if (gObserverTable) {
   1.223 +    n += aMallocSizeOf(gObserverTable);
   1.224 +    n += gObserverTable->SizeOfExcludingThis(SizeOfObserverEntryExcludingThis,
   1.225 +                                             aMallocSizeOf);
   1.226 +  }
   1.227 +  // We don't measure sRootBranch and sDefaultRootBranch here because
   1.228 +  // DMD indicates they are not significant.
   1.229 +  n += pref_SizeOfPrivateData(aMallocSizeOf);
   1.230 +  return n;
   1.231 +}
   1.232 +
   1.233 +class PreferenceServiceReporter MOZ_FINAL : public nsIMemoryReporter
   1.234 +{
   1.235 +public:
   1.236 +  NS_DECL_ISUPPORTS
   1.237 +  NS_DECL_NSIMEMORYREPORTER
   1.238 +
   1.239 +protected:
   1.240 +  static const uint32_t kSuspectReferentCount = 1000;
   1.241 +  static PLDHashOperator CountReferents(PrefCallback* aKey,
   1.242 +                                        nsAutoPtr<PrefCallback>& aCallback,
   1.243 +                                        void* aClosure);
   1.244 +};
   1.245 +
   1.246 +NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)
   1.247 +
   1.248 +struct PreferencesReferentCount {
   1.249 +  PreferencesReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
   1.250 +  size_t numStrong;
   1.251 +  size_t numWeakAlive;
   1.252 +  size_t numWeakDead;
   1.253 +  nsTArray<nsCString> suspectPreferences;
   1.254 +  // Count of the number of referents for each preference.
   1.255 +  nsDataHashtable<nsCStringHashKey, uint32_t> prefCounter;
   1.256 +};
   1.257 +
   1.258 +PLDHashOperator
   1.259 +PreferenceServiceReporter::CountReferents(PrefCallback* aKey,
   1.260 +                                          nsAutoPtr<PrefCallback>& aCallback,
   1.261 +                                          void* aClosure)
   1.262 +{
   1.263 +  PreferencesReferentCount* referentCount =
   1.264 +    static_cast<PreferencesReferentCount*>(aClosure);
   1.265 +
   1.266 +  nsPrefBranch* prefBranch = aCallback->GetPrefBranch();
   1.267 +  const char* pref = prefBranch->getPrefName(aCallback->GetDomain().get());
   1.268 +
   1.269 +  if (aCallback->IsWeak()) {
   1.270 +    nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(aCallback->mWeakRef);
   1.271 +    if (callbackRef) {
   1.272 +      referentCount->numWeakAlive++;
   1.273 +    } else {
   1.274 +      referentCount->numWeakDead++;
   1.275 +    }
   1.276 +  } else {
   1.277 +    referentCount->numStrong++;
   1.278 +  }
   1.279 +
   1.280 +  nsDependentCString prefString(pref);
   1.281 +  uint32_t oldCount = 0;
   1.282 +  referentCount->prefCounter.Get(prefString, &oldCount);
   1.283 +  uint32_t currentCount = oldCount + 1;
   1.284 +  referentCount->prefCounter.Put(prefString, currentCount);
   1.285 +
   1.286 +  // Keep track of preferences that have a suspiciously large
   1.287 +  // number of referents (symptom of leak).
   1.288 +  if (currentCount == kSuspectReferentCount) {
   1.289 +    referentCount->suspectPreferences.AppendElement(prefString);
   1.290 +  }
   1.291 +
   1.292 +  return PL_DHASH_NEXT;
   1.293 +}
   1.294 +
   1.295 +MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
   1.296 +
   1.297 +NS_IMETHODIMP
   1.298 +PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb,
   1.299 +                                          nsISupports* aClosure)
   1.300 +{
   1.301 +#define REPORT(_path, _kind, _units, _amount, _desc)                          \
   1.302 +    do {                                                                      \
   1.303 +      nsresult rv;                                                            \
   1.304 +      rv = aCb->Callback(EmptyCString(), _path, _kind,                        \
   1.305 +                         _units, _amount, NS_LITERAL_CSTRING(_desc),          \
   1.306 +                         aClosure);                                           \
   1.307 +      NS_ENSURE_SUCCESS(rv, rv);                                              \
   1.308 +    } while (0)
   1.309 +
   1.310 +  REPORT(NS_LITERAL_CSTRING("explicit/preferences"),
   1.311 +         KIND_HEAP, UNITS_BYTES,
   1.312 +         Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf),
   1.313 +         "Memory used by the preferences system.");
   1.314 +
   1.315 +  nsPrefBranch* rootBranch =
   1.316 +    static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
   1.317 +  if (!rootBranch) {
   1.318 +    return NS_OK;
   1.319 +  }
   1.320 +
   1.321 +  PreferencesReferentCount referentCount;
   1.322 +  rootBranch->mObservers.Enumerate(&CountReferents, &referentCount);
   1.323 +
   1.324 +  for (uint32_t i = 0; i < referentCount.suspectPreferences.Length(); i++) {
   1.325 +    nsCString& suspect = referentCount.suspectPreferences[i];
   1.326 +    uint32_t totalReferentCount = 0;
   1.327 +    referentCount.prefCounter.Get(suspect, &totalReferentCount);
   1.328 +
   1.329 +    nsPrintfCString suspectPath("preference-service-suspect/"
   1.330 +                                "referent(pref=%s)", suspect.get());
   1.331 +
   1.332 +    REPORT(suspectPath,
   1.333 +           KIND_OTHER, UNITS_COUNT, totalReferentCount,
   1.334 +           "A preference with a suspiciously large number "
   1.335 +           "referents (symptom of a leak).");
   1.336 +  }
   1.337 +
   1.338 +  REPORT(NS_LITERAL_CSTRING("preference-service/referent/strong"),
   1.339 +         KIND_OTHER, UNITS_COUNT, referentCount.numStrong,
   1.340 +         "The number of strong referents held by the preference service.");
   1.341 +
   1.342 +  REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/alive"),
   1.343 +         KIND_OTHER, UNITS_COUNT, referentCount.numWeakAlive,
   1.344 +         "The number of weak referents held by the preference service "
   1.345 +         "that are still alive.");
   1.346 +
   1.347 +  REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/dead"),
   1.348 +         KIND_OTHER, UNITS_COUNT, referentCount.numWeakDead,
   1.349 +         "The number of weak referents held by the preference service "
   1.350 +         "that are dead.");
   1.351 +
   1.352 +#undef REPORT
   1.353 +
   1.354 +  return NS_OK;
   1.355 +}
   1.356 +
   1.357 +namespace {
   1.358 +class AddPreferencesMemoryReporterRunnable : public nsRunnable
   1.359 +{
   1.360 +  NS_IMETHOD Run()
   1.361 +  {
   1.362 +    return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
   1.363 +  }
   1.364 +};
   1.365 +} // anonymous namespace
   1.366 +
   1.367 +// static
   1.368 +Preferences*
   1.369 +Preferences::GetInstanceForService()
   1.370 +{
   1.371 +  if (sPreferences) {
   1.372 +    NS_ADDREF(sPreferences);
   1.373 +    return sPreferences;
   1.374 +  }
   1.375 +
   1.376 +  NS_ENSURE_TRUE(!sShutdown, nullptr);
   1.377 +
   1.378 +  sRootBranch = new nsPrefBranch("", false);
   1.379 +  NS_ADDREF(sRootBranch);
   1.380 +  sDefaultRootBranch = new nsPrefBranch("", true);
   1.381 +  NS_ADDREF(sDefaultRootBranch);
   1.382 +
   1.383 +  sPreferences = new Preferences();
   1.384 +  NS_ADDREF(sPreferences);
   1.385 +
   1.386 +  if (NS_FAILED(sPreferences->Init())) {
   1.387 +    // The singleton instance will delete sRootBranch and sDefaultRootBranch.
   1.388 +    NS_RELEASE(sPreferences);
   1.389 +    return nullptr;
   1.390 +  }
   1.391 +
   1.392 +  gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
   1.393 +
   1.394 +  gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
   1.395 +
   1.396 +  // Preferences::GetInstanceForService() can be called from GetService(), and
   1.397 +  // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter).  To
   1.398 +  // avoid a potential recursive GetService() call, we can't register the
   1.399 +  // memory reporter here; instead, do it off a runnable.
   1.400 +  nsRefPtr<AddPreferencesMemoryReporterRunnable> runnable =
   1.401 +    new AddPreferencesMemoryReporterRunnable();
   1.402 +  NS_DispatchToMainThread(runnable);
   1.403 +
   1.404 +  NS_ADDREF(sPreferences);
   1.405 +  return sPreferences;
   1.406 +}
   1.407 +
   1.408 +// static
   1.409 +bool
   1.410 +Preferences::InitStaticMembers()
   1.411 +{
   1.412 +#ifndef MOZ_B2G
   1.413 +  MOZ_ASSERT(NS_IsMainThread());
   1.414 +#endif
   1.415 +
   1.416 +  if (!sShutdown && !sPreferences) {
   1.417 +    nsCOMPtr<nsIPrefService> prefService =
   1.418 +      do_GetService(NS_PREFSERVICE_CONTRACTID);
   1.419 +  }
   1.420 +
   1.421 +  return sPreferences != nullptr;
   1.422 +}
   1.423 +
   1.424 +// static
   1.425 +void
   1.426 +Preferences::Shutdown()
   1.427 +{
   1.428 +  if (!sShutdown) {
   1.429 +    sShutdown = true; // Don't create the singleton instance after here.
   1.430 +
   1.431 +    // Don't set sPreferences to nullptr here.  The instance may be grabbed by
   1.432 +    // other modules.  The utility methods of Preferences should be available
   1.433 +    // until the singleton instance actually released.
   1.434 +    if (sPreferences) {
   1.435 +      sPreferences->Release();
   1.436 +    }
   1.437 +  }
   1.438 +}
   1.439 +
   1.440 +//-----------------------------------------------------------------------------
   1.441 +
   1.442 +/*
   1.443 + * Constructor/Destructor
   1.444 + */
   1.445 +
   1.446 +Preferences::Preferences()
   1.447 +{
   1.448 +}
   1.449 +
   1.450 +Preferences::~Preferences()
   1.451 +{
   1.452 +  NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?");
   1.453 +
   1.454 +  delete gObserverTable;
   1.455 +  gObserverTable = nullptr;
   1.456 +
   1.457 +  delete gCacheData;
   1.458 +  gCacheData = nullptr;
   1.459 +
   1.460 +  NS_RELEASE(sRootBranch);
   1.461 +  NS_RELEASE(sDefaultRootBranch);
   1.462 +
   1.463 +  sPreferences = nullptr;
   1.464 +
   1.465 +  PREF_Cleanup();
   1.466 +}
   1.467 +
   1.468 +
   1.469 +/*
   1.470 + * nsISupports Implementation
   1.471 + */
   1.472 +
   1.473 +NS_IMPL_ADDREF(Preferences)
   1.474 +NS_IMPL_RELEASE(Preferences)
   1.475 +
   1.476 +NS_INTERFACE_MAP_BEGIN(Preferences)
   1.477 +    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
   1.478 +    NS_INTERFACE_MAP_ENTRY(nsIPrefService)
   1.479 +    NS_INTERFACE_MAP_ENTRY(nsIObserver)
   1.480 +    NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
   1.481 +    NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
   1.482 +    NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
   1.483 +    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   1.484 +NS_INTERFACE_MAP_END
   1.485 +
   1.486 +
   1.487 +/*
   1.488 + * nsIPrefService Implementation
   1.489 + */
   1.490 +
   1.491 +nsresult
   1.492 +Preferences::Init()
   1.493 +{
   1.494 +  nsresult rv;
   1.495 +
   1.496 +  rv = PREF_Init();
   1.497 +  NS_ENSURE_SUCCESS(rv, rv);
   1.498 +
   1.499 +  rv = pref_InitInitialObjects();
   1.500 +  NS_ENSURE_SUCCESS(rv, rv);
   1.501 +
   1.502 +  using mozilla::dom::ContentChild;
   1.503 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
   1.504 +    InfallibleTArray<PrefSetting> prefs;
   1.505 +    ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
   1.506 +
   1.507 +    // Store the array
   1.508 +    for (uint32_t i = 0; i < prefs.Length(); ++i) {
   1.509 +      pref_SetPref(prefs[i]);
   1.510 +    }
   1.511 +    return NS_OK;
   1.512 +  }
   1.513 +
   1.514 +  nsXPIDLCString lockFileName;
   1.515 +  /*
   1.516 +   * The following is a small hack which will allow us to only load the library
   1.517 +   * which supports the netscape.cfg file if the preference is defined. We
   1.518 +   * test for the existence of the pref, set in the all.js (mozilla) or
   1.519 +   * all-ns.js (netscape 6), and if it exists we startup the pref config
   1.520 +   * category which will do the rest.
   1.521 +   */
   1.522 +
   1.523 +  rv = PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName), false);
   1.524 +  if (NS_SUCCEEDED(rv))
   1.525 +    NS_CreateServicesFromCategory("pref-config-startup",
   1.526 +                                  static_cast<nsISupports *>(static_cast<void *>(this)),
   1.527 +                                  "pref-config-startup");    
   1.528 +
   1.529 +  nsCOMPtr<nsIObserverService> observerService =
   1.530 +    mozilla::services::GetObserverService();
   1.531 +  if (!observerService)
   1.532 +    return NS_ERROR_FAILURE;
   1.533 +
   1.534 +  rv = observerService->AddObserver(this, "profile-before-change", true);
   1.535 +
   1.536 +  observerService->AddObserver(this, "load-extension-defaults", true);
   1.537 +  observerService->AddObserver(this, "suspend_process_notification", true);
   1.538 +
   1.539 +  return(rv);
   1.540 +}
   1.541 +
   1.542 +// static
   1.543 +nsresult
   1.544 +Preferences::ResetAndReadUserPrefs()
   1.545 +{
   1.546 +  sPreferences->ResetUserPrefs();
   1.547 +  return sPreferences->ReadUserPrefs(nullptr);
   1.548 +}
   1.549 +
   1.550 +NS_IMETHODIMP
   1.551 +Preferences::Observe(nsISupports *aSubject, const char *aTopic,
   1.552 +                     const char16_t *someData)
   1.553 +{
   1.554 +  if (XRE_GetProcessType() == GeckoProcessType_Content)
   1.555 +    return NS_ERROR_NOT_AVAILABLE;
   1.556 +
   1.557 +  nsresult rv = NS_OK;
   1.558 +
   1.559 +  if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
   1.560 +    if (!nsCRT::strcmp(someData, MOZ_UTF16("shutdown-cleanse"))) {
   1.561 +      if (mCurrentFile) {
   1.562 +        mCurrentFile->Remove(false);
   1.563 +        mCurrentFile = nullptr;
   1.564 +      }
   1.565 +    } else {
   1.566 +      rv = SavePrefFile(nullptr);
   1.567 +    }
   1.568 +  } else if (!strcmp(aTopic, "load-extension-defaults")) {
   1.569 +    pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
   1.570 +  } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
   1.571 +    // Reload the default prefs from file.
   1.572 +    pref_InitInitialObjects();
   1.573 +  } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) {
   1.574 +    // Our process is being suspended. The OS may wake our process later,
   1.575 +    // or it may kill the process. In case our process is going to be killed
   1.576 +    // from the suspended state, we save preferences before suspending.
   1.577 +    rv = SavePrefFile(nullptr);
   1.578 +  }
   1.579 +  return rv;
   1.580 +}
   1.581 +
   1.582 +
   1.583 +NS_IMETHODIMP
   1.584 +Preferences::ReadUserPrefs(nsIFile *aFile)
   1.585 +{
   1.586 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
   1.587 +    NS_ERROR("cannot load prefs from content process");
   1.588 +    return NS_ERROR_NOT_AVAILABLE;
   1.589 +  }
   1.590 +
   1.591 +  nsresult rv;
   1.592 +
   1.593 +  if (nullptr == aFile) {
   1.594 +    rv = UseDefaultPrefFile();
   1.595 +    // A user pref file is optional.
   1.596 +    // Ignore all errors related to it, so we retain 'rv' value :-|
   1.597 +    (void) UseUserPrefFile();
   1.598 +
   1.599 +    // Migrate the old prerelease telemetry pref
   1.600 +    if (!Preferences::GetBool(kOldTelemetryPref, true)) {
   1.601 +      Preferences::SetBool(kTelemetryPref, false);
   1.602 +      Preferences::ClearUser(kOldTelemetryPref);
   1.603 +    }
   1.604 +
   1.605 +    NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
   1.606 +  } else {
   1.607 +    rv = ReadAndOwnUserPrefFile(aFile);
   1.608 +  }
   1.609 +
   1.610 +  return rv;
   1.611 +}
   1.612 +
   1.613 +NS_IMETHODIMP
   1.614 +Preferences::ResetPrefs()
   1.615 +{
   1.616 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
   1.617 +    NS_ERROR("cannot reset prefs from content process");
   1.618 +    return NS_ERROR_NOT_AVAILABLE;
   1.619 +  }
   1.620 +
   1.621 +  NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
   1.622 +  PREF_CleanupPrefs();
   1.623 +
   1.624 +  nsresult rv = PREF_Init();
   1.625 +  NS_ENSURE_SUCCESS(rv, rv);
   1.626 +
   1.627 +  return pref_InitInitialObjects();
   1.628 +}
   1.629 +
   1.630 +NS_IMETHODIMP
   1.631 +Preferences::ResetUserPrefs()
   1.632 +{
   1.633 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
   1.634 +    NS_ERROR("cannot reset user prefs from content process");
   1.635 +    return NS_ERROR_NOT_AVAILABLE;
   1.636 +  }
   1.637 +
   1.638 +  PREF_ClearAllUserPrefs();
   1.639 +  return NS_OK;    
   1.640 +}
   1.641 +
   1.642 +NS_IMETHODIMP
   1.643 +Preferences::SavePrefFile(nsIFile *aFile)
   1.644 +{
   1.645 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
   1.646 +    NS_ERROR("cannot save pref file from content process");
   1.647 +    return NS_ERROR_NOT_AVAILABLE;
   1.648 +  }
   1.649 +
   1.650 +  return SavePrefFileInternal(aFile);
   1.651 +}
   1.652 +
   1.653 +static nsresult
   1.654 +ReadExtensionPrefs(nsIFile *aFile)
   1.655 +{
   1.656 +  nsresult rv;
   1.657 +  nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv);
   1.658 +  NS_ENSURE_SUCCESS(rv, rv);
   1.659 +
   1.660 +  rv = reader->Open(aFile);
   1.661 +  NS_ENSURE_SUCCESS(rv, rv);
   1.662 +
   1.663 +  nsCOMPtr<nsIUTF8StringEnumerator> files;
   1.664 +  rv = reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),
   1.665 +                           getter_AddRefs(files));
   1.666 +  NS_ENSURE_SUCCESS(rv, rv);
   1.667 +
   1.668 +  char buffer[4096];
   1.669 +
   1.670 +  bool more;
   1.671 +  while (NS_SUCCEEDED(rv = files->HasMore(&more)) && more) {
   1.672 +    nsAutoCString entry;
   1.673 +    rv = files->GetNext(entry);
   1.674 +    NS_ENSURE_SUCCESS(rv, rv);
   1.675 +
   1.676 +    nsCOMPtr<nsIInputStream> stream;
   1.677 +    rv = reader->GetInputStream(entry, getter_AddRefs(stream));
   1.678 +    NS_ENSURE_SUCCESS(rv, rv);
   1.679 +
   1.680 +    uint64_t avail;
   1.681 +    uint32_t read;
   1.682 +
   1.683 +    PrefParseState ps;
   1.684 +    PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
   1.685 +    while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) {
   1.686 +      rv = stream->Read(buffer, 4096, &read);
   1.687 +      if (NS_FAILED(rv)) {
   1.688 +        NS_WARNING("Pref stream read failed");
   1.689 +        break;
   1.690 +      }
   1.691 +
   1.692 +      PREF_ParseBuf(&ps, buffer, read);
   1.693 +    }
   1.694 +    PREF_FinalizeParseState(&ps);
   1.695 +  }
   1.696 +  return rv;
   1.697 +}
   1.698 +
   1.699 +void
   1.700 +Preferences::SetPreference(const PrefSetting& aPref)
   1.701 +{
   1.702 +  pref_SetPref(aPref);
   1.703 +}
   1.704 +
   1.705 +void
   1.706 +Preferences::GetPreference(PrefSetting* aPref)
   1.707 +{
   1.708 +  PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get());
   1.709 +  if (!entry)
   1.710 +    return;
   1.711 +
   1.712 +  pref_GetPrefFromEntry(entry, aPref);
   1.713 +}
   1.714 +
   1.715 +void
   1.716 +Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
   1.717 +{
   1.718 +  aPrefs->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable));
   1.719 +  PL_DHashTableEnumerate(&gHashTable, pref_GetPrefs, aPrefs);
   1.720 +}
   1.721 +
   1.722 +NS_IMETHODIMP
   1.723 +Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
   1.724 +{
   1.725 +  nsresult rv;
   1.726 +
   1.727 +  if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
   1.728 +    // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
   1.729 +    nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, false);
   1.730 +    if (!prefBranch)
   1.731 +      return NS_ERROR_OUT_OF_MEMORY;
   1.732 +
   1.733 +    rv = CallQueryInterface(prefBranch, _retval);
   1.734 +  } else {
   1.735 +    // special case caching the default root
   1.736 +    nsCOMPtr<nsIPrefBranch> root(sRootBranch);
   1.737 +    root.forget(_retval);
   1.738 +    rv = NS_OK;
   1.739 +  }
   1.740 +  return rv;
   1.741 +}
   1.742 +
   1.743 +NS_IMETHODIMP
   1.744 +Preferences::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
   1.745 +{
   1.746 +  if (!aPrefRoot || !aPrefRoot[0]) {
   1.747 +    nsCOMPtr<nsIPrefBranch> root(sDefaultRootBranch);
   1.748 +    root.forget(_retval);
   1.749 +    return NS_OK;
   1.750 +  }
   1.751 +
   1.752 +  // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
   1.753 +  nsRefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, true);
   1.754 +  if (!prefBranch)
   1.755 +    return NS_ERROR_OUT_OF_MEMORY;
   1.756 +
   1.757 +  prefBranch.forget(_retval);
   1.758 +  return NS_OK;
   1.759 +}
   1.760 +
   1.761 +
   1.762 +nsresult
   1.763 +Preferences::NotifyServiceObservers(const char *aTopic)
   1.764 +{
   1.765 +  nsCOMPtr<nsIObserverService> observerService = 
   1.766 +    mozilla::services::GetObserverService();  
   1.767 +  if (!observerService)
   1.768 +    return NS_ERROR_FAILURE;
   1.769 +
   1.770 +  nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
   1.771 +  observerService->NotifyObservers(subject, aTopic, nullptr);
   1.772 +  
   1.773 +  return NS_OK;
   1.774 +}
   1.775 +
   1.776 +nsresult
   1.777 +Preferences::UseDefaultPrefFile()
   1.778 +{
   1.779 +  nsresult rv;
   1.780 +  nsCOMPtr<nsIFile> aFile;
   1.781 +
   1.782 +#if defined(XP_WIN) && defined(MOZ_METRO)
   1.783 +  if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
   1.784 +    rv = NS_GetSpecialDirectory(NS_METRO_APP_PREFS_50_FILE, getter_AddRefs(aFile));
   1.785 +  } else
   1.786 +#endif
   1.787 +  {
   1.788 +    rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
   1.789 +  }
   1.790 +
   1.791 +  if (NS_SUCCEEDED(rv)) {
   1.792 +    rv = ReadAndOwnUserPrefFile(aFile);
   1.793 +    // Most likely cause of failure here is that the file didn't
   1.794 +    // exist, so save a new one. mUserPrefReadFailed will be
   1.795 +    // used to catch an error in actually reading the file.
   1.796 +    if (NS_FAILED(rv)) {
   1.797 +      if (NS_FAILED(SavePrefFileInternal(aFile)))
   1.798 +        NS_ERROR("Failed to save new shared pref file");
   1.799 +      else
   1.800 +        rv = NS_OK;
   1.801 +    }
   1.802 +  }
   1.803 +  
   1.804 +  return rv;
   1.805 +}
   1.806 +
   1.807 +nsresult
   1.808 +Preferences::UseUserPrefFile()
   1.809 +{
   1.810 +  nsresult rv = NS_OK;
   1.811 +  nsCOMPtr<nsIFile> aFile;
   1.812 +  nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR);
   1.813 +
   1.814 +  rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile));
   1.815 +  if (NS_SUCCEEDED(rv) && aFile) {
   1.816 +    rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
   1.817 +    if (NS_SUCCEEDED(rv)) {
   1.818 +      bool exists = false;
   1.819 +      aFile->Exists(&exists);
   1.820 +      if (exists) {
   1.821 +        rv = openPrefFile(aFile);
   1.822 +      } else {
   1.823 +        rv = NS_ERROR_FILE_NOT_FOUND;
   1.824 +      }
   1.825 +    }
   1.826 +  }
   1.827 +  return rv;
   1.828 +}
   1.829 +
   1.830 +nsresult
   1.831 +Preferences::MakeBackupPrefFile(nsIFile *aFile)
   1.832 +{
   1.833 +  // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
   1.834 +  // "Invalidprefs.js" is removed if it exists, prior to making the copy.
   1.835 +  nsAutoString newFilename;
   1.836 +  nsresult rv = aFile->GetLeafName(newFilename);
   1.837 +  NS_ENSURE_SUCCESS(rv, rv);
   1.838 +  newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0);
   1.839 +  nsCOMPtr<nsIFile> newFile;
   1.840 +  rv = aFile->GetParent(getter_AddRefs(newFile));
   1.841 +  NS_ENSURE_SUCCESS(rv, rv);
   1.842 +  rv = newFile->Append(newFilename);
   1.843 +  NS_ENSURE_SUCCESS(rv, rv);
   1.844 +  bool exists = false;
   1.845 +  newFile->Exists(&exists);
   1.846 +  if (exists) {
   1.847 +    rv = newFile->Remove(false);
   1.848 +    NS_ENSURE_SUCCESS(rv, rv);
   1.849 +  }
   1.850 +  rv = aFile->CopyTo(nullptr, newFilename);
   1.851 +  NS_ENSURE_SUCCESS(rv, rv);
   1.852 +  return rv;
   1.853 +}
   1.854 +
   1.855 +nsresult
   1.856 +Preferences::ReadAndOwnUserPrefFile(nsIFile *aFile)
   1.857 +{
   1.858 +  NS_ENSURE_ARG(aFile);
   1.859 +  
   1.860 +  if (mCurrentFile == aFile)
   1.861 +    return NS_OK;
   1.862 +  mCurrentFile = aFile;
   1.863 +
   1.864 +  nsresult rv = NS_OK;
   1.865 +  bool exists = false;
   1.866 +  mCurrentFile->Exists(&exists);
   1.867 +  if (exists) {
   1.868 +    rv = openPrefFile(mCurrentFile);
   1.869 +    if (NS_FAILED(rv)) {
   1.870 +      // Save a backup copy of the current (invalid) prefs file, since all prefs
   1.871 +      // from the error line to the end of the file will be lost (bug 361102).
   1.872 +      // TODO we should notify the user about it (bug 523725).
   1.873 +      MakeBackupPrefFile(mCurrentFile);
   1.874 +    }
   1.875 +  } else {
   1.876 +    rv = NS_ERROR_FILE_NOT_FOUND;
   1.877 +  }
   1.878 +
   1.879 +  return rv;
   1.880 +}
   1.881 +
   1.882 +nsresult
   1.883 +Preferences::SavePrefFileInternal(nsIFile *aFile)
   1.884 +{
   1.885 +  if (nullptr == aFile) {
   1.886 +    // the gDirty flag tells us if we should write to mCurrentFile
   1.887 +    // we only check this flag when the caller wants to write to the default
   1.888 +    if (!gDirty)
   1.889 +      return NS_OK;
   1.890 +    
   1.891 +    // It's possible that we never got a prefs file.
   1.892 +    nsresult rv = NS_OK;
   1.893 +    if (mCurrentFile)
   1.894 +      rv = WritePrefFile(mCurrentFile);
   1.895 +
   1.896 +    return rv;
   1.897 +  } else {
   1.898 +    return WritePrefFile(aFile);
   1.899 +  }
   1.900 +}
   1.901 +
   1.902 +nsresult
   1.903 +Preferences::WritePrefFile(nsIFile* aFile)
   1.904 +{
   1.905 +  const char                outHeader[] =
   1.906 +    "# Mozilla User Preferences"
   1.907 +    NS_LINEBREAK
   1.908 +    NS_LINEBREAK
   1.909 +    "/* Do not edit this file."
   1.910 +    NS_LINEBREAK
   1.911 +    " *"
   1.912 +    NS_LINEBREAK
   1.913 +    " * If you make changes to this file while the application is running,"
   1.914 +    NS_LINEBREAK
   1.915 +    " * the changes will be overwritten when the application exits."
   1.916 +    NS_LINEBREAK
   1.917 +    " *"
   1.918 +    NS_LINEBREAK
   1.919 +    " * To make a manual change to preferences, you can visit the URL about:config"
   1.920 +    NS_LINEBREAK
   1.921 +    " */"
   1.922 +    NS_LINEBREAK
   1.923 +    NS_LINEBREAK;
   1.924 +
   1.925 +  nsCOMPtr<nsIOutputStream> outStreamSink;
   1.926 +  nsCOMPtr<nsIOutputStream> outStream;
   1.927 +  uint32_t                  writeAmount;
   1.928 +  nsresult                  rv;
   1.929 +
   1.930 +  if (!gHashTable.ops)
   1.931 +    return NS_ERROR_NOT_INITIALIZED;
   1.932 +
   1.933 +  // execute a "safe" save by saving through a tempfile
   1.934 +  rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
   1.935 +                                       aFile,
   1.936 +                                       -1,
   1.937 +                                       0600);
   1.938 +  if (NS_FAILED(rv)) 
   1.939 +      return rv;
   1.940 +  rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
   1.941 +  if (NS_FAILED(rv)) 
   1.942 +      return rv;  
   1.943 +
   1.944 +  nsAutoArrayPtr<char*> valueArray(new char*[gHashTable.entryCount]);
   1.945 +  memset(valueArray, 0, gHashTable.entryCount * sizeof(char*));
   1.946 +  pref_saveArgs saveArgs;
   1.947 +  saveArgs.prefArray = valueArray;
   1.948 +  saveArgs.saveTypes = SAVE_ALL;
   1.949 +  
   1.950 +  // get the lines that we're supposed to be writing to the file
   1.951 +  PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
   1.952 +    
   1.953 +  /* Sort the preferences to make a readable file on disk */
   1.954 +  NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char *), pref_CompareStrings, nullptr);
   1.955 +  
   1.956 +  // write out the file header
   1.957 +  outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
   1.958 +
   1.959 +  char** walker = valueArray;
   1.960 +  for (uint32_t valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) {
   1.961 +    if (*walker) {
   1.962 +      outStream->Write(*walker, strlen(*walker), &writeAmount);
   1.963 +      outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
   1.964 +      NS_Free(*walker);
   1.965 +    }
   1.966 +  }
   1.967 +
   1.968 +  // tell the safe output stream to overwrite the real prefs file
   1.969 +  // (it'll abort if there were any errors during writing)
   1.970 +  nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
   1.971 +  NS_ASSERTION(safeStream, "expected a safe output stream!");
   1.972 +  if (safeStream) {
   1.973 +    rv = safeStream->Finish();
   1.974 +    if (NS_FAILED(rv)) {
   1.975 +      NS_WARNING("failed to save prefs file! possible data loss");
   1.976 +      return rv;
   1.977 +    }
   1.978 +  }
   1.979 +
   1.980 +  gDirty = false;
   1.981 +  return NS_OK;
   1.982 +}
   1.983 +
   1.984 +static nsresult openPrefFile(nsIFile* aFile)
   1.985 +{
   1.986 +  nsCOMPtr<nsIInputStream> inStr;
   1.987 +
   1.988 +  nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
   1.989 +  if (NS_FAILED(rv)) 
   1.990 +    return rv;        
   1.991 +
   1.992 +  uint64_t fileSize64;
   1.993 +  rv = inStr->Available(&fileSize64);
   1.994 +  if (NS_FAILED(rv))
   1.995 +    return rv;
   1.996 +  NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
   1.997 +
   1.998 +  uint32_t fileSize = (uint32_t)fileSize64;
   1.999 +  nsAutoArrayPtr<char> fileBuffer(new char[fileSize]);
  1.1000 +  if (fileBuffer == nullptr)
  1.1001 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1002 +
  1.1003 +  PrefParseState ps;
  1.1004 +  PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
  1.1005 +
  1.1006 +  // Read is not guaranteed to return a buf the size of fileSize,
  1.1007 +  // but usually will.
  1.1008 +  nsresult rv2 = NS_OK;
  1.1009 +  for (;;) {
  1.1010 +    uint32_t amtRead = 0;
  1.1011 +    rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead);
  1.1012 +    if (NS_FAILED(rv) || amtRead == 0)
  1.1013 +      break;
  1.1014 +    if (!PREF_ParseBuf(&ps, fileBuffer, amtRead))
  1.1015 +      rv2 = NS_ERROR_FILE_CORRUPTED;
  1.1016 +  }
  1.1017 +
  1.1018 +  PREF_FinalizeParseState(&ps);
  1.1019 +
  1.1020 +  return NS_FAILED(rv) ? rv : rv2;
  1.1021 +}
  1.1022 +
  1.1023 +/*
  1.1024 + * some stuff that gets called from Pref_Init()
  1.1025 + */
  1.1026 +
  1.1027 +static int
  1.1028 +pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
  1.1029 +{
  1.1030 +  nsAutoCString filename1, filename2;
  1.1031 +  aFile1->GetNativeLeafName(filename1);
  1.1032 +  aFile2->GetNativeLeafName(filename2);
  1.1033 +
  1.1034 +  return Compare(filename2, filename1);
  1.1035 +}
  1.1036 +
  1.1037 +/**
  1.1038 + * Load default pref files from a directory. The files in the
  1.1039 + * directory are sorted reverse-alphabetically; a set of "special file
  1.1040 + * names" may be specified which are loaded after all the others.
  1.1041 + */
  1.1042 +static nsresult
  1.1043 +pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, uint32_t aSpecialFilesCount)
  1.1044 +{
  1.1045 +  nsresult rv, rv2;
  1.1046 +  bool hasMoreElements;
  1.1047 +
  1.1048 +  nsCOMPtr<nsISimpleEnumerator> dirIterator;
  1.1049 +
  1.1050 +  // this may fail in some normal cases, such as embedders who do not use a GRE
  1.1051 +  rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
  1.1052 +  if (NS_FAILED(rv)) {
  1.1053 +    // If the directory doesn't exist, then we have no reason to complain.  We
  1.1054 +    // loaded everything (and nothing) successfully.
  1.1055 +    if (rv == NS_ERROR_FILE_NOT_FOUND || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
  1.1056 +      rv = NS_OK;
  1.1057 +    return rv;
  1.1058 +  }
  1.1059 +
  1.1060 +  rv = dirIterator->HasMoreElements(&hasMoreElements);
  1.1061 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1062 +
  1.1063 +  nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
  1.1064 +  nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
  1.1065 +  nsCOMPtr<nsIFile> prefFile;
  1.1066 +
  1.1067 +  while (hasMoreElements && NS_SUCCEEDED(rv)) {
  1.1068 +    nsAutoCString leafName;
  1.1069 +
  1.1070 +    nsCOMPtr<nsISupports> supports;
  1.1071 +    rv = dirIterator->GetNext(getter_AddRefs(supports));
  1.1072 +    prefFile = do_QueryInterface(supports);
  1.1073 +    if (NS_FAILED(rv)) {
  1.1074 +      break;
  1.1075 +    }
  1.1076 +
  1.1077 +    prefFile->GetNativeLeafName(leafName);
  1.1078 +    NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
  1.1079 +
  1.1080 +    // Skip non-js files
  1.1081 +    if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
  1.1082 +                       nsCaseInsensitiveCStringComparator())) {
  1.1083 +      bool shouldParse = true;
  1.1084 +      // separate out special files
  1.1085 +      for (uint32_t i = 0; i < aSpecialFilesCount; ++i) {
  1.1086 +        if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
  1.1087 +          shouldParse = false;
  1.1088 +          // special files should be process in order; we put them into
  1.1089 +          // the array by index; this can make the array sparse
  1.1090 +          specialFiles.ReplaceObjectAt(prefFile, i);
  1.1091 +        }
  1.1092 +      }
  1.1093 +
  1.1094 +      if (shouldParse) {
  1.1095 +        prefFiles.AppendObject(prefFile);
  1.1096 +      }
  1.1097 +    }
  1.1098 +
  1.1099 +    rv = dirIterator->HasMoreElements(&hasMoreElements);
  1.1100 +  }
  1.1101 +
  1.1102 +  if (prefFiles.Count() + specialFiles.Count() == 0) {
  1.1103 +    NS_WARNING("No default pref files found.");
  1.1104 +    if (NS_SUCCEEDED(rv)) {
  1.1105 +      rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
  1.1106 +    }
  1.1107 +    return rv;
  1.1108 +  }
  1.1109 +
  1.1110 +  prefFiles.Sort(pref_CompareFileNames, nullptr);
  1.1111 +  
  1.1112 +  uint32_t arrayCount = prefFiles.Count();
  1.1113 +  uint32_t i;
  1.1114 +  for (i = 0; i < arrayCount; ++i) {
  1.1115 +    rv2 = openPrefFile(prefFiles[i]);
  1.1116 +    if (NS_FAILED(rv2)) {
  1.1117 +      NS_ERROR("Default pref file not parsed successfully.");
  1.1118 +      rv = rv2;
  1.1119 +    }
  1.1120 +  }
  1.1121 +
  1.1122 +  arrayCount = specialFiles.Count();
  1.1123 +  for (i = 0; i < arrayCount; ++i) {
  1.1124 +    // this may be a sparse array; test before parsing
  1.1125 +    nsIFile* file = specialFiles[i];
  1.1126 +    if (file) {
  1.1127 +      rv2 = openPrefFile(file);
  1.1128 +      if (NS_FAILED(rv2)) {
  1.1129 +        NS_ERROR("Special default pref file not parsed successfully.");
  1.1130 +        rv = rv2;
  1.1131 +      }
  1.1132 +    }
  1.1133 +  }
  1.1134 +
  1.1135 +  return rv;
  1.1136 +}
  1.1137 +
  1.1138 +static nsresult pref_LoadPrefsInDirList(const char *listId)
  1.1139 +{
  1.1140 +  nsresult rv;
  1.1141 +  nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
  1.1142 +  if (NS_FAILED(rv))
  1.1143 +    return rv;
  1.1144 +
  1.1145 +  nsCOMPtr<nsISimpleEnumerator> list;
  1.1146 +  dirSvc->Get(listId,
  1.1147 +              NS_GET_IID(nsISimpleEnumerator),
  1.1148 +              getter_AddRefs(list));
  1.1149 +  if (!list)
  1.1150 +    return NS_OK;
  1.1151 +
  1.1152 +  bool hasMore;
  1.1153 +  while (NS_SUCCEEDED(list->HasMoreElements(&hasMore)) && hasMore) {
  1.1154 +    nsCOMPtr<nsISupports> elem;
  1.1155 +    list->GetNext(getter_AddRefs(elem));
  1.1156 +    if (!elem)
  1.1157 +      continue;
  1.1158 +
  1.1159 +    nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
  1.1160 +    if (!path)
  1.1161 +      continue;
  1.1162 +
  1.1163 +    nsAutoCString leaf;
  1.1164 +    path->GetNativeLeafName(leaf);
  1.1165 +
  1.1166 +    // Do we care if a file provided by this process fails to load?
  1.1167 +    if (Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi")))
  1.1168 +      ReadExtensionPrefs(path);
  1.1169 +    else
  1.1170 +      pref_LoadPrefsInDir(path, nullptr, 0);
  1.1171 +  }
  1.1172 +  return NS_OK;
  1.1173 +}
  1.1174 +
  1.1175 +static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
  1.1176 +{
  1.1177 +  nsZipItemPtr<char> manifest(jarReader, name, true);
  1.1178 +  NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
  1.1179 +
  1.1180 +  PrefParseState ps;
  1.1181 +  PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
  1.1182 +  PREF_ParseBuf(&ps, manifest, manifest.Length());
  1.1183 +  PREF_FinalizeParseState(&ps);
  1.1184 +
  1.1185 +  return NS_OK;
  1.1186 +}
  1.1187 +
  1.1188 +//----------------------------------------------------------------------------------------
  1.1189 +// Initialize default preference JavaScript buffers from
  1.1190 +// appropriate TEXT resources
  1.1191 +//----------------------------------------------------------------------------------------
  1.1192 +static nsresult pref_InitInitialObjects()
  1.1193 +{
  1.1194 +  nsresult rv;
  1.1195 +
  1.1196 +  // In omni.jar case, we load the following prefs:
  1.1197 +  // - jar:$gre/omni.jar!/greprefs.js
  1.1198 +  // - jar:$gre/omni.jar!/defaults/pref/*.js
  1.1199 +  // In non omni.jar case, we load:
  1.1200 +  // - $gre/greprefs.js
  1.1201 +  //
  1.1202 +  // In both cases, we also load:
  1.1203 +  // - $gre/defaults/pref/*.js
  1.1204 +  // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
  1.1205 +  // on $app == $gre case ; we load all files instead of channel-prefs.js only
  1.1206 +  // to have the same behaviour as $app != $gre, where this is required as
  1.1207 +  // a supported location for GRE preferences.
  1.1208 +  //
  1.1209 +  // When $app != $gre, we additionally load, in omni.jar case:
  1.1210 +  // - jar:$app/omni.jar!/defaults/preferences/*.js
  1.1211 +  // - $app/defaults/preferences/*.js
  1.1212 +  // and in non omni.jar case:
  1.1213 +  // - $app/defaults/preferences/*.js
  1.1214 +  // When $app == $gre, we additionally load, in omni.jar case:
  1.1215 +  // - jar:$gre/omni.jar!/defaults/preferences/*.js
  1.1216 +  // Thus, in omni.jar case, we always load app-specific default preferences
  1.1217 +  // from omni.jar, whether or not $app == $gre.
  1.1218 +
  1.1219 +  nsZipFind *findPtr;
  1.1220 +  nsAutoPtr<nsZipFind> find;
  1.1221 +  nsTArray<nsCString> prefEntries;
  1.1222 +  const char *entryName;
  1.1223 +  uint16_t entryNameLen;
  1.1224 +
  1.1225 +  nsRefPtr<nsZipArchive> jarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
  1.1226 +  if (jarReader) {
  1.1227 +    // Load jar:$gre/omni.jar!/greprefs.js
  1.1228 +    rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
  1.1229 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1230 +
  1.1231 +    // Load jar:$gre/omni.jar!/defaults/pref/*.js
  1.1232 +    rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr);
  1.1233 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1234 +
  1.1235 +    find = findPtr;
  1.1236 +    while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
  1.1237 +      prefEntries.AppendElement(Substring(entryName, entryNameLen));
  1.1238 +    }
  1.1239 +
  1.1240 +    prefEntries.Sort();
  1.1241 +    for (uint32_t i = prefEntries.Length(); i--; ) {
  1.1242 +      rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
  1.1243 +      if (NS_FAILED(rv))
  1.1244 +        NS_WARNING("Error parsing preferences.");
  1.1245 +    }
  1.1246 +  } else {
  1.1247 +    // Load $gre/greprefs.js
  1.1248 +    nsCOMPtr<nsIFile> greprefsFile;
  1.1249 +    rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greprefsFile));
  1.1250 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1251 +
  1.1252 +    rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
  1.1253 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1254 +
  1.1255 +    rv = openPrefFile(greprefsFile);
  1.1256 +    if (NS_FAILED(rv))
  1.1257 +      NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
  1.1258 +  }
  1.1259 +
  1.1260 +  // Load $gre/defaults/pref/*.js
  1.1261 +  nsCOMPtr<nsIFile> defaultPrefDir;
  1.1262 +
  1.1263 +  rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
  1.1264 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1265 +
  1.1266 +  /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
  1.1267 +  static const char* specialFiles[] = {
  1.1268 +#if defined(XP_MACOSX)
  1.1269 +    "macprefs.js"
  1.1270 +#elif defined(XP_WIN)
  1.1271 +    "winpref.js"
  1.1272 +#elif defined(XP_UNIX)
  1.1273 +    "unix.js"
  1.1274 +#if defined(VMS)
  1.1275 +    , "openvms.js"
  1.1276 +#elif defined(_AIX)
  1.1277 +    , "aix.js"
  1.1278 +#endif
  1.1279 +#elif defined(XP_BEOS)
  1.1280 +    "beos.js"
  1.1281 +#endif
  1.1282 +  };
  1.1283 +
  1.1284 +  rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
  1.1285 +  if (NS_FAILED(rv))
  1.1286 +    NS_WARNING("Error parsing application default preferences.");
  1.1287 +
  1.1288 +  // Load jar:$app/omni.jar!/defaults/preferences/*.js
  1.1289 +  // or jar:$gre/omni.jar!/defaults/preferences/*.js.
  1.1290 +  nsRefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
  1.1291 +  // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
  1.1292 +  // case we look for app-specific default preferences in $gre.
  1.1293 +  if (!appJarReader)
  1.1294 +    appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
  1.1295 +  if (appJarReader) {
  1.1296 +    rv = appJarReader->FindInit("defaults/preferences/*.js$", &findPtr);
  1.1297 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1298 +    find = findPtr;
  1.1299 +    prefEntries.Clear();
  1.1300 +    while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
  1.1301 +      prefEntries.AppendElement(Substring(entryName, entryNameLen));
  1.1302 +    }
  1.1303 +    prefEntries.Sort();
  1.1304 +    for (uint32_t i = prefEntries.Length(); i--; ) {
  1.1305 +      rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
  1.1306 +      if (NS_FAILED(rv))
  1.1307 +        NS_WARNING("Error parsing preferences.");
  1.1308 +    }
  1.1309 +  }
  1.1310 +
  1.1311 +  rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
  1.1312 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1313 +
  1.1314 +  // Set up the correct default for toolkit.telemetry.enabled.
  1.1315 +  // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta
  1.1316 +  // channel, telemetry is on by default, otherwise not. This is necessary
  1.1317 +  // so that beta users who are testing final release builds don't flipflop
  1.1318 +  // defaults.
  1.1319 +  if (Preferences::GetDefaultType(kTelemetryPref) == PREF_INVALID) {
  1.1320 +    bool prerelease = false;
  1.1321 +#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
  1.1322 +    prerelease = true;
  1.1323 +#else
  1.1324 +    if (Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")) {
  1.1325 +      prerelease = true;
  1.1326 +    }
  1.1327 +#endif
  1.1328 +    PREF_SetBoolPref(kTelemetryPref, prerelease, true);
  1.1329 +  }
  1.1330 +
  1.1331 +  NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
  1.1332 +                                nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
  1.1333 +
  1.1334 +  nsCOMPtr<nsIObserverService> observerService =
  1.1335 +    mozilla::services::GetObserverService();
  1.1336 +  if (!observerService)
  1.1337 +    return NS_ERROR_FAILURE;
  1.1338 +
  1.1339 +  observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr);
  1.1340 +
  1.1341 +  return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
  1.1342 +}
  1.1343 +
  1.1344 +
  1.1345 +/******************************************************************************
  1.1346 + *
  1.1347 + * static utilities
  1.1348 + *
  1.1349 + ******************************************************************************/
  1.1350 +
  1.1351 +// static
  1.1352 +nsresult
  1.1353 +Preferences::GetBool(const char* aPref, bool* aResult)
  1.1354 +{
  1.1355 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1356 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1357 +  return PREF_GetBoolPref(aPref, aResult, false);
  1.1358 +}
  1.1359 +
  1.1360 +// static
  1.1361 +nsresult
  1.1362 +Preferences::GetInt(const char* aPref, int32_t* aResult)
  1.1363 +{
  1.1364 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1365 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1366 +  return PREF_GetIntPref(aPref, aResult, false);
  1.1367 +}
  1.1368 +
  1.1369 +// static
  1.1370 +nsresult
  1.1371 +Preferences::GetFloat(const char* aPref, float* aResult)
  1.1372 +{
  1.1373 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1374 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1375 +  nsAutoCString result;
  1.1376 +  nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
  1.1377 +  if (NS_SUCCEEDED(rv)) {
  1.1378 +    *aResult = result.ToFloat(&rv);
  1.1379 +  }
  1.1380 +
  1.1381 +  return rv;
  1.1382 +}
  1.1383 +
  1.1384 +// static
  1.1385 +nsAdoptingCString
  1.1386 +Preferences::GetCString(const char* aPref)
  1.1387 +{
  1.1388 +  nsAdoptingCString result;
  1.1389 +  PREF_CopyCharPref(aPref, getter_Copies(result), false);
  1.1390 +  return result;
  1.1391 +}
  1.1392 +
  1.1393 +// static
  1.1394 +nsAdoptingString
  1.1395 +Preferences::GetString(const char* aPref)
  1.1396 +{
  1.1397 +  nsAdoptingString result;
  1.1398 +  GetString(aPref, &result);
  1.1399 +  return result;
  1.1400 +}
  1.1401 +
  1.1402 +// static
  1.1403 +nsresult
  1.1404 +Preferences::GetCString(const char* aPref, nsACString* aResult)
  1.1405 +{
  1.1406 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1407 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1408 +  nsAutoCString result;
  1.1409 +  nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
  1.1410 +  if (NS_SUCCEEDED(rv)) {
  1.1411 +    *aResult = result;
  1.1412 +  }
  1.1413 +  return rv;
  1.1414 +}
  1.1415 +
  1.1416 +// static
  1.1417 +nsresult
  1.1418 +Preferences::GetString(const char* aPref, nsAString* aResult)
  1.1419 +{
  1.1420 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1421 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1422 +  nsAutoCString result;
  1.1423 +  nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
  1.1424 +  if (NS_SUCCEEDED(rv)) {
  1.1425 +    CopyUTF8toUTF16(result, *aResult);
  1.1426 +  }
  1.1427 +  return rv;
  1.1428 +}
  1.1429 +
  1.1430 +// static
  1.1431 +nsAdoptingCString
  1.1432 +Preferences::GetLocalizedCString(const char* aPref)
  1.1433 +{
  1.1434 +  nsAdoptingCString result;
  1.1435 +  GetLocalizedCString(aPref, &result);
  1.1436 +  return result;
  1.1437 +}
  1.1438 +
  1.1439 +// static
  1.1440 +nsAdoptingString
  1.1441 +Preferences::GetLocalizedString(const char* aPref)
  1.1442 +{
  1.1443 +  nsAdoptingString result;
  1.1444 +  GetLocalizedString(aPref, &result);
  1.1445 +  return result;
  1.1446 +}
  1.1447 +
  1.1448 +// static
  1.1449 +nsresult
  1.1450 +Preferences::GetLocalizedCString(const char* aPref, nsACString* aResult)
  1.1451 +{
  1.1452 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1453 +  nsAutoString result;
  1.1454 +  nsresult rv = GetLocalizedString(aPref, &result);
  1.1455 +  if (NS_SUCCEEDED(rv)) {
  1.1456 +    CopyUTF16toUTF8(result, *aResult);
  1.1457 +  }
  1.1458 +  return rv;
  1.1459 +}
  1.1460 +
  1.1461 +// static
  1.1462 +nsresult
  1.1463 +Preferences::GetLocalizedString(const char* aPref, nsAString* aResult)
  1.1464 +{
  1.1465 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1466 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1467 +  nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
  1.1468 +  nsresult rv = sRootBranch->GetComplexValue(aPref,
  1.1469 +                                             NS_GET_IID(nsIPrefLocalizedString),
  1.1470 +                                             getter_AddRefs(prefLocalString));
  1.1471 +  if (NS_SUCCEEDED(rv)) {
  1.1472 +    NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
  1.1473 +    prefLocalString->GetData(getter_Copies(*aResult));
  1.1474 +  }
  1.1475 +  return rv;
  1.1476 +}
  1.1477 +
  1.1478 +// static
  1.1479 +nsresult
  1.1480 +Preferences::GetComplex(const char* aPref, const nsIID &aType, void** aResult)
  1.1481 +{
  1.1482 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1483 +  return sRootBranch->GetComplexValue(aPref, aType, aResult);
  1.1484 +}
  1.1485 +
  1.1486 +// static
  1.1487 +nsresult
  1.1488 +Preferences::SetCString(const char* aPref, const char* aValue)
  1.1489 +{
  1.1490 +  ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
  1.1491 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1492 +  return PREF_SetCharPref(aPref, aValue, false);
  1.1493 +}
  1.1494 +
  1.1495 +// static
  1.1496 +nsresult
  1.1497 +Preferences::SetCString(const char* aPref, const nsACString &aValue)
  1.1498 +{
  1.1499 +  ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
  1.1500 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1501 +  return PREF_SetCharPref(aPref, PromiseFlatCString(aValue).get(), false);
  1.1502 +}
  1.1503 +
  1.1504 +// static
  1.1505 +nsresult
  1.1506 +Preferences::SetString(const char* aPref, const char16_t* aValue)
  1.1507 +{
  1.1508 +  ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
  1.1509 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1510 +  return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
  1.1511 +}
  1.1512 +
  1.1513 +// static
  1.1514 +nsresult
  1.1515 +Preferences::SetString(const char* aPref, const nsAString &aValue)
  1.1516 +{
  1.1517 +  ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
  1.1518 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1519 +  return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
  1.1520 +}
  1.1521 +
  1.1522 +// static
  1.1523 +nsresult
  1.1524 +Preferences::SetBool(const char* aPref, bool aValue)
  1.1525 +{
  1.1526 +  ENSURE_MAIN_PROCESS("Cannot SetBool from content process:", aPref);
  1.1527 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1528 +  return PREF_SetBoolPref(aPref, aValue, false);
  1.1529 +}
  1.1530 +
  1.1531 +// static
  1.1532 +nsresult
  1.1533 +Preferences::SetInt(const char* aPref, int32_t aValue)
  1.1534 +{
  1.1535 +  ENSURE_MAIN_PROCESS("Cannot SetInt from content process:", aPref);
  1.1536 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1537 +  return PREF_SetIntPref(aPref, aValue, false);
  1.1538 +}
  1.1539 +
  1.1540 +// static
  1.1541 +nsresult
  1.1542 +Preferences::SetComplex(const char* aPref, const nsIID &aType,
  1.1543 +                        nsISupports* aValue)
  1.1544 +{
  1.1545 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1546 +  return sRootBranch->SetComplexValue(aPref, aType, aValue);
  1.1547 +}
  1.1548 +
  1.1549 +// static
  1.1550 +nsresult
  1.1551 +Preferences::ClearUser(const char* aPref)
  1.1552 +{
  1.1553 +  ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:", aPref);
  1.1554 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1555 +  return PREF_ClearUserPref(aPref);
  1.1556 +}
  1.1557 +
  1.1558 +// static
  1.1559 +bool
  1.1560 +Preferences::HasUserValue(const char* aPref)
  1.1561 +{
  1.1562 +  NS_ENSURE_TRUE(InitStaticMembers(), false);
  1.1563 +  return PREF_HasUserPref(aPref);
  1.1564 +}
  1.1565 +
  1.1566 +// static
  1.1567 +int32_t
  1.1568 +Preferences::GetType(const char* aPref)
  1.1569 +{
  1.1570 +  NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
  1.1571 +  int32_t result;
  1.1572 +  return NS_SUCCEEDED(sRootBranch->GetPrefType(aPref, &result)) ?
  1.1573 +    result : nsIPrefBranch::PREF_INVALID;
  1.1574 +}
  1.1575 +
  1.1576 +// static
  1.1577 +nsresult
  1.1578 +Preferences::AddStrongObserver(nsIObserver* aObserver,
  1.1579 +                               const char* aPref)
  1.1580 +{
  1.1581 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1582 +  return sRootBranch->AddObserver(aPref, aObserver, false);
  1.1583 +}
  1.1584 +
  1.1585 +// static
  1.1586 +nsresult
  1.1587 +Preferences::AddWeakObserver(nsIObserver* aObserver,
  1.1588 +                             const char* aPref)
  1.1589 +{
  1.1590 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1591 +  return sRootBranch->AddObserver(aPref, aObserver, true);
  1.1592 +}
  1.1593 +
  1.1594 +// static
  1.1595 +nsresult
  1.1596 +Preferences::RemoveObserver(nsIObserver* aObserver,
  1.1597 +                            const char* aPref)
  1.1598 +{
  1.1599 +  if (!sPreferences && sShutdown) {
  1.1600 +    return NS_OK; // Observers have been released automatically.
  1.1601 +  }
  1.1602 +  NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
  1.1603 +  return sRootBranch->RemoveObserver(aPref, aObserver);
  1.1604 +}
  1.1605 +
  1.1606 +// static
  1.1607 +nsresult
  1.1608 +Preferences::AddStrongObservers(nsIObserver* aObserver,
  1.1609 +                                const char** aPrefs)
  1.1610 +{
  1.1611 +  for (uint32_t i = 0; aPrefs[i]; i++) {
  1.1612 +    nsresult rv = AddStrongObserver(aObserver, aPrefs[i]);
  1.1613 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1614 +  }
  1.1615 +  return NS_OK;
  1.1616 +}
  1.1617 +
  1.1618 +// static
  1.1619 +nsresult
  1.1620 +Preferences::AddWeakObservers(nsIObserver* aObserver,
  1.1621 +                              const char** aPrefs)
  1.1622 +{
  1.1623 +  for (uint32_t i = 0; aPrefs[i]; i++) {
  1.1624 +    nsresult rv = AddWeakObserver(aObserver, aPrefs[i]);
  1.1625 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1626 +  }
  1.1627 +  return NS_OK;
  1.1628 +}
  1.1629 +
  1.1630 +// static
  1.1631 +nsresult
  1.1632 +Preferences::RemoveObservers(nsIObserver* aObserver,
  1.1633 +                             const char** aPrefs)
  1.1634 +{
  1.1635 +  if (!sPreferences && sShutdown) {
  1.1636 +    return NS_OK; // Observers have been released automatically.
  1.1637 +  }
  1.1638 +  NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
  1.1639 +
  1.1640 +  for (uint32_t i = 0; aPrefs[i]; i++) {
  1.1641 +    nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
  1.1642 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1643 +  }
  1.1644 +  return NS_OK;
  1.1645 +}
  1.1646 +
  1.1647 +// static
  1.1648 +nsresult
  1.1649 +Preferences::RegisterCallback(PrefChangedFunc aCallback,
  1.1650 +                              const char* aPref,
  1.1651 +                              void* aClosure)
  1.1652 +{
  1.1653 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1654 +
  1.1655 +  ValueObserverHashKey hashKey(aPref, aCallback);
  1.1656 +  nsRefPtr<ValueObserver> observer;
  1.1657 +  gObserverTable->Get(&hashKey, getter_AddRefs(observer));
  1.1658 +  if (observer) {
  1.1659 +    observer->AppendClosure(aClosure);
  1.1660 +    return NS_OK;
  1.1661 +  }
  1.1662 +
  1.1663 +  observer = new ValueObserver(aPref, aCallback);
  1.1664 +  observer->AppendClosure(aClosure);
  1.1665 +  nsresult rv = AddStrongObserver(observer, aPref);
  1.1666 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1667 +  gObserverTable->Put(observer, observer);
  1.1668 +  return NS_OK;
  1.1669 +}
  1.1670 +
  1.1671 +// static
  1.1672 +nsresult
  1.1673 +Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
  1.1674 +                                     const char* aPref,
  1.1675 +                                     void* aClosure)
  1.1676 +{
  1.1677 +  nsresult rv = RegisterCallback(aCallback, aPref, aClosure);
  1.1678 +  if (NS_SUCCEEDED(rv)) {
  1.1679 +    (*aCallback)(aPref, aClosure);
  1.1680 +  }
  1.1681 +  return rv;
  1.1682 +}
  1.1683 +
  1.1684 +// static
  1.1685 +nsresult
  1.1686 +Preferences::UnregisterCallback(PrefChangedFunc aCallback,
  1.1687 +                                const char* aPref,
  1.1688 +                                void* aClosure)
  1.1689 +{
  1.1690 +  if (!sPreferences && sShutdown) {
  1.1691 +    return NS_OK; // Observers have been released automatically.
  1.1692 +  }
  1.1693 +  NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
  1.1694 +
  1.1695 +  ValueObserverHashKey hashKey(aPref, aCallback);
  1.1696 +  nsRefPtr<ValueObserver> observer;
  1.1697 +  gObserverTable->Get(&hashKey, getter_AddRefs(observer));
  1.1698 +  if (!observer) {
  1.1699 +    return NS_OK;
  1.1700 +  }
  1.1701 +
  1.1702 +  observer->RemoveClosure(aClosure);
  1.1703 +  if (observer->HasNoClosures()) {
  1.1704 +    // Delete the callback since its list of closures is empty.
  1.1705 +    gObserverTable->Remove(observer);
  1.1706 +  }
  1.1707 +  return NS_OK;
  1.1708 +}
  1.1709 +
  1.1710 +static void BoolVarChanged(const char* aPref, void* aClosure)
  1.1711 +{
  1.1712 +  CacheData* cache = static_cast<CacheData*>(aClosure);
  1.1713 +  *((bool*)cache->cacheLocation) =
  1.1714 +    Preferences::GetBool(aPref, cache->defaultValueBool);
  1.1715 +}
  1.1716 +
  1.1717 +// static
  1.1718 +nsresult
  1.1719 +Preferences::AddBoolVarCache(bool* aCache,
  1.1720 +                             const char* aPref,
  1.1721 +                             bool aDefault)
  1.1722 +{
  1.1723 +  NS_ASSERTION(aCache, "aCache must not be NULL");
  1.1724 +  *aCache = GetBool(aPref, aDefault);
  1.1725 +  CacheData* data = new CacheData();
  1.1726 +  data->cacheLocation = aCache;
  1.1727 +  data->defaultValueBool = aDefault;
  1.1728 +  gCacheData->AppendElement(data);
  1.1729 +  return RegisterCallback(BoolVarChanged, aPref, data);
  1.1730 +}
  1.1731 +
  1.1732 +static void IntVarChanged(const char* aPref, void* aClosure)
  1.1733 +{
  1.1734 +  CacheData* cache = static_cast<CacheData*>(aClosure);
  1.1735 +  *((int32_t*)cache->cacheLocation) =
  1.1736 +    Preferences::GetInt(aPref, cache->defaultValueInt);
  1.1737 +}
  1.1738 +
  1.1739 +// static
  1.1740 +nsresult
  1.1741 +Preferences::AddIntVarCache(int32_t* aCache,
  1.1742 +                            const char* aPref,
  1.1743 +                            int32_t aDefault)
  1.1744 +{
  1.1745 +  NS_ASSERTION(aCache, "aCache must not be NULL");
  1.1746 +  *aCache = Preferences::GetInt(aPref, aDefault);
  1.1747 +  CacheData* data = new CacheData();
  1.1748 +  data->cacheLocation = aCache;
  1.1749 +  data->defaultValueInt = aDefault;
  1.1750 +  gCacheData->AppendElement(data);
  1.1751 +  return RegisterCallback(IntVarChanged, aPref, data);
  1.1752 +}
  1.1753 +
  1.1754 +static void UintVarChanged(const char* aPref, void* aClosure)
  1.1755 +{
  1.1756 +  CacheData* cache = static_cast<CacheData*>(aClosure);
  1.1757 +  *((uint32_t*)cache->cacheLocation) =
  1.1758 +    Preferences::GetUint(aPref, cache->defaultValueUint);
  1.1759 +}
  1.1760 +
  1.1761 +// static
  1.1762 +nsresult
  1.1763 +Preferences::AddUintVarCache(uint32_t* aCache,
  1.1764 +                             const char* aPref,
  1.1765 +                             uint32_t aDefault)
  1.1766 +{
  1.1767 +  NS_ASSERTION(aCache, "aCache must not be NULL");
  1.1768 +  *aCache = Preferences::GetUint(aPref, aDefault);
  1.1769 +  CacheData* data = new CacheData();
  1.1770 +  data->cacheLocation = aCache;
  1.1771 +  data->defaultValueUint = aDefault;
  1.1772 +  gCacheData->AppendElement(data);
  1.1773 +  return RegisterCallback(UintVarChanged, aPref, data);
  1.1774 +}
  1.1775 +
  1.1776 +static void FloatVarChanged(const char* aPref, void* aClosure)
  1.1777 +{
  1.1778 +  CacheData* cache = static_cast<CacheData*>(aClosure);
  1.1779 +  *((float*)cache->cacheLocation) =
  1.1780 +    Preferences::GetFloat(aPref, cache->defaultValueFloat);
  1.1781 +}
  1.1782 +
  1.1783 +// static
  1.1784 +nsresult
  1.1785 +Preferences::AddFloatVarCache(float* aCache,
  1.1786 +                             const char* aPref,
  1.1787 +                             float aDefault)
  1.1788 +{
  1.1789 +  NS_ASSERTION(aCache, "aCache must not be NULL");
  1.1790 +  *aCache = Preferences::GetFloat(aPref, aDefault);
  1.1791 +  CacheData* data = new CacheData();
  1.1792 +  data->cacheLocation = aCache;
  1.1793 +  data->defaultValueFloat = aDefault;
  1.1794 +  gCacheData->AppendElement(data);
  1.1795 +  return RegisterCallback(FloatVarChanged, aPref, data);
  1.1796 +}
  1.1797 +
  1.1798 +// static
  1.1799 +nsresult
  1.1800 +Preferences::GetDefaultBool(const char* aPref, bool* aResult)
  1.1801 +{
  1.1802 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1803 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1804 +  return PREF_GetBoolPref(aPref, aResult, true);
  1.1805 +}
  1.1806 +
  1.1807 +// static
  1.1808 +nsresult
  1.1809 +Preferences::GetDefaultInt(const char* aPref, int32_t* aResult)
  1.1810 +{
  1.1811 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1812 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1813 +  return PREF_GetIntPref(aPref, aResult, true);
  1.1814 +}
  1.1815 +
  1.1816 +// static
  1.1817 +nsresult
  1.1818 +Preferences::GetDefaultCString(const char* aPref, nsACString* aResult)
  1.1819 +{
  1.1820 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1821 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1822 +  nsAutoCString result;
  1.1823 +  nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
  1.1824 +  if (NS_SUCCEEDED(rv)) {
  1.1825 +    *aResult = result;
  1.1826 +  }
  1.1827 +  return rv;
  1.1828 +}
  1.1829 +
  1.1830 +// static
  1.1831 +nsresult
  1.1832 +Preferences::GetDefaultString(const char* aPref, nsAString* aResult)
  1.1833 +{
  1.1834 +  NS_PRECONDITION(aResult, "aResult must not be NULL");
  1.1835 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1836 +  nsAutoCString result;
  1.1837 +  nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
  1.1838 +  if (NS_SUCCEEDED(rv)) {
  1.1839 +    CopyUTF8toUTF16(result, *aResult);
  1.1840 +  }
  1.1841 +  return rv;
  1.1842 +}
  1.1843 +
  1.1844 +// static
  1.1845 +nsresult
  1.1846 +Preferences::GetDefaultLocalizedCString(const char* aPref,
  1.1847 +                                        nsACString* aResult)
  1.1848 +{
  1.1849 +  nsAutoString result;
  1.1850 +  nsresult rv = GetDefaultLocalizedString(aPref, &result);
  1.1851 +  if (NS_SUCCEEDED(rv)) {
  1.1852 +    CopyUTF16toUTF8(result, *aResult);
  1.1853 +  }
  1.1854 +  return rv;
  1.1855 +}
  1.1856 +
  1.1857 +// static
  1.1858 +nsresult
  1.1859 +Preferences::GetDefaultLocalizedString(const char* aPref,
  1.1860 +                                       nsAString* aResult)
  1.1861 +{
  1.1862 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1863 +  nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
  1.1864 +  nsresult rv =
  1.1865 +    sDefaultRootBranch->GetComplexValue(aPref,
  1.1866 +                                        NS_GET_IID(nsIPrefLocalizedString),
  1.1867 +                                        getter_AddRefs(prefLocalString));
  1.1868 +  if (NS_SUCCEEDED(rv)) {
  1.1869 +    NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
  1.1870 +    prefLocalString->GetData(getter_Copies(*aResult));
  1.1871 +  }
  1.1872 +  return rv;
  1.1873 +}
  1.1874 +
  1.1875 +// static
  1.1876 +nsAdoptingString
  1.1877 +Preferences::GetDefaultString(const char* aPref)
  1.1878 +{
  1.1879 +  nsAdoptingString result;
  1.1880 +  GetDefaultString(aPref, &result);
  1.1881 +  return result;
  1.1882 +}
  1.1883 +
  1.1884 +// static
  1.1885 +nsAdoptingCString
  1.1886 +Preferences::GetDefaultCString(const char* aPref)
  1.1887 +{
  1.1888 +  nsAdoptingCString result;
  1.1889 +  PREF_CopyCharPref(aPref, getter_Copies(result), true);
  1.1890 +  return result;
  1.1891 +}
  1.1892 +
  1.1893 +// static
  1.1894 +nsAdoptingString
  1.1895 +Preferences::GetDefaultLocalizedString(const char* aPref)
  1.1896 +{
  1.1897 +  nsAdoptingString result;
  1.1898 +  GetDefaultLocalizedString(aPref, &result);
  1.1899 +  return result;
  1.1900 +}
  1.1901 +
  1.1902 +// static
  1.1903 +nsAdoptingCString
  1.1904 +Preferences::GetDefaultLocalizedCString(const char* aPref)
  1.1905 +{
  1.1906 +  nsAdoptingCString result;
  1.1907 +  GetDefaultLocalizedCString(aPref, &result);
  1.1908 +  return result;
  1.1909 +}
  1.1910 +
  1.1911 +// static
  1.1912 +nsresult
  1.1913 +Preferences::GetDefaultComplex(const char* aPref, const nsIID &aType,
  1.1914 +                               void** aResult)
  1.1915 +{
  1.1916 +  NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
  1.1917 +  return sDefaultRootBranch->GetComplexValue(aPref, aType, aResult);
  1.1918 +}
  1.1919 +
  1.1920 +// static
  1.1921 +int32_t
  1.1922 +Preferences::GetDefaultType(const char* aPref)
  1.1923 +{
  1.1924 +  NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
  1.1925 +  int32_t result;
  1.1926 +  return NS_SUCCEEDED(sDefaultRootBranch->GetPrefType(aPref, &result)) ?
  1.1927 +    result : nsIPrefBranch::PREF_INVALID;
  1.1928 +}
  1.1929 +
  1.1930 +} // namespace mozilla
  1.1931 +
  1.1932 +#undef ENSURE_MAIN_PROCESS

mercurial