modules/libpref/src/Preferences.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial