Bumping manifests a=b2g-bump
[gecko.git] / modules / libpref / Preferences.cpp
blob070043b6d2f572dbacee419db831e13ba02875bf
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/MemoryReporting.h"
8 #include "mozilla/dom/ContentChild.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/HashFunctions.h"
14 #include "nsXULAppAPI.h"
16 #include "mozilla/Preferences.h"
17 #include "nsAppDirectoryServiceDefs.h"
18 #include "nsDataHashtable.h"
19 #include "nsDirectoryServiceDefs.h"
20 #include "nsICategoryManager.h"
21 #include "nsCategoryManagerUtils.h"
22 #include "nsNetUtil.h"
23 #include "nsIFile.h"
24 #include "nsIInputStream.h"
25 #include "nsIObserverService.h"
26 #include "nsIStringEnumerator.h"
27 #include "nsIZipReader.h"
28 #include "nsPrefBranch.h"
29 #include "nsXPIDLString.h"
30 #include "nsCRT.h"
31 #include "nsCOMArray.h"
32 #include "nsXPCOMCID.h"
33 #include "nsAutoPtr.h"
34 #include "nsPrintfCString.h"
36 #include "nsQuickSort.h"
37 #include "pldhash.h"
39 #include "prefapi.h"
40 #include "prefread.h"
41 #include "prefapi_private_data.h"
43 #include "mozilla/Omnijar.h"
44 #include "nsZipArchive.h"
46 #include "nsTArray.h"
47 #include "nsRefPtrHashtable.h"
48 #include "nsIMemoryReporter.h"
49 #include "nsThreadUtils.h"
51 #ifdef DEBUG
52 #define ENSURE_MAIN_PROCESS(message, pref) do { \
53 if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) { \
54 nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref); \
55 NS_WARNING(msg.get()); \
56 return NS_ERROR_NOT_AVAILABLE; \
57 } \
58 } while (0);
59 #else
60 #define ENSURE_MAIN_PROCESS(message, pref) \
61 if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) { \
62 return NS_ERROR_NOT_AVAILABLE; \
64 #endif
66 class PrefCallback;
68 namespace mozilla {
70 // Definitions
71 #define INITIAL_PREF_FILES 10
72 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
74 // Prototypes
75 static nsresult openPrefFile(nsIFile* aFile);
76 static nsresult pref_InitInitialObjects(void);
77 static nsresult pref_LoadPrefsInDirList(const char *listId);
78 static nsresult ReadExtensionPrefs(nsIFile *aFile);
80 static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
81 static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease";
82 static const char kChannelPref[] = "app.update.channel";
84 Preferences* Preferences::sPreferences = nullptr;
85 nsIPrefBranch* Preferences::sRootBranch = nullptr;
86 nsIPrefBranch* Preferences::sDefaultRootBranch = nullptr;
87 bool Preferences::sShutdown = false;
89 class ValueObserverHashKey : public PLDHashEntryHdr {
90 public:
91 typedef ValueObserverHashKey* KeyType;
92 typedef const ValueObserverHashKey* KeyTypePointer;
94 static const ValueObserverHashKey* KeyToPointer(ValueObserverHashKey *aKey)
96 return aKey;
99 static PLDHashNumber HashKey(const ValueObserverHashKey *aKey)
101 PLDHashNumber hash = HashString(aKey->mPrefName);
102 return AddToHash(hash, aKey->mCallback);
105 ValueObserverHashKey(const char *aPref, PrefChangedFunc aCallback) :
106 mPrefName(aPref), mCallback(aCallback) { }
108 explicit ValueObserverHashKey(const ValueObserverHashKey *aOther) :
109 mPrefName(aOther->mPrefName), mCallback(aOther->mCallback)
112 bool KeyEquals(const ValueObserverHashKey *aOther) const
114 return mCallback == aOther->mCallback && mPrefName == aOther->mPrefName;
117 ValueObserverHashKey *GetKey() const
119 return const_cast<ValueObserverHashKey*>(this);
122 enum { ALLOW_MEMMOVE = true };
124 nsCString mPrefName;
125 PrefChangedFunc mCallback;
128 class ValueObserver MOZ_FINAL : public nsIObserver,
129 public ValueObserverHashKey
131 ~ValueObserver() {
132 Preferences::RemoveObserver(this, mPrefName.get());
135 public:
136 NS_DECL_ISUPPORTS
137 NS_DECL_NSIOBSERVER
139 ValueObserver(const char *aPref, PrefChangedFunc aCallback)
140 : ValueObserverHashKey(aPref, aCallback) { }
142 void AppendClosure(void *aClosure) {
143 mClosures.AppendElement(aClosure);
146 void RemoveClosure(void *aClosure) {
147 mClosures.RemoveElement(aClosure);
150 bool HasNoClosures() {
151 return mClosures.Length() == 0;
154 nsTArray<void*> mClosures;
157 NS_IMPL_ISUPPORTS(ValueObserver, nsIObserver)
159 NS_IMETHODIMP
160 ValueObserver::Observe(nsISupports *aSubject,
161 const char *aTopic,
162 const char16_t *aData)
164 NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
165 "invalid topic");
166 NS_ConvertUTF16toUTF8 data(aData);
167 for (uint32_t i = 0; i < mClosures.Length(); i++) {
168 mCallback(data.get(), mClosures.ElementAt(i));
171 return NS_OK;
174 struct CacheData {
175 void* cacheLocation;
176 union {
177 bool defaultValueBool;
178 int32_t defaultValueInt;
179 uint32_t defaultValueUint;
180 float defaultValueFloat;
184 static nsTArray<nsAutoPtr<CacheData> >* gCacheData = nullptr;
185 static nsRefPtrHashtable<ValueObserverHashKey,
186 ValueObserver>* gObserverTable = nullptr;
188 #ifdef DEBUG
189 static bool
190 HaveExistingCacheFor(void* aPtr)
192 MOZ_ASSERT(NS_IsMainThread());
193 if (gCacheData) {
194 for (size_t i = 0, count = gCacheData->Length(); i < count; ++i) {
195 if ((*gCacheData)[i]->cacheLocation == aPtr) {
196 return true;
200 return false;
203 static void
204 AssertNotAlreadyCached(const char* aPrefType,
205 const char* aPref,
206 void* aPtr)
208 if (HaveExistingCacheFor(aPtr)) {
209 fprintf_stderr(stderr,
210 "Attempt to add a %s pref cache for preference '%s' at address '%p'"
211 "was made. However, a pref was already cached at this address.\n",
212 aPrefType, aPref, aPtr);
213 MOZ_ASSERT(false, "Should not have an existing pref cache for this address");
216 #endif
218 static size_t
219 SizeOfObserverEntryExcludingThis(ValueObserverHashKey* aKey,
220 const nsRefPtr<ValueObserver>& aData,
221 mozilla::MallocSizeOf aMallocSizeOf,
222 void*)
224 size_t n = 0;
225 n += aKey->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
226 n += aData->mClosures.SizeOfExcludingThis(aMallocSizeOf);
227 return n;
230 // Although this is a member of Preferences, it measures sPreferences and
231 // several other global structures.
232 /* static */ int64_t
233 Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf)
235 NS_ENSURE_TRUE(InitStaticMembers(), 0);
237 size_t n = aMallocSizeOf(sPreferences);
238 if (gHashTable.ops) {
239 // pref keys are allocated in a private arena, which we count elsewhere.
240 // pref stringvals are allocated out of the same private arena.
241 n += PL_DHashTableSizeOfExcludingThis(&gHashTable, nullptr, aMallocSizeOf);
243 if (gCacheData) {
244 n += gCacheData->SizeOfIncludingThis(aMallocSizeOf);
245 for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) {
246 n += aMallocSizeOf((*gCacheData)[i]);
249 if (gObserverTable) {
250 n += aMallocSizeOf(gObserverTable);
251 n += gObserverTable->SizeOfExcludingThis(SizeOfObserverEntryExcludingThis,
252 aMallocSizeOf);
254 // We don't measure sRootBranch and sDefaultRootBranch here because
255 // DMD indicates they are not significant.
256 n += pref_SizeOfPrivateData(aMallocSizeOf);
257 return n;
260 class PreferenceServiceReporter MOZ_FINAL : public nsIMemoryReporter
262 ~PreferenceServiceReporter() {}
264 public:
265 NS_DECL_ISUPPORTS
266 NS_DECL_NSIMEMORYREPORTER
268 protected:
269 static const uint32_t kSuspectReferentCount = 1000;
270 static PLDHashOperator CountReferents(PrefCallback* aKey,
271 nsAutoPtr<PrefCallback>& aCallback,
272 void* aClosure);
275 NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)
277 struct PreferencesReferentCount {
278 PreferencesReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {}
279 size_t numStrong;
280 size_t numWeakAlive;
281 size_t numWeakDead;
282 nsTArray<nsCString> suspectPreferences;
283 // Count of the number of referents for each preference.
284 nsDataHashtable<nsCStringHashKey, uint32_t> prefCounter;
287 PLDHashOperator
288 PreferenceServiceReporter::CountReferents(PrefCallback* aKey,
289 nsAutoPtr<PrefCallback>& aCallback,
290 void* aClosure)
292 PreferencesReferentCount* referentCount =
293 static_cast<PreferencesReferentCount*>(aClosure);
295 nsPrefBranch* prefBranch = aCallback->GetPrefBranch();
296 const char* pref = prefBranch->getPrefName(aCallback->GetDomain().get());
298 if (aCallback->IsWeak()) {
299 nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(aCallback->mWeakRef);
300 if (callbackRef) {
301 referentCount->numWeakAlive++;
302 } else {
303 referentCount->numWeakDead++;
305 } else {
306 referentCount->numStrong++;
309 nsDependentCString prefString(pref);
310 uint32_t oldCount = 0;
311 referentCount->prefCounter.Get(prefString, &oldCount);
312 uint32_t currentCount = oldCount + 1;
313 referentCount->prefCounter.Put(prefString, currentCount);
315 // Keep track of preferences that have a suspiciously large
316 // number of referents (symptom of leak).
317 if (currentCount == kSuspectReferentCount) {
318 referentCount->suspectPreferences.AppendElement(prefString);
321 return PL_DHASH_NEXT;
324 MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)
326 NS_IMETHODIMP
327 PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb,
328 nsISupports* aClosure,
329 bool aAnonymize)
331 #define REPORT(_path, _kind, _units, _amount, _desc) \
332 do { \
333 nsresult rv; \
334 rv = aCb->Callback(EmptyCString(), _path, _kind, \
335 _units, _amount, NS_LITERAL_CSTRING(_desc), \
336 aClosure); \
337 NS_ENSURE_SUCCESS(rv, rv); \
338 } while (0)
340 REPORT(NS_LITERAL_CSTRING("explicit/preferences"),
341 KIND_HEAP, UNITS_BYTES,
342 Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf),
343 "Memory used by the preferences system.");
345 nsPrefBranch* rootBranch =
346 static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
347 if (!rootBranch) {
348 return NS_OK;
351 PreferencesReferentCount referentCount;
352 rootBranch->mObservers.Enumerate(&CountReferents, &referentCount);
354 for (uint32_t i = 0; i < referentCount.suspectPreferences.Length(); i++) {
355 nsCString& suspect = referentCount.suspectPreferences[i];
356 uint32_t totalReferentCount = 0;
357 referentCount.prefCounter.Get(suspect, &totalReferentCount);
359 nsPrintfCString suspectPath("preference-service-suspect/"
360 "referent(pref=%s)", suspect.get());
362 REPORT(suspectPath,
363 KIND_OTHER, UNITS_COUNT, totalReferentCount,
364 "A preference with a suspiciously large number "
365 "referents (symptom of a leak).");
368 REPORT(NS_LITERAL_CSTRING("preference-service/referent/strong"),
369 KIND_OTHER, UNITS_COUNT, referentCount.numStrong,
370 "The number of strong referents held by the preference service.");
372 REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/alive"),
373 KIND_OTHER, UNITS_COUNT, referentCount.numWeakAlive,
374 "The number of weak referents held by the preference service "
375 "that are still alive.");
377 REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/dead"),
378 KIND_OTHER, UNITS_COUNT, referentCount.numWeakDead,
379 "The number of weak referents held by the preference service "
380 "that are dead.");
382 #undef REPORT
384 return NS_OK;
387 namespace {
388 class AddPreferencesMemoryReporterRunnable : public nsRunnable
390 NS_IMETHOD Run()
392 return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
395 } // anonymous namespace
397 // static
398 Preferences*
399 Preferences::GetInstanceForService()
401 if (sPreferences) {
402 NS_ADDREF(sPreferences);
403 return sPreferences;
406 NS_ENSURE_TRUE(!sShutdown, nullptr);
408 sRootBranch = new nsPrefBranch("", false);
409 NS_ADDREF(sRootBranch);
410 sDefaultRootBranch = new nsPrefBranch("", true);
411 NS_ADDREF(sDefaultRootBranch);
413 sPreferences = new Preferences();
414 NS_ADDREF(sPreferences);
416 if (NS_FAILED(sPreferences->Init())) {
417 // The singleton instance will delete sRootBranch and sDefaultRootBranch.
418 NS_RELEASE(sPreferences);
419 return nullptr;
422 gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
424 gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
426 // Preferences::GetInstanceForService() can be called from GetService(), and
427 // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To
428 // avoid a potential recursive GetService() call, we can't register the
429 // memory reporter here; instead, do it off a runnable.
430 nsRefPtr<AddPreferencesMemoryReporterRunnable> runnable =
431 new AddPreferencesMemoryReporterRunnable();
432 NS_DispatchToMainThread(runnable);
434 NS_ADDREF(sPreferences);
435 return sPreferences;
438 // static
439 bool
440 Preferences::InitStaticMembers()
442 #ifndef MOZ_B2G
443 MOZ_ASSERT(NS_IsMainThread());
444 #endif
446 if (!sShutdown && !sPreferences) {
447 nsCOMPtr<nsIPrefService> prefService =
448 do_GetService(NS_PREFSERVICE_CONTRACTID);
451 return sPreferences != nullptr;
454 // static
455 void
456 Preferences::Shutdown()
458 if (!sShutdown) {
459 sShutdown = true; // Don't create the singleton instance after here.
461 // Don't set sPreferences to nullptr here. The instance may be grabbed by
462 // other modules. The utility methods of Preferences should be available
463 // until the singleton instance actually released.
464 if (sPreferences) {
465 sPreferences->Release();
470 //-----------------------------------------------------------------------------
473 * Constructor/Destructor
476 Preferences::Preferences()
480 Preferences::~Preferences()
482 NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?");
484 delete gObserverTable;
485 gObserverTable = nullptr;
487 delete gCacheData;
488 gCacheData = nullptr;
490 NS_RELEASE(sRootBranch);
491 NS_RELEASE(sDefaultRootBranch);
493 sPreferences = nullptr;
495 PREF_Cleanup();
500 * nsISupports Implementation
503 NS_IMPL_ADDREF(Preferences)
504 NS_IMPL_RELEASE(Preferences)
506 NS_INTERFACE_MAP_BEGIN(Preferences)
507 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
508 NS_INTERFACE_MAP_ENTRY(nsIPrefService)
509 NS_INTERFACE_MAP_ENTRY(nsIObserver)
510 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
511 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
512 NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
513 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
514 NS_INTERFACE_MAP_END
518 * nsIPrefService Implementation
521 nsresult
522 Preferences::Init()
524 nsresult rv;
526 rv = PREF_Init();
527 NS_ENSURE_SUCCESS(rv, rv);
529 rv = pref_InitInitialObjects();
530 NS_ENSURE_SUCCESS(rv, rv);
532 using mozilla::dom::ContentChild;
533 if (XRE_GetProcessType() == GeckoProcessType_Content) {
534 InfallibleTArray<PrefSetting> prefs;
535 ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);
537 // Store the array
538 for (uint32_t i = 0; i < prefs.Length(); ++i) {
539 pref_SetPref(prefs[i]);
541 return NS_OK;
544 nsXPIDLCString lockFileName;
546 * The following is a small hack which will allow us to only load the library
547 * which supports the netscape.cfg file if the preference is defined. We
548 * test for the existence of the pref, set in the all.js (mozilla) or
549 * all-ns.js (netscape 6), and if it exists we startup the pref config
550 * category which will do the rest.
553 rv = PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName), false);
554 if (NS_SUCCEEDED(rv))
555 NS_CreateServicesFromCategory("pref-config-startup",
556 static_cast<nsISupports *>(static_cast<void *>(this)),
557 "pref-config-startup");
559 nsCOMPtr<nsIObserverService> observerService =
560 mozilla::services::GetObserverService();
561 if (!observerService)
562 return NS_ERROR_FAILURE;
564 rv = observerService->AddObserver(this, "profile-before-change", true);
566 observerService->AddObserver(this, "load-extension-defaults", true);
567 observerService->AddObserver(this, "suspend_process_notification", true);
569 return(rv);
572 // static
573 nsresult
574 Preferences::ResetAndReadUserPrefs()
576 sPreferences->ResetUserPrefs();
577 return sPreferences->ReadUserPrefs(nullptr);
580 NS_IMETHODIMP
581 Preferences::Observe(nsISupports *aSubject, const char *aTopic,
582 const char16_t *someData)
584 if (XRE_GetProcessType() == GeckoProcessType_Content)
585 return NS_ERROR_NOT_AVAILABLE;
587 nsresult rv = NS_OK;
589 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
590 rv = SavePrefFile(nullptr);
591 } else if (!strcmp(aTopic, "load-extension-defaults")) {
592 pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
593 } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
594 // Reload the default prefs from file.
595 pref_InitInitialObjects();
596 } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) {
597 // Our process is being suspended. The OS may wake our process later,
598 // or it may kill the process. In case our process is going to be killed
599 // from the suspended state, we save preferences before suspending.
600 rv = SavePrefFile(nullptr);
602 return rv;
606 NS_IMETHODIMP
607 Preferences::ReadUserPrefs(nsIFile *aFile)
609 if (XRE_GetProcessType() == GeckoProcessType_Content) {
610 NS_ERROR("cannot load prefs from content process");
611 return NS_ERROR_NOT_AVAILABLE;
614 nsresult rv;
616 if (nullptr == aFile) {
617 rv = UseDefaultPrefFile();
618 // A user pref file is optional.
619 // Ignore all errors related to it, so we retain 'rv' value :-|
620 (void) UseUserPrefFile();
622 // Migrate the old prerelease telemetry pref
623 if (!Preferences::GetBool(kOldTelemetryPref, true)) {
624 Preferences::SetBool(kTelemetryPref, false);
625 Preferences::ClearUser(kOldTelemetryPref);
628 NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
629 } else {
630 rv = ReadAndOwnUserPrefFile(aFile);
633 return rv;
636 NS_IMETHODIMP
637 Preferences::ResetPrefs()
639 if (XRE_GetProcessType() == GeckoProcessType_Content) {
640 NS_ERROR("cannot reset prefs from content process");
641 return NS_ERROR_NOT_AVAILABLE;
644 NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
645 PREF_CleanupPrefs();
647 nsresult rv = PREF_Init();
648 NS_ENSURE_SUCCESS(rv, rv);
650 return pref_InitInitialObjects();
653 NS_IMETHODIMP
654 Preferences::ResetUserPrefs()
656 if (XRE_GetProcessType() == GeckoProcessType_Content) {
657 NS_ERROR("cannot reset user prefs from content process");
658 return NS_ERROR_NOT_AVAILABLE;
661 PREF_ClearAllUserPrefs();
662 return NS_OK;
665 NS_IMETHODIMP
666 Preferences::SavePrefFile(nsIFile *aFile)
668 if (XRE_GetProcessType() == GeckoProcessType_Content) {
669 NS_ERROR("cannot save pref file from content process");
670 return NS_ERROR_NOT_AVAILABLE;
673 return SavePrefFileInternal(aFile);
676 static nsresult
677 ReadExtensionPrefs(nsIFile *aFile)
679 nsresult rv;
680 nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv);
681 NS_ENSURE_SUCCESS(rv, rv);
683 rv = reader->Open(aFile);
684 NS_ENSURE_SUCCESS(rv, rv);
686 nsCOMPtr<nsIUTF8StringEnumerator> files;
687 rv = reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),
688 getter_AddRefs(files));
689 NS_ENSURE_SUCCESS(rv, rv);
691 char buffer[4096];
693 bool more;
694 while (NS_SUCCEEDED(rv = files->HasMore(&more)) && more) {
695 nsAutoCString entry;
696 rv = files->GetNext(entry);
697 NS_ENSURE_SUCCESS(rv, rv);
699 nsCOMPtr<nsIInputStream> stream;
700 rv = reader->GetInputStream(entry, getter_AddRefs(stream));
701 NS_ENSURE_SUCCESS(rv, rv);
703 uint64_t avail;
704 uint32_t read;
706 PrefParseState ps;
707 PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
708 while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) {
709 rv = stream->Read(buffer, 4096, &read);
710 if (NS_FAILED(rv)) {
711 NS_WARNING("Pref stream read failed");
712 break;
715 PREF_ParseBuf(&ps, buffer, read);
717 PREF_FinalizeParseState(&ps);
719 return rv;
722 void
723 Preferences::SetPreference(const PrefSetting& aPref)
725 pref_SetPref(aPref);
728 void
729 Preferences::GetPreference(PrefSetting* aPref)
731 PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get());
732 if (!entry)
733 return;
735 pref_GetPrefFromEntry(entry, aPref);
738 void
739 Preferences::GetPreferences(InfallibleTArray<PrefSetting>* aPrefs)
741 aPrefs->SetCapacity(gHashTable.Capacity());
742 PL_DHashTableEnumerate(&gHashTable, pref_GetPrefs, aPrefs);
745 NS_IMETHODIMP
746 Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
748 nsresult rv;
750 if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
751 // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
752 nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, false);
753 if (!prefBranch)
754 return NS_ERROR_OUT_OF_MEMORY;
756 rv = CallQueryInterface(prefBranch, _retval);
757 } else {
758 // special case caching the default root
759 nsCOMPtr<nsIPrefBranch> root(sRootBranch);
760 root.forget(_retval);
761 rv = NS_OK;
763 return rv;
766 NS_IMETHODIMP
767 Preferences::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
769 if (!aPrefRoot || !aPrefRoot[0]) {
770 nsCOMPtr<nsIPrefBranch> root(sDefaultRootBranch);
771 root.forget(_retval);
772 return NS_OK;
775 // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
776 nsRefPtr<nsPrefBranch> prefBranch = new nsPrefBranch(aPrefRoot, true);
777 if (!prefBranch)
778 return NS_ERROR_OUT_OF_MEMORY;
780 prefBranch.forget(_retval);
781 return NS_OK;
784 NS_IMETHODIMP
785 Preferences::GetDirty(bool *_retval) {
786 *_retval = gDirty;
787 return NS_OK;
790 nsresult
791 Preferences::NotifyServiceObservers(const char *aTopic)
793 nsCOMPtr<nsIObserverService> observerService =
794 mozilla::services::GetObserverService();
795 if (!observerService)
796 return NS_ERROR_FAILURE;
798 nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
799 observerService->NotifyObservers(subject, aTopic, nullptr);
801 return NS_OK;
804 nsresult
805 Preferences::UseDefaultPrefFile()
807 nsresult rv;
808 nsCOMPtr<nsIFile> aFile;
810 #if defined(XP_WIN) && defined(MOZ_METRO)
811 if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
812 rv = NS_GetSpecialDirectory(NS_METRO_APP_PREFS_50_FILE, getter_AddRefs(aFile));
813 } else
814 #endif
816 rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
819 if (NS_SUCCEEDED(rv)) {
820 rv = ReadAndOwnUserPrefFile(aFile);
821 // Most likely cause of failure here is that the file didn't
822 // exist, so save a new one. mUserPrefReadFailed will be
823 // used to catch an error in actually reading the file.
824 if (NS_FAILED(rv)) {
825 if (NS_FAILED(SavePrefFileInternal(aFile)))
826 NS_ERROR("Failed to save new shared pref file");
827 else
828 rv = NS_OK;
832 return rv;
835 nsresult
836 Preferences::UseUserPrefFile()
838 nsresult rv = NS_OK;
839 nsCOMPtr<nsIFile> aFile;
840 nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR);
842 rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile));
843 if (NS_SUCCEEDED(rv) && aFile) {
844 rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
845 if (NS_SUCCEEDED(rv)) {
846 bool exists = false;
847 aFile->Exists(&exists);
848 if (exists) {
849 rv = openPrefFile(aFile);
850 } else {
851 rv = NS_ERROR_FILE_NOT_FOUND;
855 return rv;
858 nsresult
859 Preferences::MakeBackupPrefFile(nsIFile *aFile)
861 // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
862 // "Invalidprefs.js" is removed if it exists, prior to making the copy.
863 nsAutoString newFilename;
864 nsresult rv = aFile->GetLeafName(newFilename);
865 NS_ENSURE_SUCCESS(rv, rv);
866 newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0);
867 nsCOMPtr<nsIFile> newFile;
868 rv = aFile->GetParent(getter_AddRefs(newFile));
869 NS_ENSURE_SUCCESS(rv, rv);
870 rv = newFile->Append(newFilename);
871 NS_ENSURE_SUCCESS(rv, rv);
872 bool exists = false;
873 newFile->Exists(&exists);
874 if (exists) {
875 rv = newFile->Remove(false);
876 NS_ENSURE_SUCCESS(rv, rv);
878 rv = aFile->CopyTo(nullptr, newFilename);
879 NS_ENSURE_SUCCESS(rv, rv);
880 return rv;
883 nsresult
884 Preferences::ReadAndOwnUserPrefFile(nsIFile *aFile)
886 NS_ENSURE_ARG(aFile);
888 if (mCurrentFile == aFile)
889 return NS_OK;
890 mCurrentFile = aFile;
892 nsresult rv = NS_OK;
893 bool exists = false;
894 mCurrentFile->Exists(&exists);
895 if (exists) {
896 rv = openPrefFile(mCurrentFile);
897 if (NS_FAILED(rv)) {
898 // Save a backup copy of the current (invalid) prefs file, since all prefs
899 // from the error line to the end of the file will be lost (bug 361102).
900 // TODO we should notify the user about it (bug 523725).
901 MakeBackupPrefFile(mCurrentFile);
903 } else {
904 rv = NS_ERROR_FILE_NOT_FOUND;
907 return rv;
910 nsresult
911 Preferences::SavePrefFileInternal(nsIFile *aFile)
913 if (nullptr == aFile) {
914 // the gDirty flag tells us if we should write to mCurrentFile
915 // we only check this flag when the caller wants to write to the default
916 if (!gDirty)
917 return NS_OK;
919 // It's possible that we never got a prefs file.
920 nsresult rv = NS_OK;
921 if (mCurrentFile)
922 rv = WritePrefFile(mCurrentFile);
924 return rv;
925 } else {
926 return WritePrefFile(aFile);
930 nsresult
931 Preferences::WritePrefFile(nsIFile* aFile)
933 const char outHeader[] =
934 "# Mozilla User Preferences"
935 NS_LINEBREAK
936 NS_LINEBREAK
937 "/* Do not edit this file."
938 NS_LINEBREAK
939 " *"
940 NS_LINEBREAK
941 " * If you make changes to this file while the application is running,"
942 NS_LINEBREAK
943 " * the changes will be overwritten when the application exits."
944 NS_LINEBREAK
945 " *"
946 NS_LINEBREAK
947 " * To make a manual change to preferences, you can visit the URL about:config"
948 NS_LINEBREAK
949 " */"
950 NS_LINEBREAK
951 NS_LINEBREAK;
953 nsCOMPtr<nsIOutputStream> outStreamSink;
954 nsCOMPtr<nsIOutputStream> outStream;
955 uint32_t writeAmount;
956 nsresult rv;
958 if (!gHashTable.ops)
959 return NS_ERROR_NOT_INITIALIZED;
961 // execute a "safe" save by saving through a tempfile
962 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
963 aFile,
965 0600);
966 if (NS_FAILED(rv))
967 return rv;
968 rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
969 if (NS_FAILED(rv))
970 return rv;
972 nsAutoArrayPtr<char*> valueArray(new char*[gHashTable.EntryCount()]);
973 memset(valueArray, 0, gHashTable.EntryCount() * sizeof(char*));
974 pref_saveArgs saveArgs;
975 saveArgs.prefArray = valueArray;
976 saveArgs.saveTypes = SAVE_ALL;
978 // get the lines that we're supposed to be writing to the file
979 PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
981 /* Sort the preferences to make a readable file on disk */
982 NS_QuickSort(valueArray, gHashTable.EntryCount(), sizeof(char *), pref_CompareStrings, nullptr);
984 // write out the file header
985 outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
987 char** walker = valueArray;
988 for (uint32_t valueIdx = 0; valueIdx < gHashTable.EntryCount(); valueIdx++, walker++) {
989 if (*walker) {
990 outStream->Write(*walker, strlen(*walker), &writeAmount);
991 outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
992 NS_Free(*walker);
996 // tell the safe output stream to overwrite the real prefs file
997 // (it'll abort if there were any errors during writing)
998 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
999 NS_ASSERTION(safeStream, "expected a safe output stream!");
1000 if (safeStream) {
1001 rv = safeStream->Finish();
1002 if (NS_FAILED(rv)) {
1003 NS_WARNING("failed to save prefs file! possible data loss");
1004 return rv;
1008 gDirty = false;
1009 return NS_OK;
1012 static nsresult openPrefFile(nsIFile* aFile)
1014 nsCOMPtr<nsIInputStream> inStr;
1016 nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
1017 if (NS_FAILED(rv))
1018 return rv;
1020 uint64_t fileSize64;
1021 rv = inStr->Available(&fileSize64);
1022 if (NS_FAILED(rv))
1023 return rv;
1024 NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
1026 uint32_t fileSize = (uint32_t)fileSize64;
1027 nsAutoArrayPtr<char> fileBuffer(new char[fileSize]);
1028 if (fileBuffer == nullptr)
1029 return NS_ERROR_OUT_OF_MEMORY;
1031 PrefParseState ps;
1032 PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
1034 // Read is not guaranteed to return a buf the size of fileSize,
1035 // but usually will.
1036 nsresult rv2 = NS_OK;
1037 for (;;) {
1038 uint32_t amtRead = 0;
1039 rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead);
1040 if (NS_FAILED(rv) || amtRead == 0)
1041 break;
1042 if (!PREF_ParseBuf(&ps, fileBuffer, amtRead))
1043 rv2 = NS_ERROR_FILE_CORRUPTED;
1046 PREF_FinalizeParseState(&ps);
1048 return NS_FAILED(rv) ? rv : rv2;
1052 * some stuff that gets called from Pref_Init()
1055 static int
1056 pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
1058 nsAutoCString filename1, filename2;
1059 aFile1->GetNativeLeafName(filename1);
1060 aFile2->GetNativeLeafName(filename2);
1062 return Compare(filename2, filename1);
1066 * Load default pref files from a directory. The files in the
1067 * directory are sorted reverse-alphabetically; a set of "special file
1068 * names" may be specified which are loaded after all the others.
1070 static nsresult
1071 pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, uint32_t aSpecialFilesCount)
1073 nsresult rv, rv2;
1074 bool hasMoreElements;
1076 nsCOMPtr<nsISimpleEnumerator> dirIterator;
1078 // this may fail in some normal cases, such as embedders who do not use a GRE
1079 rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
1080 if (NS_FAILED(rv)) {
1081 // If the directory doesn't exist, then we have no reason to complain. We
1082 // loaded everything (and nothing) successfully.
1083 if (rv == NS_ERROR_FILE_NOT_FOUND || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
1084 rv = NS_OK;
1085 return rv;
1088 rv = dirIterator->HasMoreElements(&hasMoreElements);
1089 NS_ENSURE_SUCCESS(rv, rv);
1091 nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
1092 nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
1093 nsCOMPtr<nsIFile> prefFile;
1095 while (hasMoreElements && NS_SUCCEEDED(rv)) {
1096 nsAutoCString leafName;
1098 nsCOMPtr<nsISupports> supports;
1099 rv = dirIterator->GetNext(getter_AddRefs(supports));
1100 prefFile = do_QueryInterface(supports);
1101 if (NS_FAILED(rv)) {
1102 break;
1105 prefFile->GetNativeLeafName(leafName);
1106 NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
1108 // Skip non-js files
1109 if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
1110 nsCaseInsensitiveCStringComparator())) {
1111 bool shouldParse = true;
1112 // separate out special files
1113 for (uint32_t i = 0; i < aSpecialFilesCount; ++i) {
1114 if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
1115 shouldParse = false;
1116 // special files should be process in order; we put them into
1117 // the array by index; this can make the array sparse
1118 specialFiles.ReplaceObjectAt(prefFile, i);
1122 if (shouldParse) {
1123 prefFiles.AppendObject(prefFile);
1127 rv = dirIterator->HasMoreElements(&hasMoreElements);
1130 if (prefFiles.Count() + specialFiles.Count() == 0) {
1131 NS_WARNING("No default pref files found.");
1132 if (NS_SUCCEEDED(rv)) {
1133 rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
1135 return rv;
1138 prefFiles.Sort(pref_CompareFileNames, nullptr);
1140 uint32_t arrayCount = prefFiles.Count();
1141 uint32_t i;
1142 for (i = 0; i < arrayCount; ++i) {
1143 rv2 = openPrefFile(prefFiles[i]);
1144 if (NS_FAILED(rv2)) {
1145 NS_ERROR("Default pref file not parsed successfully.");
1146 rv = rv2;
1150 arrayCount = specialFiles.Count();
1151 for (i = 0; i < arrayCount; ++i) {
1152 // this may be a sparse array; test before parsing
1153 nsIFile* file = specialFiles[i];
1154 if (file) {
1155 rv2 = openPrefFile(file);
1156 if (NS_FAILED(rv2)) {
1157 NS_ERROR("Special default pref file not parsed successfully.");
1158 rv = rv2;
1163 return rv;
1166 static nsresult pref_LoadPrefsInDirList(const char *listId)
1168 nsresult rv;
1169 nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
1170 if (NS_FAILED(rv))
1171 return rv;
1173 nsCOMPtr<nsISimpleEnumerator> list;
1174 dirSvc->Get(listId,
1175 NS_GET_IID(nsISimpleEnumerator),
1176 getter_AddRefs(list));
1177 if (!list)
1178 return NS_OK;
1180 bool hasMore;
1181 while (NS_SUCCEEDED(list->HasMoreElements(&hasMore)) && hasMore) {
1182 nsCOMPtr<nsISupports> elem;
1183 list->GetNext(getter_AddRefs(elem));
1184 if (!elem)
1185 continue;
1187 nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
1188 if (!path)
1189 continue;
1191 nsAutoCString leaf;
1192 path->GetNativeLeafName(leaf);
1194 // Do we care if a file provided by this process fails to load?
1195 if (Substring(leaf, leaf.Length() - 4).EqualsLiteral(".xpi"))
1196 ReadExtensionPrefs(path);
1197 else
1198 pref_LoadPrefsInDir(path, nullptr, 0);
1200 return NS_OK;
1203 static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
1205 nsZipItemPtr<char> manifest(jarReader, name, true);
1206 NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
1208 PrefParseState ps;
1209 PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr);
1210 PREF_ParseBuf(&ps, manifest, manifest.Length());
1211 PREF_FinalizeParseState(&ps);
1213 return NS_OK;
1216 //----------------------------------------------------------------------------------------
1217 // Initialize default preference JavaScript buffers from
1218 // appropriate TEXT resources
1219 //----------------------------------------------------------------------------------------
1220 static nsresult pref_InitInitialObjects()
1222 nsresult rv;
1224 // In omni.jar case, we load the following prefs:
1225 // - jar:$gre/omni.jar!/greprefs.js
1226 // - jar:$gre/omni.jar!/defaults/pref/*.js
1227 // In non omni.jar case, we load:
1228 // - $gre/greprefs.js
1230 // In both cases, we also load:
1231 // - $gre/defaults/pref/*.js
1232 // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
1233 // on $app == $gre case ; we load all files instead of channel-prefs.js only
1234 // to have the same behaviour as $app != $gre, where this is required as
1235 // a supported location for GRE preferences.
1237 // When $app != $gre, we additionally load, in omni.jar case:
1238 // - jar:$app/omni.jar!/defaults/preferences/*.js
1239 // - $app/defaults/preferences/*.js
1240 // and in non omni.jar case:
1241 // - $app/defaults/preferences/*.js
1242 // When $app == $gre, we additionally load, in omni.jar case:
1243 // - jar:$gre/omni.jar!/defaults/preferences/*.js
1244 // Thus, in omni.jar case, we always load app-specific default preferences
1245 // from omni.jar, whether or not $app == $gre.
1247 nsZipFind *findPtr;
1248 nsAutoPtr<nsZipFind> find;
1249 nsTArray<nsCString> prefEntries;
1250 const char *entryName;
1251 uint16_t entryNameLen;
1253 nsRefPtr<nsZipArchive> jarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
1254 if (jarReader) {
1255 // Load jar:$gre/omni.jar!/greprefs.js
1256 rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
1257 NS_ENSURE_SUCCESS(rv, rv);
1259 // Load jar:$gre/omni.jar!/defaults/pref/*.js
1260 rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr);
1261 NS_ENSURE_SUCCESS(rv, rv);
1263 find = findPtr;
1264 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
1265 prefEntries.AppendElement(Substring(entryName, entryNameLen));
1268 prefEntries.Sort();
1269 for (uint32_t i = prefEntries.Length(); i--; ) {
1270 rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
1271 if (NS_FAILED(rv))
1272 NS_WARNING("Error parsing preferences.");
1274 } else {
1275 // Load $gre/greprefs.js
1276 nsCOMPtr<nsIFile> greprefsFile;
1277 rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greprefsFile));
1278 NS_ENSURE_SUCCESS(rv, rv);
1280 rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
1281 NS_ENSURE_SUCCESS(rv, rv);
1283 rv = openPrefFile(greprefsFile);
1284 if (NS_FAILED(rv))
1285 NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
1288 // Load $gre/defaults/pref/*.js
1289 nsCOMPtr<nsIFile> defaultPrefDir;
1291 rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
1292 NS_ENSURE_SUCCESS(rv, rv);
1294 /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
1295 static const char* specialFiles[] = {
1296 #if defined(XP_MACOSX)
1297 "macprefs.js"
1298 #elif defined(XP_WIN)
1299 "winpref.js"
1300 #elif defined(XP_UNIX)
1301 "unix.js"
1302 #if defined(VMS)
1303 , "openvms.js"
1304 #elif defined(_AIX)
1305 , "aix.js"
1306 #endif
1307 #elif defined(XP_BEOS)
1308 "beos.js"
1309 #endif
1312 rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
1313 if (NS_FAILED(rv))
1314 NS_WARNING("Error parsing application default preferences.");
1316 // Load jar:$app/omni.jar!/defaults/preferences/*.js
1317 // or jar:$gre/omni.jar!/defaults/preferences/*.js.
1318 nsRefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
1319 // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which
1320 // case we look for app-specific default preferences in $gre.
1321 if (!appJarReader)
1322 appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
1323 if (appJarReader) {
1324 rv = appJarReader->FindInit("defaults/preferences/*.js$", &findPtr);
1325 NS_ENSURE_SUCCESS(rv, rv);
1326 find = findPtr;
1327 prefEntries.Clear();
1328 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
1329 prefEntries.AppendElement(Substring(entryName, entryNameLen));
1331 prefEntries.Sort();
1332 for (uint32_t i = prefEntries.Length(); i--; ) {
1333 rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
1334 if (NS_FAILED(rv))
1335 NS_WARNING("Error parsing preferences.");
1339 rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
1340 NS_ENSURE_SUCCESS(rv, rv);
1342 // Set up the correct default for toolkit.telemetry.enabled.
1343 // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta
1344 // channel, telemetry is on by default, otherwise not. This is necessary
1345 // so that beta users who are testing final release builds don't flipflop
1346 // defaults.
1347 if (Preferences::GetDefaultType(kTelemetryPref) == PREF_INVALID) {
1348 bool prerelease = false;
1349 #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
1350 prerelease = true;
1351 #else
1352 if (Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")) {
1353 prerelease = true;
1355 #endif
1356 PREF_SetBoolPref(kTelemetryPref, prerelease, true);
1359 NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
1360 nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
1362 nsCOMPtr<nsIObserverService> observerService =
1363 mozilla::services::GetObserverService();
1364 if (!observerService)
1365 return NS_ERROR_FAILURE;
1367 observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr);
1369 return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
1373 /******************************************************************************
1375 * static utilities
1377 ******************************************************************************/
1379 // static
1380 nsresult
1381 Preferences::GetBool(const char* aPref, bool* aResult)
1383 NS_PRECONDITION(aResult, "aResult must not be NULL");
1384 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1385 return PREF_GetBoolPref(aPref, aResult, false);
1388 // static
1389 nsresult
1390 Preferences::GetInt(const char* aPref, int32_t* aResult)
1392 NS_PRECONDITION(aResult, "aResult must not be NULL");
1393 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1394 return PREF_GetIntPref(aPref, aResult, false);
1397 // static
1398 nsresult
1399 Preferences::GetFloat(const char* aPref, float* aResult)
1401 NS_PRECONDITION(aResult, "aResult must not be NULL");
1402 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1403 nsAutoCString result;
1404 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
1405 if (NS_SUCCEEDED(rv)) {
1406 *aResult = result.ToFloat(&rv);
1409 return rv;
1412 // static
1413 nsAdoptingCString
1414 Preferences::GetCString(const char* aPref)
1416 nsAdoptingCString result;
1417 PREF_CopyCharPref(aPref, getter_Copies(result), false);
1418 return result;
1421 // static
1422 nsAdoptingString
1423 Preferences::GetString(const char* aPref)
1425 nsAdoptingString result;
1426 GetString(aPref, &result);
1427 return result;
1430 // static
1431 nsresult
1432 Preferences::GetCString(const char* aPref, nsACString* aResult)
1434 NS_PRECONDITION(aResult, "aResult must not be NULL");
1435 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1436 nsAutoCString result;
1437 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
1438 if (NS_SUCCEEDED(rv)) {
1439 *aResult = result;
1441 return rv;
1444 // static
1445 nsresult
1446 Preferences::GetString(const char* aPref, nsAString* aResult)
1448 NS_PRECONDITION(aResult, "aResult must not be NULL");
1449 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1450 nsAutoCString result;
1451 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
1452 if (NS_SUCCEEDED(rv)) {
1453 CopyUTF8toUTF16(result, *aResult);
1455 return rv;
1458 // static
1459 nsAdoptingCString
1460 Preferences::GetLocalizedCString(const char* aPref)
1462 nsAdoptingCString result;
1463 GetLocalizedCString(aPref, &result);
1464 return result;
1467 // static
1468 nsAdoptingString
1469 Preferences::GetLocalizedString(const char* aPref)
1471 nsAdoptingString result;
1472 GetLocalizedString(aPref, &result);
1473 return result;
1476 // static
1477 nsresult
1478 Preferences::GetLocalizedCString(const char* aPref, nsACString* aResult)
1480 NS_PRECONDITION(aResult, "aResult must not be NULL");
1481 nsAutoString result;
1482 nsresult rv = GetLocalizedString(aPref, &result);
1483 if (NS_SUCCEEDED(rv)) {
1484 CopyUTF16toUTF8(result, *aResult);
1486 return rv;
1489 // static
1490 nsresult
1491 Preferences::GetLocalizedString(const char* aPref, nsAString* aResult)
1493 NS_PRECONDITION(aResult, "aResult must not be NULL");
1494 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1495 nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
1496 nsresult rv = sRootBranch->GetComplexValue(aPref,
1497 NS_GET_IID(nsIPrefLocalizedString),
1498 getter_AddRefs(prefLocalString));
1499 if (NS_SUCCEEDED(rv)) {
1500 NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
1501 prefLocalString->GetData(getter_Copies(*aResult));
1503 return rv;
1506 // static
1507 nsresult
1508 Preferences::GetComplex(const char* aPref, const nsIID &aType, void** aResult)
1510 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1511 return sRootBranch->GetComplexValue(aPref, aType, aResult);
1514 // static
1515 nsresult
1516 Preferences::SetCString(const char* aPref, const char* aValue)
1518 ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
1519 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1520 return PREF_SetCharPref(aPref, aValue, false);
1523 // static
1524 nsresult
1525 Preferences::SetCString(const char* aPref, const nsACString &aValue)
1527 ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref);
1528 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1529 return PREF_SetCharPref(aPref, PromiseFlatCString(aValue).get(), false);
1532 // static
1533 nsresult
1534 Preferences::SetString(const char* aPref, const char16_t* aValue)
1536 ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
1537 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1538 return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
1541 // static
1542 nsresult
1543 Preferences::SetString(const char* aPref, const nsAString &aValue)
1545 ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref);
1546 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1547 return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
1550 // static
1551 nsresult
1552 Preferences::SetBool(const char* aPref, bool aValue)
1554 ENSURE_MAIN_PROCESS("Cannot SetBool from content process:", aPref);
1555 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1556 return PREF_SetBoolPref(aPref, aValue, false);
1559 // static
1560 nsresult
1561 Preferences::SetInt(const char* aPref, int32_t aValue)
1563 ENSURE_MAIN_PROCESS("Cannot SetInt from content process:", aPref);
1564 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1565 return PREF_SetIntPref(aPref, aValue, false);
1568 // static
1569 nsresult
1570 Preferences::SetFloat(const char* aPref, float aValue)
1572 return SetCString(aPref, nsPrintfCString("%f", aValue).get());
1575 // static
1576 nsresult
1577 Preferences::SetComplex(const char* aPref, const nsIID &aType,
1578 nsISupports* aValue)
1580 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1581 return sRootBranch->SetComplexValue(aPref, aType, aValue);
1584 // static
1585 nsresult
1586 Preferences::ClearUser(const char* aPref)
1588 ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:", aPref);
1589 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1590 return PREF_ClearUserPref(aPref);
1593 // static
1594 bool
1595 Preferences::HasUserValue(const char* aPref)
1597 NS_ENSURE_TRUE(InitStaticMembers(), false);
1598 return PREF_HasUserPref(aPref);
1601 // static
1602 int32_t
1603 Preferences::GetType(const char* aPref)
1605 NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
1606 int32_t result;
1607 return NS_SUCCEEDED(sRootBranch->GetPrefType(aPref, &result)) ?
1608 result : nsIPrefBranch::PREF_INVALID;
1611 // static
1612 nsresult
1613 Preferences::AddStrongObserver(nsIObserver* aObserver,
1614 const char* aPref)
1616 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1617 return sRootBranch->AddObserver(aPref, aObserver, false);
1620 // static
1621 nsresult
1622 Preferences::AddWeakObserver(nsIObserver* aObserver,
1623 const char* aPref)
1625 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1626 return sRootBranch->AddObserver(aPref, aObserver, true);
1629 // static
1630 nsresult
1631 Preferences::RemoveObserver(nsIObserver* aObserver,
1632 const char* aPref)
1634 if (!sPreferences && sShutdown) {
1635 return NS_OK; // Observers have been released automatically.
1637 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1638 return sRootBranch->RemoveObserver(aPref, aObserver);
1641 // static
1642 nsresult
1643 Preferences::AddStrongObservers(nsIObserver* aObserver,
1644 const char** aPrefs)
1646 for (uint32_t i = 0; aPrefs[i]; i++) {
1647 nsresult rv = AddStrongObserver(aObserver, aPrefs[i]);
1648 NS_ENSURE_SUCCESS(rv, rv);
1650 return NS_OK;
1653 // static
1654 nsresult
1655 Preferences::AddWeakObservers(nsIObserver* aObserver,
1656 const char** aPrefs)
1658 for (uint32_t i = 0; aPrefs[i]; i++) {
1659 nsresult rv = AddWeakObserver(aObserver, aPrefs[i]);
1660 NS_ENSURE_SUCCESS(rv, rv);
1662 return NS_OK;
1665 // static
1666 nsresult
1667 Preferences::RemoveObservers(nsIObserver* aObserver,
1668 const char** aPrefs)
1670 if (!sPreferences && sShutdown) {
1671 return NS_OK; // Observers have been released automatically.
1673 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1675 for (uint32_t i = 0; aPrefs[i]; i++) {
1676 nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
1677 NS_ENSURE_SUCCESS(rv, rv);
1679 return NS_OK;
1682 // static
1683 nsresult
1684 Preferences::RegisterCallback(PrefChangedFunc aCallback,
1685 const char* aPref,
1686 void* aClosure)
1688 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1690 ValueObserverHashKey hashKey(aPref, aCallback);
1691 nsRefPtr<ValueObserver> observer;
1692 gObserverTable->Get(&hashKey, getter_AddRefs(observer));
1693 if (observer) {
1694 observer->AppendClosure(aClosure);
1695 return NS_OK;
1698 observer = new ValueObserver(aPref, aCallback);
1699 observer->AppendClosure(aClosure);
1700 nsresult rv = AddStrongObserver(observer, aPref);
1701 NS_ENSURE_SUCCESS(rv, rv);
1702 gObserverTable->Put(observer, observer);
1703 return NS_OK;
1706 // static
1707 nsresult
1708 Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
1709 const char* aPref,
1710 void* aClosure)
1712 nsresult rv = RegisterCallback(aCallback, aPref, aClosure);
1713 if (NS_SUCCEEDED(rv)) {
1714 (*aCallback)(aPref, aClosure);
1716 return rv;
1719 // static
1720 nsresult
1721 Preferences::UnregisterCallback(PrefChangedFunc aCallback,
1722 const char* aPref,
1723 void* aClosure)
1725 if (!sPreferences && sShutdown) {
1726 return NS_OK; // Observers have been released automatically.
1728 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1730 ValueObserverHashKey hashKey(aPref, aCallback);
1731 nsRefPtr<ValueObserver> observer;
1732 gObserverTable->Get(&hashKey, getter_AddRefs(observer));
1733 if (!observer) {
1734 return NS_OK;
1737 observer->RemoveClosure(aClosure);
1738 if (observer->HasNoClosures()) {
1739 // Delete the callback since its list of closures is empty.
1740 gObserverTable->Remove(observer);
1742 return NS_OK;
1745 static void BoolVarChanged(const char* aPref, void* aClosure)
1747 CacheData* cache = static_cast<CacheData*>(aClosure);
1748 *((bool*)cache->cacheLocation) =
1749 Preferences::GetBool(aPref, cache->defaultValueBool);
1752 // static
1753 nsresult
1754 Preferences::AddBoolVarCache(bool* aCache,
1755 const char* aPref,
1756 bool aDefault)
1758 NS_ASSERTION(aCache, "aCache must not be NULL");
1759 #ifdef DEBUG
1760 AssertNotAlreadyCached("bool", aPref, aCache);
1761 #endif
1762 *aCache = GetBool(aPref, aDefault);
1763 CacheData* data = new CacheData();
1764 data->cacheLocation = aCache;
1765 data->defaultValueBool = aDefault;
1766 gCacheData->AppendElement(data);
1767 return RegisterCallback(BoolVarChanged, aPref, data);
1770 static void IntVarChanged(const char* aPref, void* aClosure)
1772 CacheData* cache = static_cast<CacheData*>(aClosure);
1773 *((int32_t*)cache->cacheLocation) =
1774 Preferences::GetInt(aPref, cache->defaultValueInt);
1777 // static
1778 nsresult
1779 Preferences::AddIntVarCache(int32_t* aCache,
1780 const char* aPref,
1781 int32_t aDefault)
1783 NS_ASSERTION(aCache, "aCache must not be NULL");
1784 #ifdef DEBUG
1785 AssertNotAlreadyCached("int", aPref, aCache);
1786 #endif
1787 *aCache = Preferences::GetInt(aPref, aDefault);
1788 CacheData* data = new CacheData();
1789 data->cacheLocation = aCache;
1790 data->defaultValueInt = aDefault;
1791 gCacheData->AppendElement(data);
1792 return RegisterCallback(IntVarChanged, aPref, data);
1795 static void UintVarChanged(const char* aPref, void* aClosure)
1797 CacheData* cache = static_cast<CacheData*>(aClosure);
1798 *((uint32_t*)cache->cacheLocation) =
1799 Preferences::GetUint(aPref, cache->defaultValueUint);
1802 // static
1803 nsresult
1804 Preferences::AddUintVarCache(uint32_t* aCache,
1805 const char* aPref,
1806 uint32_t aDefault)
1808 NS_ASSERTION(aCache, "aCache must not be NULL");
1809 #ifdef DEBUG
1810 AssertNotAlreadyCached("uint", aPref, aCache);
1811 #endif
1812 *aCache = Preferences::GetUint(aPref, aDefault);
1813 CacheData* data = new CacheData();
1814 data->cacheLocation = aCache;
1815 data->defaultValueUint = aDefault;
1816 gCacheData->AppendElement(data);
1817 return RegisterCallback(UintVarChanged, aPref, data);
1820 static void FloatVarChanged(const char* aPref, void* aClosure)
1822 CacheData* cache = static_cast<CacheData*>(aClosure);
1823 *((float*)cache->cacheLocation) =
1824 Preferences::GetFloat(aPref, cache->defaultValueFloat);
1827 // static
1828 nsresult
1829 Preferences::AddFloatVarCache(float* aCache,
1830 const char* aPref,
1831 float aDefault)
1833 NS_ASSERTION(aCache, "aCache must not be NULL");
1834 #ifdef DEBUG
1835 AssertNotAlreadyCached("float", aPref, aCache);
1836 #endif
1837 *aCache = Preferences::GetFloat(aPref, aDefault);
1838 CacheData* data = new CacheData();
1839 data->cacheLocation = aCache;
1840 data->defaultValueFloat = aDefault;
1841 gCacheData->AppendElement(data);
1842 return RegisterCallback(FloatVarChanged, aPref, data);
1845 // static
1846 nsresult
1847 Preferences::GetDefaultBool(const char* aPref, bool* aResult)
1849 NS_PRECONDITION(aResult, "aResult must not be NULL");
1850 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1851 return PREF_GetBoolPref(aPref, aResult, true);
1854 // static
1855 nsresult
1856 Preferences::GetDefaultInt(const char* aPref, int32_t* aResult)
1858 NS_PRECONDITION(aResult, "aResult must not be NULL");
1859 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1860 return PREF_GetIntPref(aPref, aResult, true);
1863 // static
1864 nsresult
1865 Preferences::GetDefaultCString(const char* aPref, nsACString* aResult)
1867 NS_PRECONDITION(aResult, "aResult must not be NULL");
1868 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1869 nsAutoCString result;
1870 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
1871 if (NS_SUCCEEDED(rv)) {
1872 *aResult = result;
1874 return rv;
1877 // static
1878 nsresult
1879 Preferences::GetDefaultString(const char* aPref, nsAString* aResult)
1881 NS_PRECONDITION(aResult, "aResult must not be NULL");
1882 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1883 nsAutoCString result;
1884 nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
1885 if (NS_SUCCEEDED(rv)) {
1886 CopyUTF8toUTF16(result, *aResult);
1888 return rv;
1891 // static
1892 nsresult
1893 Preferences::GetDefaultLocalizedCString(const char* aPref,
1894 nsACString* aResult)
1896 nsAutoString result;
1897 nsresult rv = GetDefaultLocalizedString(aPref, &result);
1898 if (NS_SUCCEEDED(rv)) {
1899 CopyUTF16toUTF8(result, *aResult);
1901 return rv;
1904 // static
1905 nsresult
1906 Preferences::GetDefaultLocalizedString(const char* aPref,
1907 nsAString* aResult)
1909 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1910 nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
1911 nsresult rv =
1912 sDefaultRootBranch->GetComplexValue(aPref,
1913 NS_GET_IID(nsIPrefLocalizedString),
1914 getter_AddRefs(prefLocalString));
1915 if (NS_SUCCEEDED(rv)) {
1916 NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
1917 prefLocalString->GetData(getter_Copies(*aResult));
1919 return rv;
1922 // static
1923 nsAdoptingString
1924 Preferences::GetDefaultString(const char* aPref)
1926 nsAdoptingString result;
1927 GetDefaultString(aPref, &result);
1928 return result;
1931 // static
1932 nsAdoptingCString
1933 Preferences::GetDefaultCString(const char* aPref)
1935 nsAdoptingCString result;
1936 PREF_CopyCharPref(aPref, getter_Copies(result), true);
1937 return result;
1940 // static
1941 nsAdoptingString
1942 Preferences::GetDefaultLocalizedString(const char* aPref)
1944 nsAdoptingString result;
1945 GetDefaultLocalizedString(aPref, &result);
1946 return result;
1949 // static
1950 nsAdoptingCString
1951 Preferences::GetDefaultLocalizedCString(const char* aPref)
1953 nsAdoptingCString result;
1954 GetDefaultLocalizedCString(aPref, &result);
1955 return result;
1958 // static
1959 nsresult
1960 Preferences::GetDefaultComplex(const char* aPref, const nsIID &aType,
1961 void** aResult)
1963 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1964 return sDefaultRootBranch->GetComplexValue(aPref, aType, aResult);
1967 // static
1968 int32_t
1969 Preferences::GetDefaultType(const char* aPref)
1971 NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID);
1972 int32_t result;
1973 return NS_SUCCEEDED(sDefaultRootBranch->GetPrefType(aPref, &result)) ?
1974 result : nsIPrefBranch::PREF_INVALID;
1977 } // namespace mozilla
1979 #undef ENSURE_MAIN_PROCESS