michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=8 sts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/dom/ContentChild.h" michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/HashFunctions.h" michael@0: michael@0: #include "nsXULAppAPI.h" michael@0: michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsAppDirectoryServiceDefs.h" michael@0: #include "nsDataHashtable.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsICategoryManager.h" michael@0: #include "nsCategoryManagerUtils.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIStringEnumerator.h" michael@0: #include "nsIZipReader.h" michael@0: #include "nsPrefBranch.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsCRT.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsXPCOMCID.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsPrintfCString.h" michael@0: michael@0: #include "nsQuickSort.h" michael@0: #include "pldhash.h" michael@0: michael@0: #include "prefapi.h" michael@0: #include "prefread.h" michael@0: #include "prefapi_private_data.h" michael@0: michael@0: #include "mozilla/Omnijar.h" michael@0: #include "nsZipArchive.h" michael@0: michael@0: #include "nsTArray.h" michael@0: #include "nsRefPtrHashtable.h" michael@0: #include "nsIMemoryReporter.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: #ifdef DEBUG michael@0: #define ENSURE_MAIN_PROCESS(message, pref) do { \ michael@0: if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) { \ michael@0: nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref); \ michael@0: NS_WARNING(msg.get()); \ michael@0: return NS_ERROR_NOT_AVAILABLE; \ michael@0: } \ michael@0: } while (0); michael@0: #else michael@0: #define ENSURE_MAIN_PROCESS(message, pref) \ michael@0: if (MOZ_UNLIKELY(XRE_GetProcessType() != GeckoProcessType_Default)) { \ michael@0: return NS_ERROR_NOT_AVAILABLE; \ michael@0: } michael@0: #endif michael@0: michael@0: class PrefCallback; michael@0: michael@0: namespace mozilla { michael@0: michael@0: // Definitions michael@0: #define INITIAL_PREF_FILES 10 michael@0: static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID); michael@0: michael@0: // Prototypes michael@0: static nsresult openPrefFile(nsIFile* aFile); michael@0: static nsresult pref_InitInitialObjects(void); michael@0: static nsresult pref_LoadPrefsInDirList(const char *listId); michael@0: static nsresult ReadExtensionPrefs(nsIFile *aFile); michael@0: michael@0: static const char kTelemetryPref[] = "toolkit.telemetry.enabled"; michael@0: static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease"; michael@0: static const char kChannelPref[] = "app.update.channel"; michael@0: michael@0: Preferences* Preferences::sPreferences = nullptr; michael@0: nsIPrefBranch* Preferences::sRootBranch = nullptr; michael@0: nsIPrefBranch* Preferences::sDefaultRootBranch = nullptr; michael@0: bool Preferences::sShutdown = false; michael@0: michael@0: class ValueObserverHashKey : public PLDHashEntryHdr { michael@0: public: michael@0: typedef ValueObserverHashKey* KeyType; michael@0: typedef const ValueObserverHashKey* KeyTypePointer; michael@0: michael@0: static const ValueObserverHashKey* KeyToPointer(ValueObserverHashKey *aKey) michael@0: { michael@0: return aKey; michael@0: } michael@0: michael@0: static PLDHashNumber HashKey(const ValueObserverHashKey *aKey) michael@0: { michael@0: PLDHashNumber hash = HashString(aKey->mPrefName); michael@0: return AddToHash(hash, aKey->mCallback); michael@0: } michael@0: michael@0: ValueObserverHashKey(const char *aPref, PrefChangedFunc aCallback) : michael@0: mPrefName(aPref), mCallback(aCallback) { } michael@0: michael@0: ValueObserverHashKey(const ValueObserverHashKey *aOther) : michael@0: mPrefName(aOther->mPrefName), mCallback(aOther->mCallback) michael@0: { } michael@0: michael@0: bool KeyEquals(const ValueObserverHashKey *aOther) const michael@0: { michael@0: return mCallback == aOther->mCallback && mPrefName == aOther->mPrefName; michael@0: } michael@0: michael@0: ValueObserverHashKey *GetKey() const michael@0: { michael@0: return const_cast(this); michael@0: } michael@0: michael@0: enum { ALLOW_MEMMOVE = true }; michael@0: michael@0: nsCString mPrefName; michael@0: PrefChangedFunc mCallback; michael@0: }; michael@0: michael@0: class ValueObserver MOZ_FINAL : public nsIObserver, michael@0: public ValueObserverHashKey michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: ValueObserver(const char *aPref, PrefChangedFunc aCallback) michael@0: : ValueObserverHashKey(aPref, aCallback) { } michael@0: michael@0: ~ValueObserver() { michael@0: Preferences::RemoveObserver(this, mPrefName.get()); michael@0: } michael@0: michael@0: void AppendClosure(void *aClosure) { michael@0: mClosures.AppendElement(aClosure); michael@0: } michael@0: michael@0: void RemoveClosure(void *aClosure) { michael@0: mClosures.RemoveElement(aClosure); michael@0: } michael@0: michael@0: bool HasNoClosures() { michael@0: return mClosures.Length() == 0; michael@0: } michael@0: michael@0: nsTArray mClosures; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(ValueObserver, nsIObserver) michael@0: michael@0: NS_IMETHODIMP michael@0: ValueObserver::Observe(nsISupports *aSubject, michael@0: const char *aTopic, michael@0: const char16_t *aData) michael@0: { michael@0: NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), michael@0: "invalid topic"); michael@0: NS_ConvertUTF16toUTF8 data(aData); michael@0: for (uint32_t i = 0; i < mClosures.Length(); i++) { michael@0: mCallback(data.get(), mClosures.ElementAt(i)); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: struct CacheData { michael@0: void* cacheLocation; michael@0: union { michael@0: bool defaultValueBool; michael@0: int32_t defaultValueInt; michael@0: uint32_t defaultValueUint; michael@0: float defaultValueFloat; michael@0: }; michael@0: }; michael@0: michael@0: static nsTArray >* gCacheData = nullptr; michael@0: static nsRefPtrHashtable* gObserverTable = nullptr; michael@0: michael@0: static size_t michael@0: SizeOfObserverEntryExcludingThis(ValueObserverHashKey* aKey, michael@0: const nsRefPtr& aData, michael@0: mozilla::MallocSizeOf aMallocSizeOf, michael@0: void*) michael@0: { michael@0: size_t n = 0; michael@0: n += aKey->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf); michael@0: n += aData->mClosures.SizeOfExcludingThis(aMallocSizeOf); michael@0: return n; michael@0: } michael@0: michael@0: // Although this is a member of Preferences, it measures sPreferences and michael@0: // several other global structures. michael@0: /* static */ int64_t michael@0: Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), 0); michael@0: michael@0: size_t n = aMallocSizeOf(sPreferences); michael@0: if (gHashTable.ops) { michael@0: // pref keys are allocated in a private arena, which we count elsewhere. michael@0: // pref stringvals are allocated out of the same private arena. michael@0: n += PL_DHashTableSizeOfExcludingThis(&gHashTable, nullptr, aMallocSizeOf); michael@0: } michael@0: if (gCacheData) { michael@0: n += gCacheData->SizeOfIncludingThis(aMallocSizeOf); michael@0: for (uint32_t i = 0, count = gCacheData->Length(); i < count; ++i) { michael@0: n += aMallocSizeOf((*gCacheData)[i]); michael@0: } michael@0: } michael@0: if (gObserverTable) { michael@0: n += aMallocSizeOf(gObserverTable); michael@0: n += gObserverTable->SizeOfExcludingThis(SizeOfObserverEntryExcludingThis, michael@0: aMallocSizeOf); michael@0: } michael@0: // We don't measure sRootBranch and sDefaultRootBranch here because michael@0: // DMD indicates they are not significant. michael@0: n += pref_SizeOfPrivateData(aMallocSizeOf); michael@0: return n; michael@0: } michael@0: michael@0: class PreferenceServiceReporter MOZ_FINAL : public nsIMemoryReporter michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIMEMORYREPORTER michael@0: michael@0: protected: michael@0: static const uint32_t kSuspectReferentCount = 1000; michael@0: static PLDHashOperator CountReferents(PrefCallback* aKey, michael@0: nsAutoPtr& aCallback, michael@0: void* aClosure); michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter) michael@0: michael@0: struct PreferencesReferentCount { michael@0: PreferencesReferentCount() : numStrong(0), numWeakAlive(0), numWeakDead(0) {} michael@0: size_t numStrong; michael@0: size_t numWeakAlive; michael@0: size_t numWeakDead; michael@0: nsTArray suspectPreferences; michael@0: // Count of the number of referents for each preference. michael@0: nsDataHashtable prefCounter; michael@0: }; michael@0: michael@0: PLDHashOperator michael@0: PreferenceServiceReporter::CountReferents(PrefCallback* aKey, michael@0: nsAutoPtr& aCallback, michael@0: void* aClosure) michael@0: { michael@0: PreferencesReferentCount* referentCount = michael@0: static_cast(aClosure); michael@0: michael@0: nsPrefBranch* prefBranch = aCallback->GetPrefBranch(); michael@0: const char* pref = prefBranch->getPrefName(aCallback->GetDomain().get()); michael@0: michael@0: if (aCallback->IsWeak()) { michael@0: nsCOMPtr callbackRef = do_QueryReferent(aCallback->mWeakRef); michael@0: if (callbackRef) { michael@0: referentCount->numWeakAlive++; michael@0: } else { michael@0: referentCount->numWeakDead++; michael@0: } michael@0: } else { michael@0: referentCount->numStrong++; michael@0: } michael@0: michael@0: nsDependentCString prefString(pref); michael@0: uint32_t oldCount = 0; michael@0: referentCount->prefCounter.Get(prefString, &oldCount); michael@0: uint32_t currentCount = oldCount + 1; michael@0: referentCount->prefCounter.Put(prefString, currentCount); michael@0: michael@0: // Keep track of preferences that have a suspiciously large michael@0: // number of referents (symptom of leak). michael@0: if (currentCount == kSuspectReferentCount) { michael@0: referentCount->suspectPreferences.AppendElement(prefString); michael@0: } michael@0: michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf) michael@0: michael@0: NS_IMETHODIMP michael@0: PreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback* aCb, michael@0: nsISupports* aClosure) michael@0: { michael@0: #define REPORT(_path, _kind, _units, _amount, _desc) \ michael@0: do { \ michael@0: nsresult rv; \ michael@0: rv = aCb->Callback(EmptyCString(), _path, _kind, \ michael@0: _units, _amount, NS_LITERAL_CSTRING(_desc), \ michael@0: aClosure); \ michael@0: NS_ENSURE_SUCCESS(rv, rv); \ michael@0: } while (0) michael@0: michael@0: REPORT(NS_LITERAL_CSTRING("explicit/preferences"), michael@0: KIND_HEAP, UNITS_BYTES, michael@0: Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf), michael@0: "Memory used by the preferences system."); michael@0: michael@0: nsPrefBranch* rootBranch = michael@0: static_cast(Preferences::GetRootBranch()); michael@0: if (!rootBranch) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: PreferencesReferentCount referentCount; michael@0: rootBranch->mObservers.Enumerate(&CountReferents, &referentCount); michael@0: michael@0: for (uint32_t i = 0; i < referentCount.suspectPreferences.Length(); i++) { michael@0: nsCString& suspect = referentCount.suspectPreferences[i]; michael@0: uint32_t totalReferentCount = 0; michael@0: referentCount.prefCounter.Get(suspect, &totalReferentCount); michael@0: michael@0: nsPrintfCString suspectPath("preference-service-suspect/" michael@0: "referent(pref=%s)", suspect.get()); michael@0: michael@0: REPORT(suspectPath, michael@0: KIND_OTHER, UNITS_COUNT, totalReferentCount, michael@0: "A preference with a suspiciously large number " michael@0: "referents (symptom of a leak)."); michael@0: } michael@0: michael@0: REPORT(NS_LITERAL_CSTRING("preference-service/referent/strong"), michael@0: KIND_OTHER, UNITS_COUNT, referentCount.numStrong, michael@0: "The number of strong referents held by the preference service."); michael@0: michael@0: REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/alive"), michael@0: KIND_OTHER, UNITS_COUNT, referentCount.numWeakAlive, michael@0: "The number of weak referents held by the preference service " michael@0: "that are still alive."); michael@0: michael@0: REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/dead"), michael@0: KIND_OTHER, UNITS_COUNT, referentCount.numWeakDead, michael@0: "The number of weak referents held by the preference service " michael@0: "that are dead."); michael@0: michael@0: #undef REPORT michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: namespace { michael@0: class AddPreferencesMemoryReporterRunnable : public nsRunnable michael@0: { michael@0: NS_IMETHOD Run() michael@0: { michael@0: return RegisterStrongMemoryReporter(new PreferenceServiceReporter()); michael@0: } michael@0: }; michael@0: } // anonymous namespace michael@0: michael@0: // static michael@0: Preferences* michael@0: Preferences::GetInstanceForService() michael@0: { michael@0: if (sPreferences) { michael@0: NS_ADDREF(sPreferences); michael@0: return sPreferences; michael@0: } michael@0: michael@0: NS_ENSURE_TRUE(!sShutdown, nullptr); michael@0: michael@0: sRootBranch = new nsPrefBranch("", false); michael@0: NS_ADDREF(sRootBranch); michael@0: sDefaultRootBranch = new nsPrefBranch("", true); michael@0: NS_ADDREF(sDefaultRootBranch); michael@0: michael@0: sPreferences = new Preferences(); michael@0: NS_ADDREF(sPreferences); michael@0: michael@0: if (NS_FAILED(sPreferences->Init())) { michael@0: // The singleton instance will delete sRootBranch and sDefaultRootBranch. michael@0: NS_RELEASE(sPreferences); michael@0: return nullptr; michael@0: } michael@0: michael@0: gCacheData = new nsTArray >(); michael@0: michael@0: gObserverTable = new nsRefPtrHashtable(); michael@0: michael@0: // Preferences::GetInstanceForService() can be called from GetService(), and michael@0: // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To michael@0: // avoid a potential recursive GetService() call, we can't register the michael@0: // memory reporter here; instead, do it off a runnable. michael@0: nsRefPtr runnable = michael@0: new AddPreferencesMemoryReporterRunnable(); michael@0: NS_DispatchToMainThread(runnable); michael@0: michael@0: NS_ADDREF(sPreferences); michael@0: return sPreferences; michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: Preferences::InitStaticMembers() michael@0: { michael@0: #ifndef MOZ_B2G michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: #endif michael@0: michael@0: if (!sShutdown && !sPreferences) { michael@0: nsCOMPtr prefService = michael@0: do_GetService(NS_PREFSERVICE_CONTRACTID); michael@0: } michael@0: michael@0: return sPreferences != nullptr; michael@0: } michael@0: michael@0: // static michael@0: void michael@0: Preferences::Shutdown() michael@0: { michael@0: if (!sShutdown) { michael@0: sShutdown = true; // Don't create the singleton instance after here. michael@0: michael@0: // Don't set sPreferences to nullptr here. The instance may be grabbed by michael@0: // other modules. The utility methods of Preferences should be available michael@0: // until the singleton instance actually released. michael@0: if (sPreferences) { michael@0: sPreferences->Release(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: /* michael@0: * Constructor/Destructor michael@0: */ michael@0: michael@0: Preferences::Preferences() michael@0: { michael@0: } michael@0: michael@0: Preferences::~Preferences() michael@0: { michael@0: NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?"); michael@0: michael@0: delete gObserverTable; michael@0: gObserverTable = nullptr; michael@0: michael@0: delete gCacheData; michael@0: gCacheData = nullptr; michael@0: michael@0: NS_RELEASE(sRootBranch); michael@0: NS_RELEASE(sDefaultRootBranch); michael@0: michael@0: sPreferences = nullptr; michael@0: michael@0: PREF_Cleanup(); michael@0: } michael@0: michael@0: michael@0: /* michael@0: * nsISupports Implementation michael@0: */ michael@0: michael@0: NS_IMPL_ADDREF(Preferences) michael@0: NS_IMPL_RELEASE(Preferences) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN(Preferences) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService) michael@0: NS_INTERFACE_MAP_ENTRY(nsIPrefService) michael@0: NS_INTERFACE_MAP_ENTRY(nsIObserver) michael@0: NS_INTERFACE_MAP_ENTRY(nsIPrefBranch) michael@0: NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2) michael@0: NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal) michael@0: NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: michael@0: /* michael@0: * nsIPrefService Implementation michael@0: */ michael@0: michael@0: nsresult michael@0: Preferences::Init() michael@0: { michael@0: nsresult rv; michael@0: michael@0: rv = PREF_Init(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = pref_InitInitialObjects(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: using mozilla::dom::ContentChild; michael@0: if (XRE_GetProcessType() == GeckoProcessType_Content) { michael@0: InfallibleTArray prefs; michael@0: ContentChild::GetSingleton()->SendReadPrefsArray(&prefs); michael@0: michael@0: // Store the array michael@0: for (uint32_t i = 0; i < prefs.Length(); ++i) { michael@0: pref_SetPref(prefs[i]); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsXPIDLCString lockFileName; michael@0: /* michael@0: * The following is a small hack which will allow us to only load the library michael@0: * which supports the netscape.cfg file if the preference is defined. We michael@0: * test for the existence of the pref, set in the all.js (mozilla) or michael@0: * all-ns.js (netscape 6), and if it exists we startup the pref config michael@0: * category which will do the rest. michael@0: */ michael@0: michael@0: rv = PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName), false); michael@0: if (NS_SUCCEEDED(rv)) michael@0: NS_CreateServicesFromCategory("pref-config-startup", michael@0: static_cast(static_cast(this)), michael@0: "pref-config-startup"); michael@0: michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (!observerService) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: rv = observerService->AddObserver(this, "profile-before-change", true); michael@0: michael@0: observerService->AddObserver(this, "load-extension-defaults", true); michael@0: observerService->AddObserver(this, "suspend_process_notification", true); michael@0: michael@0: return(rv); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::ResetAndReadUserPrefs() michael@0: { michael@0: sPreferences->ResetUserPrefs(); michael@0: return sPreferences->ReadUserPrefs(nullptr); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Preferences::Observe(nsISupports *aSubject, const char *aTopic, michael@0: const char16_t *someData) michael@0: { michael@0: if (XRE_GetProcessType() == GeckoProcessType_Content) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: if (!nsCRT::strcmp(aTopic, "profile-before-change")) { michael@0: if (!nsCRT::strcmp(someData, MOZ_UTF16("shutdown-cleanse"))) { michael@0: if (mCurrentFile) { michael@0: mCurrentFile->Remove(false); michael@0: mCurrentFile = nullptr; michael@0: } michael@0: } else { michael@0: rv = SavePrefFile(nullptr); michael@0: } michael@0: } else if (!strcmp(aTopic, "load-extension-defaults")) { michael@0: pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST); michael@0: } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) { michael@0: // Reload the default prefs from file. michael@0: pref_InitInitialObjects(); michael@0: } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) { michael@0: // Our process is being suspended. The OS may wake our process later, michael@0: // or it may kill the process. In case our process is going to be killed michael@0: // from the suspended state, we save preferences before suspending. michael@0: rv = SavePrefFile(nullptr); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: Preferences::ReadUserPrefs(nsIFile *aFile) michael@0: { michael@0: if (XRE_GetProcessType() == GeckoProcessType_Content) { michael@0: NS_ERROR("cannot load prefs from content process"); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: if (nullptr == aFile) { michael@0: rv = UseDefaultPrefFile(); michael@0: // A user pref file is optional. michael@0: // Ignore all errors related to it, so we retain 'rv' value :-| michael@0: (void) UseUserPrefFile(); michael@0: michael@0: // Migrate the old prerelease telemetry pref michael@0: if (!Preferences::GetBool(kOldTelemetryPref, true)) { michael@0: Preferences::SetBool(kTelemetryPref, false); michael@0: Preferences::ClearUser(kOldTelemetryPref); michael@0: } michael@0: michael@0: NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID); michael@0: } else { michael@0: rv = ReadAndOwnUserPrefFile(aFile); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Preferences::ResetPrefs() michael@0: { michael@0: if (XRE_GetProcessType() == GeckoProcessType_Content) { michael@0: NS_ERROR("cannot reset prefs from content process"); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID); michael@0: PREF_CleanupPrefs(); michael@0: michael@0: nsresult rv = PREF_Init(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return pref_InitInitialObjects(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Preferences::ResetUserPrefs() michael@0: { michael@0: if (XRE_GetProcessType() == GeckoProcessType_Content) { michael@0: NS_ERROR("cannot reset user prefs from content process"); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: PREF_ClearAllUserPrefs(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Preferences::SavePrefFile(nsIFile *aFile) michael@0: { michael@0: if (XRE_GetProcessType() == GeckoProcessType_Content) { michael@0: NS_ERROR("cannot save pref file from content process"); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: return SavePrefFileInternal(aFile); michael@0: } michael@0: michael@0: static nsresult michael@0: ReadExtensionPrefs(nsIFile *aFile) michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr reader = do_CreateInstance(kZipReaderCID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = reader->Open(aFile); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr files; michael@0: rv = reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"), michael@0: getter_AddRefs(files)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: char buffer[4096]; michael@0: michael@0: bool more; michael@0: while (NS_SUCCEEDED(rv = files->HasMore(&more)) && more) { michael@0: nsAutoCString entry; michael@0: rv = files->GetNext(entry); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr stream; michael@0: rv = reader->GetInputStream(entry, getter_AddRefs(stream)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: uint64_t avail; michael@0: uint32_t read; michael@0: michael@0: PrefParseState ps; michael@0: PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr); michael@0: while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) { michael@0: rv = stream->Read(buffer, 4096, &read); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Pref stream read failed"); michael@0: break; michael@0: } michael@0: michael@0: PREF_ParseBuf(&ps, buffer, read); michael@0: } michael@0: PREF_FinalizeParseState(&ps); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: void michael@0: Preferences::SetPreference(const PrefSetting& aPref) michael@0: { michael@0: pref_SetPref(aPref); michael@0: } michael@0: michael@0: void michael@0: Preferences::GetPreference(PrefSetting* aPref) michael@0: { michael@0: PrefHashEntry *entry = pref_HashTableLookup(aPref->name().get()); michael@0: if (!entry) michael@0: return; michael@0: michael@0: pref_GetPrefFromEntry(entry, aPref); michael@0: } michael@0: michael@0: void michael@0: Preferences::GetPreferences(InfallibleTArray* aPrefs) michael@0: { michael@0: aPrefs->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable)); michael@0: PL_DHashTableEnumerate(&gHashTable, pref_GetPrefs, aPrefs); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval) michael@0: { michael@0: nsresult rv; michael@0: michael@0: if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) { michael@0: // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think) michael@0: nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, false); michael@0: if (!prefBranch) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: rv = CallQueryInterface(prefBranch, _retval); michael@0: } else { michael@0: // special case caching the default root michael@0: nsCOMPtr root(sRootBranch); michael@0: root.forget(_retval); michael@0: rv = NS_OK; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: Preferences::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval) michael@0: { michael@0: if (!aPrefRoot || !aPrefRoot[0]) { michael@0: nsCOMPtr root(sDefaultRootBranch); michael@0: root.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think) michael@0: nsRefPtr prefBranch = new nsPrefBranch(aPrefRoot, true); michael@0: if (!prefBranch) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: prefBranch.forget(_retval); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: Preferences::NotifyServiceObservers(const char *aTopic) michael@0: { michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (!observerService) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsISupports *subject = (nsISupports *)((nsIPrefService *)this); michael@0: observerService->NotifyObservers(subject, aTopic, nullptr); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: Preferences::UseDefaultPrefFile() michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr aFile; michael@0: michael@0: #if defined(XP_WIN) && defined(MOZ_METRO) michael@0: if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { michael@0: rv = NS_GetSpecialDirectory(NS_METRO_APP_PREFS_50_FILE, getter_AddRefs(aFile)); michael@0: } else michael@0: #endif michael@0: { michael@0: rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile)); michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = ReadAndOwnUserPrefFile(aFile); michael@0: // Most likely cause of failure here is that the file didn't michael@0: // exist, so save a new one. mUserPrefReadFailed will be michael@0: // used to catch an error in actually reading the file. michael@0: if (NS_FAILED(rv)) { michael@0: if (NS_FAILED(SavePrefFileInternal(aFile))) michael@0: NS_ERROR("Failed to save new shared pref file"); michael@0: else michael@0: rv = NS_OK; michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: Preferences::UseUserPrefFile() michael@0: { michael@0: nsresult rv = NS_OK; michael@0: nsCOMPtr aFile; michael@0: nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR); michael@0: michael@0: rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile)); michael@0: if (NS_SUCCEEDED(rv) && aFile) { michael@0: rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js")); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: bool exists = false; michael@0: aFile->Exists(&exists); michael@0: if (exists) { michael@0: rv = openPrefFile(aFile); michael@0: } else { michael@0: rv = NS_ERROR_FILE_NOT_FOUND; michael@0: } michael@0: } michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: Preferences::MakeBackupPrefFile(nsIFile *aFile) michael@0: { michael@0: // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory. michael@0: // "Invalidprefs.js" is removed if it exists, prior to making the copy. michael@0: nsAutoString newFilename; michael@0: nsresult rv = aFile->GetLeafName(newFilename); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0); michael@0: nsCOMPtr newFile; michael@0: rv = aFile->GetParent(getter_AddRefs(newFile)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = newFile->Append(newFilename); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: bool exists = false; michael@0: newFile->Exists(&exists); michael@0: if (exists) { michael@0: rv = newFile->Remove(false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: rv = aFile->CopyTo(nullptr, newFilename); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: Preferences::ReadAndOwnUserPrefFile(nsIFile *aFile) michael@0: { michael@0: NS_ENSURE_ARG(aFile); michael@0: michael@0: if (mCurrentFile == aFile) michael@0: return NS_OK; michael@0: mCurrentFile = aFile; michael@0: michael@0: nsresult rv = NS_OK; michael@0: bool exists = false; michael@0: mCurrentFile->Exists(&exists); michael@0: if (exists) { michael@0: rv = openPrefFile(mCurrentFile); michael@0: if (NS_FAILED(rv)) { michael@0: // Save a backup copy of the current (invalid) prefs file, since all prefs michael@0: // from the error line to the end of the file will be lost (bug 361102). michael@0: // TODO we should notify the user about it (bug 523725). michael@0: MakeBackupPrefFile(mCurrentFile); michael@0: } michael@0: } else { michael@0: rv = NS_ERROR_FILE_NOT_FOUND; michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: Preferences::SavePrefFileInternal(nsIFile *aFile) michael@0: { michael@0: if (nullptr == aFile) { michael@0: // the gDirty flag tells us if we should write to mCurrentFile michael@0: // we only check this flag when the caller wants to write to the default michael@0: if (!gDirty) michael@0: return NS_OK; michael@0: michael@0: // It's possible that we never got a prefs file. michael@0: nsresult rv = NS_OK; michael@0: if (mCurrentFile) michael@0: rv = WritePrefFile(mCurrentFile); michael@0: michael@0: return rv; michael@0: } else { michael@0: return WritePrefFile(aFile); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: Preferences::WritePrefFile(nsIFile* aFile) michael@0: { michael@0: const char outHeader[] = michael@0: "# Mozilla User Preferences" michael@0: NS_LINEBREAK michael@0: NS_LINEBREAK michael@0: "/* Do not edit this file." michael@0: NS_LINEBREAK michael@0: " *" michael@0: NS_LINEBREAK michael@0: " * If you make changes to this file while the application is running," michael@0: NS_LINEBREAK michael@0: " * the changes will be overwritten when the application exits." michael@0: NS_LINEBREAK michael@0: " *" michael@0: NS_LINEBREAK michael@0: " * To make a manual change to preferences, you can visit the URL about:config" michael@0: NS_LINEBREAK michael@0: " */" michael@0: NS_LINEBREAK michael@0: NS_LINEBREAK; michael@0: michael@0: nsCOMPtr outStreamSink; michael@0: nsCOMPtr outStream; michael@0: uint32_t writeAmount; michael@0: nsresult rv; michael@0: michael@0: if (!gHashTable.ops) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: // execute a "safe" save by saving through a tempfile michael@0: rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink), michael@0: aFile, michael@0: -1, michael@0: 0600); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsAutoArrayPtr valueArray(new char*[gHashTable.entryCount]); michael@0: memset(valueArray, 0, gHashTable.entryCount * sizeof(char*)); michael@0: pref_saveArgs saveArgs; michael@0: saveArgs.prefArray = valueArray; michael@0: saveArgs.saveTypes = SAVE_ALL; michael@0: michael@0: // get the lines that we're supposed to be writing to the file michael@0: PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs); michael@0: michael@0: /* Sort the preferences to make a readable file on disk */ michael@0: NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char *), pref_CompareStrings, nullptr); michael@0: michael@0: // write out the file header michael@0: outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount); michael@0: michael@0: char** walker = valueArray; michael@0: for (uint32_t valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) { michael@0: if (*walker) { michael@0: outStream->Write(*walker, strlen(*walker), &writeAmount); michael@0: outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount); michael@0: NS_Free(*walker); michael@0: } michael@0: } michael@0: michael@0: // tell the safe output stream to overwrite the real prefs file michael@0: // (it'll abort if there were any errors during writing) michael@0: nsCOMPtr safeStream = do_QueryInterface(outStream); michael@0: NS_ASSERTION(safeStream, "expected a safe output stream!"); michael@0: if (safeStream) { michael@0: rv = safeStream->Finish(); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("failed to save prefs file! possible data loss"); michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: gDirty = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult openPrefFile(nsIFile* aFile) michael@0: { michael@0: nsCOMPtr inStr; michael@0: michael@0: nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: uint64_t fileSize64; michael@0: rv = inStr->Available(&fileSize64); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG); michael@0: michael@0: uint32_t fileSize = (uint32_t)fileSize64; michael@0: nsAutoArrayPtr fileBuffer(new char[fileSize]); michael@0: if (fileBuffer == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: PrefParseState ps; michael@0: PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr); michael@0: michael@0: // Read is not guaranteed to return a buf the size of fileSize, michael@0: // but usually will. michael@0: nsresult rv2 = NS_OK; michael@0: for (;;) { michael@0: uint32_t amtRead = 0; michael@0: rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead); michael@0: if (NS_FAILED(rv) || amtRead == 0) michael@0: break; michael@0: if (!PREF_ParseBuf(&ps, fileBuffer, amtRead)) michael@0: rv2 = NS_ERROR_FILE_CORRUPTED; michael@0: } michael@0: michael@0: PREF_FinalizeParseState(&ps); michael@0: michael@0: return NS_FAILED(rv) ? rv : rv2; michael@0: } michael@0: michael@0: /* michael@0: * some stuff that gets called from Pref_Init() michael@0: */ michael@0: michael@0: static int michael@0: pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/) michael@0: { michael@0: nsAutoCString filename1, filename2; michael@0: aFile1->GetNativeLeafName(filename1); michael@0: aFile2->GetNativeLeafName(filename2); michael@0: michael@0: return Compare(filename2, filename1); michael@0: } michael@0: michael@0: /** michael@0: * Load default pref files from a directory. The files in the michael@0: * directory are sorted reverse-alphabetically; a set of "special file michael@0: * names" may be specified which are loaded after all the others. michael@0: */ michael@0: static nsresult michael@0: pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, uint32_t aSpecialFilesCount) michael@0: { michael@0: nsresult rv, rv2; michael@0: bool hasMoreElements; michael@0: michael@0: nsCOMPtr dirIterator; michael@0: michael@0: // this may fail in some normal cases, such as embedders who do not use a GRE michael@0: rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator)); michael@0: if (NS_FAILED(rv)) { michael@0: // If the directory doesn't exist, then we have no reason to complain. We michael@0: // loaded everything (and nothing) successfully. michael@0: if (rv == NS_ERROR_FILE_NOT_FOUND || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) michael@0: rv = NS_OK; michael@0: return rv; michael@0: } michael@0: michael@0: rv = dirIterator->HasMoreElements(&hasMoreElements); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMArray prefFiles(INITIAL_PREF_FILES); michael@0: nsCOMArray specialFiles(aSpecialFilesCount); michael@0: nsCOMPtr prefFile; michael@0: michael@0: while (hasMoreElements && NS_SUCCEEDED(rv)) { michael@0: nsAutoCString leafName; michael@0: michael@0: nsCOMPtr supports; michael@0: rv = dirIterator->GetNext(getter_AddRefs(supports)); michael@0: prefFile = do_QueryInterface(supports); michael@0: if (NS_FAILED(rv)) { michael@0: break; michael@0: } michael@0: michael@0: prefFile->GetNativeLeafName(leafName); michael@0: NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?"); michael@0: michael@0: // Skip non-js files michael@0: if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"), michael@0: nsCaseInsensitiveCStringComparator())) { michael@0: bool shouldParse = true; michael@0: // separate out special files michael@0: for (uint32_t i = 0; i < aSpecialFilesCount; ++i) { michael@0: if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) { michael@0: shouldParse = false; michael@0: // special files should be process in order; we put them into michael@0: // the array by index; this can make the array sparse michael@0: specialFiles.ReplaceObjectAt(prefFile, i); michael@0: } michael@0: } michael@0: michael@0: if (shouldParse) { michael@0: prefFiles.AppendObject(prefFile); michael@0: } michael@0: } michael@0: michael@0: rv = dirIterator->HasMoreElements(&hasMoreElements); michael@0: } michael@0: michael@0: if (prefFiles.Count() + specialFiles.Count() == 0) { michael@0: NS_WARNING("No default pref files found."); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: prefFiles.Sort(pref_CompareFileNames, nullptr); michael@0: michael@0: uint32_t arrayCount = prefFiles.Count(); michael@0: uint32_t i; michael@0: for (i = 0; i < arrayCount; ++i) { michael@0: rv2 = openPrefFile(prefFiles[i]); michael@0: if (NS_FAILED(rv2)) { michael@0: NS_ERROR("Default pref file not parsed successfully."); michael@0: rv = rv2; michael@0: } michael@0: } michael@0: michael@0: arrayCount = specialFiles.Count(); michael@0: for (i = 0; i < arrayCount; ++i) { michael@0: // this may be a sparse array; test before parsing michael@0: nsIFile* file = specialFiles[i]; michael@0: if (file) { michael@0: rv2 = openPrefFile(file); michael@0: if (NS_FAILED(rv2)) { michael@0: NS_ERROR("Special default pref file not parsed successfully."); michael@0: rv = rv2; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult pref_LoadPrefsInDirList(const char *listId) michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsCOMPtr list; michael@0: dirSvc->Get(listId, michael@0: NS_GET_IID(nsISimpleEnumerator), michael@0: getter_AddRefs(list)); michael@0: if (!list) michael@0: return NS_OK; michael@0: michael@0: bool hasMore; michael@0: while (NS_SUCCEEDED(list->HasMoreElements(&hasMore)) && hasMore) { michael@0: nsCOMPtr elem; michael@0: list->GetNext(getter_AddRefs(elem)); michael@0: if (!elem) michael@0: continue; michael@0: michael@0: nsCOMPtr path = do_QueryInterface(elem); michael@0: if (!path) michael@0: continue; michael@0: michael@0: nsAutoCString leaf; michael@0: path->GetNativeLeafName(leaf); michael@0: michael@0: // Do we care if a file provided by this process fails to load? michael@0: if (Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi"))) michael@0: ReadExtensionPrefs(path); michael@0: else michael@0: pref_LoadPrefsInDir(path, nullptr, 0); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name) michael@0: { michael@0: nsZipItemPtr manifest(jarReader, name, true); michael@0: NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: PrefParseState ps; michael@0: PREF_InitParseState(&ps, PREF_ReaderCallback, nullptr); michael@0: PREF_ParseBuf(&ps, manifest, manifest.Length()); michael@0: PREF_FinalizeParseState(&ps); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------------------------- michael@0: // Initialize default preference JavaScript buffers from michael@0: // appropriate TEXT resources michael@0: //---------------------------------------------------------------------------------------- michael@0: static nsresult pref_InitInitialObjects() michael@0: { michael@0: nsresult rv; michael@0: michael@0: // In omni.jar case, we load the following prefs: michael@0: // - jar:$gre/omni.jar!/greprefs.js michael@0: // - jar:$gre/omni.jar!/defaults/pref/*.js michael@0: // In non omni.jar case, we load: michael@0: // - $gre/greprefs.js michael@0: // michael@0: // In both cases, we also load: michael@0: // - $gre/defaults/pref/*.js michael@0: // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar) michael@0: // on $app == $gre case ; we load all files instead of channel-prefs.js only michael@0: // to have the same behaviour as $app != $gre, where this is required as michael@0: // a supported location for GRE preferences. michael@0: // michael@0: // When $app != $gre, we additionally load, in omni.jar case: michael@0: // - jar:$app/omni.jar!/defaults/preferences/*.js michael@0: // - $app/defaults/preferences/*.js michael@0: // and in non omni.jar case: michael@0: // - $app/defaults/preferences/*.js michael@0: // When $app == $gre, we additionally load, in omni.jar case: michael@0: // - jar:$gre/omni.jar!/defaults/preferences/*.js michael@0: // Thus, in omni.jar case, we always load app-specific default preferences michael@0: // from omni.jar, whether or not $app == $gre. michael@0: michael@0: nsZipFind *findPtr; michael@0: nsAutoPtr find; michael@0: nsTArray prefEntries; michael@0: const char *entryName; michael@0: uint16_t entryNameLen; michael@0: michael@0: nsRefPtr jarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE); michael@0: if (jarReader) { michael@0: // Load jar:$gre/omni.jar!/greprefs.js michael@0: rv = pref_ReadPrefFromJar(jarReader, "greprefs.js"); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Load jar:$gre/omni.jar!/defaults/pref/*.js michael@0: rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: find = findPtr; michael@0: while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) { michael@0: prefEntries.AppendElement(Substring(entryName, entryNameLen)); michael@0: } michael@0: michael@0: prefEntries.Sort(); michael@0: for (uint32_t i = prefEntries.Length(); i--; ) { michael@0: rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get()); michael@0: if (NS_FAILED(rv)) michael@0: NS_WARNING("Error parsing preferences."); michael@0: } michael@0: } else { michael@0: // Load $gre/greprefs.js michael@0: nsCOMPtr greprefsFile; michael@0: rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greprefsFile)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js")); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = openPrefFile(greprefsFile); michael@0: if (NS_FAILED(rv)) michael@0: NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?"); michael@0: } michael@0: michael@0: // Load $gre/defaults/pref/*.js michael@0: nsCOMPtr defaultPrefDir; michael@0: michael@0: rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */ michael@0: static const char* specialFiles[] = { michael@0: #if defined(XP_MACOSX) michael@0: "macprefs.js" michael@0: #elif defined(XP_WIN) michael@0: "winpref.js" michael@0: #elif defined(XP_UNIX) michael@0: "unix.js" michael@0: #if defined(VMS) michael@0: , "openvms.js" michael@0: #elif defined(_AIX) michael@0: , "aix.js" michael@0: #endif michael@0: #elif defined(XP_BEOS) michael@0: "beos.js" michael@0: #endif michael@0: }; michael@0: michael@0: rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles)); michael@0: if (NS_FAILED(rv)) michael@0: NS_WARNING("Error parsing application default preferences."); michael@0: michael@0: // Load jar:$app/omni.jar!/defaults/preferences/*.js michael@0: // or jar:$gre/omni.jar!/defaults/preferences/*.js. michael@0: nsRefPtr appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP); michael@0: // GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which michael@0: // case we look for app-specific default preferences in $gre. michael@0: if (!appJarReader) michael@0: appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE); michael@0: if (appJarReader) { michael@0: rv = appJarReader->FindInit("defaults/preferences/*.js$", &findPtr); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: find = findPtr; michael@0: prefEntries.Clear(); michael@0: while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) { michael@0: prefEntries.AppendElement(Substring(entryName, entryNameLen)); michael@0: } michael@0: prefEntries.Sort(); michael@0: for (uint32_t i = prefEntries.Length(); i--; ) { michael@0: rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get()); michael@0: if (NS_FAILED(rv)) michael@0: NS_WARNING("Error parsing preferences."); michael@0: } michael@0: } michael@0: michael@0: rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Set up the correct default for toolkit.telemetry.enabled. michael@0: // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta michael@0: // channel, telemetry is on by default, otherwise not. This is necessary michael@0: // so that beta users who are testing final release builds don't flipflop michael@0: // defaults. michael@0: if (Preferences::GetDefaultType(kTelemetryPref) == PREF_INVALID) { michael@0: bool prerelease = false; michael@0: #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT michael@0: prerelease = true; michael@0: #else michael@0: if (Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")) { michael@0: prerelease = true; michael@0: } michael@0: #endif michael@0: PREF_SetBoolPref(kTelemetryPref, prerelease, true); michael@0: } michael@0: michael@0: NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, michael@0: nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID); michael@0: michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (!observerService) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr); michael@0: michael@0: return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST); michael@0: } michael@0: michael@0: michael@0: /****************************************************************************** michael@0: * michael@0: * static utilities michael@0: * michael@0: ******************************************************************************/ michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetBool(const char* aPref, bool* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_GetBoolPref(aPref, aResult, false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetInt(const char* aPref, int32_t* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_GetIntPref(aPref, aResult, false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetFloat(const char* aPref, float* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: nsAutoCString result; michael@0: nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: *aResult = result.ToFloat(&rv); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsAdoptingCString michael@0: Preferences::GetCString(const char* aPref) michael@0: { michael@0: nsAdoptingCString result; michael@0: PREF_CopyCharPref(aPref, getter_Copies(result), false); michael@0: return result; michael@0: } michael@0: michael@0: // static michael@0: nsAdoptingString michael@0: Preferences::GetString(const char* aPref) michael@0: { michael@0: nsAdoptingString result; michael@0: GetString(aPref, &result); michael@0: return result; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetCString(const char* aPref, nsACString* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: nsAutoCString result; michael@0: nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: *aResult = result; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetString(const char* aPref, nsAString* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: nsAutoCString result; michael@0: nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: CopyUTF8toUTF16(result, *aResult); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsAdoptingCString michael@0: Preferences::GetLocalizedCString(const char* aPref) michael@0: { michael@0: nsAdoptingCString result; michael@0: GetLocalizedCString(aPref, &result); michael@0: return result; michael@0: } michael@0: michael@0: // static michael@0: nsAdoptingString michael@0: Preferences::GetLocalizedString(const char* aPref) michael@0: { michael@0: nsAdoptingString result; michael@0: GetLocalizedString(aPref, &result); michael@0: return result; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetLocalizedCString(const char* aPref, nsACString* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: nsAutoString result; michael@0: nsresult rv = GetLocalizedString(aPref, &result); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: CopyUTF16toUTF8(result, *aResult); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetLocalizedString(const char* aPref, nsAString* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: nsCOMPtr prefLocalString; michael@0: nsresult rv = sRootBranch->GetComplexValue(aPref, michael@0: NS_GET_IID(nsIPrefLocalizedString), michael@0: getter_AddRefs(prefLocalString)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL"); michael@0: prefLocalString->GetData(getter_Copies(*aResult)); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetComplex(const char* aPref, const nsIID &aType, void** aResult) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return sRootBranch->GetComplexValue(aPref, aType, aResult); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::SetCString(const char* aPref, const char* aValue) michael@0: { michael@0: ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_SetCharPref(aPref, aValue, false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::SetCString(const char* aPref, const nsACString &aValue) michael@0: { michael@0: ENSURE_MAIN_PROCESS("Cannot SetCString from content process:", aPref); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_SetCharPref(aPref, PromiseFlatCString(aValue).get(), false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::SetString(const char* aPref, const char16_t* aValue) michael@0: { michael@0: ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::SetString(const char* aPref, const nsAString &aValue) michael@0: { michael@0: ENSURE_MAIN_PROCESS("Cannot SetString from content process:", aPref); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::SetBool(const char* aPref, bool aValue) michael@0: { michael@0: ENSURE_MAIN_PROCESS("Cannot SetBool from content process:", aPref); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_SetBoolPref(aPref, aValue, false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::SetInt(const char* aPref, int32_t aValue) michael@0: { michael@0: ENSURE_MAIN_PROCESS("Cannot SetInt from content process:", aPref); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_SetIntPref(aPref, aValue, false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::SetComplex(const char* aPref, const nsIID &aType, michael@0: nsISupports* aValue) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return sRootBranch->SetComplexValue(aPref, aType, aValue); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::ClearUser(const char* aPref) michael@0: { michael@0: ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:", aPref); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_ClearUserPref(aPref); michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: Preferences::HasUserValue(const char* aPref) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), false); michael@0: return PREF_HasUserPref(aPref); michael@0: } michael@0: michael@0: // static michael@0: int32_t michael@0: Preferences::GetType(const char* aPref) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID); michael@0: int32_t result; michael@0: return NS_SUCCEEDED(sRootBranch->GetPrefType(aPref, &result)) ? michael@0: result : nsIPrefBranch::PREF_INVALID; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::AddStrongObserver(nsIObserver* aObserver, michael@0: const char* aPref) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return sRootBranch->AddObserver(aPref, aObserver, false); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::AddWeakObserver(nsIObserver* aObserver, michael@0: const char* aPref) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return sRootBranch->AddObserver(aPref, aObserver, true); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::RemoveObserver(nsIObserver* aObserver, michael@0: const char* aPref) michael@0: { michael@0: if (!sPreferences && sShutdown) { michael@0: return NS_OK; // Observers have been released automatically. michael@0: } michael@0: NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE); michael@0: return sRootBranch->RemoveObserver(aPref, aObserver); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::AddStrongObservers(nsIObserver* aObserver, michael@0: const char** aPrefs) michael@0: { michael@0: for (uint32_t i = 0; aPrefs[i]; i++) { michael@0: nsresult rv = AddStrongObserver(aObserver, aPrefs[i]); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::AddWeakObservers(nsIObserver* aObserver, michael@0: const char** aPrefs) michael@0: { michael@0: for (uint32_t i = 0; aPrefs[i]; i++) { michael@0: nsresult rv = AddWeakObserver(aObserver, aPrefs[i]); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::RemoveObservers(nsIObserver* aObserver, michael@0: const char** aPrefs) michael@0: { michael@0: if (!sPreferences && sShutdown) { michael@0: return NS_OK; // Observers have been released automatically. michael@0: } michael@0: NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: for (uint32_t i = 0; aPrefs[i]; i++) { michael@0: nsresult rv = RemoveObserver(aObserver, aPrefs[i]); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::RegisterCallback(PrefChangedFunc aCallback, michael@0: const char* aPref, michael@0: void* aClosure) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: ValueObserverHashKey hashKey(aPref, aCallback); michael@0: nsRefPtr observer; michael@0: gObserverTable->Get(&hashKey, getter_AddRefs(observer)); michael@0: if (observer) { michael@0: observer->AppendClosure(aClosure); michael@0: return NS_OK; michael@0: } michael@0: michael@0: observer = new ValueObserver(aPref, aCallback); michael@0: observer->AppendClosure(aClosure); michael@0: nsresult rv = AddStrongObserver(observer, aPref); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: gObserverTable->Put(observer, observer); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback, michael@0: const char* aPref, michael@0: void* aClosure) michael@0: { michael@0: nsresult rv = RegisterCallback(aCallback, aPref, aClosure); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: (*aCallback)(aPref, aClosure); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::UnregisterCallback(PrefChangedFunc aCallback, michael@0: const char* aPref, michael@0: void* aClosure) michael@0: { michael@0: if (!sPreferences && sShutdown) { michael@0: return NS_OK; // Observers have been released automatically. michael@0: } michael@0: NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE); michael@0: michael@0: ValueObserverHashKey hashKey(aPref, aCallback); michael@0: nsRefPtr observer; michael@0: gObserverTable->Get(&hashKey, getter_AddRefs(observer)); michael@0: if (!observer) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: observer->RemoveClosure(aClosure); michael@0: if (observer->HasNoClosures()) { michael@0: // Delete the callback since its list of closures is empty. michael@0: gObserverTable->Remove(observer); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void BoolVarChanged(const char* aPref, void* aClosure) michael@0: { michael@0: CacheData* cache = static_cast(aClosure); michael@0: *((bool*)cache->cacheLocation) = michael@0: Preferences::GetBool(aPref, cache->defaultValueBool); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::AddBoolVarCache(bool* aCache, michael@0: const char* aPref, michael@0: bool aDefault) michael@0: { michael@0: NS_ASSERTION(aCache, "aCache must not be NULL"); michael@0: *aCache = GetBool(aPref, aDefault); michael@0: CacheData* data = new CacheData(); michael@0: data->cacheLocation = aCache; michael@0: data->defaultValueBool = aDefault; michael@0: gCacheData->AppendElement(data); michael@0: return RegisterCallback(BoolVarChanged, aPref, data); michael@0: } michael@0: michael@0: static void IntVarChanged(const char* aPref, void* aClosure) michael@0: { michael@0: CacheData* cache = static_cast(aClosure); michael@0: *((int32_t*)cache->cacheLocation) = michael@0: Preferences::GetInt(aPref, cache->defaultValueInt); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::AddIntVarCache(int32_t* aCache, michael@0: const char* aPref, michael@0: int32_t aDefault) michael@0: { michael@0: NS_ASSERTION(aCache, "aCache must not be NULL"); michael@0: *aCache = Preferences::GetInt(aPref, aDefault); michael@0: CacheData* data = new CacheData(); michael@0: data->cacheLocation = aCache; michael@0: data->defaultValueInt = aDefault; michael@0: gCacheData->AppendElement(data); michael@0: return RegisterCallback(IntVarChanged, aPref, data); michael@0: } michael@0: michael@0: static void UintVarChanged(const char* aPref, void* aClosure) michael@0: { michael@0: CacheData* cache = static_cast(aClosure); michael@0: *((uint32_t*)cache->cacheLocation) = michael@0: Preferences::GetUint(aPref, cache->defaultValueUint); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::AddUintVarCache(uint32_t* aCache, michael@0: const char* aPref, michael@0: uint32_t aDefault) michael@0: { michael@0: NS_ASSERTION(aCache, "aCache must not be NULL"); michael@0: *aCache = Preferences::GetUint(aPref, aDefault); michael@0: CacheData* data = new CacheData(); michael@0: data->cacheLocation = aCache; michael@0: data->defaultValueUint = aDefault; michael@0: gCacheData->AppendElement(data); michael@0: return RegisterCallback(UintVarChanged, aPref, data); michael@0: } michael@0: michael@0: static void FloatVarChanged(const char* aPref, void* aClosure) michael@0: { michael@0: CacheData* cache = static_cast(aClosure); michael@0: *((float*)cache->cacheLocation) = michael@0: Preferences::GetFloat(aPref, cache->defaultValueFloat); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::AddFloatVarCache(float* aCache, michael@0: const char* aPref, michael@0: float aDefault) michael@0: { michael@0: NS_ASSERTION(aCache, "aCache must not be NULL"); michael@0: *aCache = Preferences::GetFloat(aPref, aDefault); michael@0: CacheData* data = new CacheData(); michael@0: data->cacheLocation = aCache; michael@0: data->defaultValueFloat = aDefault; michael@0: gCacheData->AppendElement(data); michael@0: return RegisterCallback(FloatVarChanged, aPref, data); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetDefaultBool(const char* aPref, bool* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_GetBoolPref(aPref, aResult, true); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetDefaultInt(const char* aPref, int32_t* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return PREF_GetIntPref(aPref, aResult, true); michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetDefaultCString(const char* aPref, nsACString* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: nsAutoCString result; michael@0: nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: *aResult = result; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetDefaultString(const char* aPref, nsAString* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult, "aResult must not be NULL"); michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: nsAutoCString result; michael@0: nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: CopyUTF8toUTF16(result, *aResult); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetDefaultLocalizedCString(const char* aPref, michael@0: nsACString* aResult) michael@0: { michael@0: nsAutoString result; michael@0: nsresult rv = GetDefaultLocalizedString(aPref, &result); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: CopyUTF16toUTF8(result, *aResult); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetDefaultLocalizedString(const char* aPref, michael@0: nsAString* aResult) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: nsCOMPtr prefLocalString; michael@0: nsresult rv = michael@0: sDefaultRootBranch->GetComplexValue(aPref, michael@0: NS_GET_IID(nsIPrefLocalizedString), michael@0: getter_AddRefs(prefLocalString)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL"); michael@0: prefLocalString->GetData(getter_Copies(*aResult)); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // static michael@0: nsAdoptingString michael@0: Preferences::GetDefaultString(const char* aPref) michael@0: { michael@0: nsAdoptingString result; michael@0: GetDefaultString(aPref, &result); michael@0: return result; michael@0: } michael@0: michael@0: // static michael@0: nsAdoptingCString michael@0: Preferences::GetDefaultCString(const char* aPref) michael@0: { michael@0: nsAdoptingCString result; michael@0: PREF_CopyCharPref(aPref, getter_Copies(result), true); michael@0: return result; michael@0: } michael@0: michael@0: // static michael@0: nsAdoptingString michael@0: Preferences::GetDefaultLocalizedString(const char* aPref) michael@0: { michael@0: nsAdoptingString result; michael@0: GetDefaultLocalizedString(aPref, &result); michael@0: return result; michael@0: } michael@0: michael@0: // static michael@0: nsAdoptingCString michael@0: Preferences::GetDefaultLocalizedCString(const char* aPref) michael@0: { michael@0: nsAdoptingCString result; michael@0: GetDefaultLocalizedCString(aPref, &result); michael@0: return result; michael@0: } michael@0: michael@0: // static michael@0: nsresult michael@0: Preferences::GetDefaultComplex(const char* aPref, const nsIID &aType, michael@0: void** aResult) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE); michael@0: return sDefaultRootBranch->GetComplexValue(aPref, aType, aResult); michael@0: } michael@0: michael@0: // static michael@0: int32_t michael@0: Preferences::GetDefaultType(const char* aPref) michael@0: { michael@0: NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID); michael@0: int32_t result; michael@0: return NS_SUCCEEDED(sDefaultRootBranch->GetPrefType(aPref, &result)) ? michael@0: result : nsIPrefBranch::PREF_INVALID; michael@0: } michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #undef ENSURE_MAIN_PROCESS