/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"mozilla/MemoryReporting.h"#include"mozilla/dom/ContentChild.h"#include"mozilla/ArrayUtils.h"#include"mozilla/Attributes.h"#include"mozilla/HashFunctions.h"#include"mozilla/UniquePtrExtensions.h"#include"nsXULAppAPI.h"#include"mozilla/Preferences.h"#include"nsAppDirectoryServiceDefs.h"#include"nsDataHashtable.h"#include"nsDirectoryServiceDefs.h"#include"nsICategoryManager.h"#include"nsCategoryManagerUtils.h"#include"nsNetUtil.h"#include"nsIFile.h"#include"nsIInputStream.h"#include"nsIObserverService.h"#include"nsIOutputStream.h"#include"nsISafeOutputStream.h"#include"nsISimpleEnumerator.h"#include"nsIStringEnumerator.h"#include"nsIZipReader.h"#include"nsPrefBranch.h"#include"nsXPIDLString.h"#include"nsCRT.h"#include"nsCOMArray.h"#include"nsXPCOMCID.h"#include"nsAutoPtr.h"#include"nsPrintfCString.h"#include"nsQuickSort.h"#include"PLDHashTable.h"#include"prefapi.h"#include"prefread.h"#include"prefapi_private_data.h"#include"mozilla/Omnijar.h"#include"nsZipArchive.h"#include"nsTArray.h"#include"nsRefPtrHashtable.h"#include"nsIMemoryReporter.h"#include"nsThreadUtils.h"#ifdef DEBUG#define ENSURE_MAIN_PROCESS(message, pref) do { \ if (MOZ_UNLIKELY(!XRE_IsParentProcess())) { \ nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref); \ NS_WARNING(msg.get()); \ return NS_ERROR_NOT_AVAILABLE; \ } \} while (0);#else#define ENSURE_MAIN_PROCESS(message, pref) \ if (MOZ_UNLIKELY(!XRE_IsParentProcess())) { \ return NS_ERROR_NOT_AVAILABLE; \ }#endifclassPrefCallback;namespacemozilla{// Definitions#define INITIAL_PREF_FILES 10staticNS_DEFINE_CID(kZipReaderCID,NS_ZIPREADER_CID);// PrototypesstaticnsresultopenPrefFile(nsIFile*aFile);staticnsresultpref_InitInitialObjects(void);staticnsresultpref_LoadPrefsInDirList(constchar*listId);staticnsresultReadExtensionPrefs(nsIFile*aFile);staticconstcharkTelemetryPref[]="toolkit.telemetry.enabled";staticconstcharkOldTelemetryPref[]="toolkit.telemetry.enabledPreRelease";staticconstcharkChannelPref[]="app.update.channel";Preferences*Preferences::sPreferences=nullptr;nsIPrefBranch*Preferences::sRootBranch=nullptr;nsIPrefBranch*Preferences::sDefaultRootBranch=nullptr;boolPreferences::sShutdown=false;classValueObserverHashKey:publicPLDHashEntryHdr{public:typedefValueObserverHashKey*KeyType;typedefconstValueObserverHashKey*KeyTypePointer;staticconstValueObserverHashKey*KeyToPointer(ValueObserverHashKey*aKey){returnaKey;}staticPLDHashNumberHashKey(constValueObserverHashKey*aKey){PLDHashNumberhash=HashString(aKey->mPrefName);hash=AddToHash(hash,aKey->mMatchKind);returnAddToHash(hash,aKey->mCallback);}ValueObserverHashKey(constchar*aPref,PrefChangedFuncaCallback,Preferences::MatchKindaMatchKind):mPrefName(aPref),mCallback(aCallback),mMatchKind(aMatchKind){}explicitValueObserverHashKey(constValueObserverHashKey*aOther):mPrefName(aOther->mPrefName),mCallback(aOther->mCallback),mMatchKind(aOther->mMatchKind){}boolKeyEquals(constValueObserverHashKey*aOther)const{returnmCallback==aOther->mCallback&&mPrefName==aOther->mPrefName&&mMatchKind==aOther->mMatchKind;}ValueObserverHashKey*GetKey()const{returnconst_cast<ValueObserverHashKey*>(this);}enum{ALLOW_MEMMOVE=true};nsCStringmPrefName;PrefChangedFuncmCallback;Preferences::MatchKindmMatchKind;};classValueObserverfinal:publicnsIObserver,publicValueObserverHashKey{~ValueObserver(){Preferences::RemoveObserver(this,mPrefName.get());}public:NS_DECL_ISUPPORTSNS_DECL_NSIOBSERVERValueObserver(constchar*aPref,PrefChangedFuncaCallback,Preferences::MatchKindaMatchKind):ValueObserverHashKey(aPref,aCallback,aMatchKind){}voidAppendClosure(void*aClosure){mClosures.AppendElement(aClosure);}voidRemoveClosure(void*aClosure){mClosures.RemoveElement(aClosure);}boolHasNoClosures(){returnmClosures.Length()==0;}nsTArray<void*>mClosures;};NS_IMPL_ISUPPORTS(ValueObserver,nsIObserver)NS_IMETHODIMPValueObserver::Observe(nsISupports*aSubject,constchar*aTopic,constchar16_t*aData){NS_ASSERTION(!nsCRT::strcmp(aTopic,NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),"invalid topic");NS_ConvertUTF16toUTF8data(aData);if(mMatchKind==Preferences::ExactMatch&&!mPrefName.EqualsASCII(data.get())){returnNS_OK;}for(uint32_ti=0;i<mClosures.Length();i++){mCallback(data.get(),mClosures.ElementAt(i));}returnNS_OK;}structCacheData{void*cacheLocation;union{booldefaultValueBool;int32_tdefaultValueInt;uint32_tdefaultValueUint;floatdefaultValueFloat;};};staticnsTArray<nsAutoPtr<CacheData>>*gCacheData=nullptr;staticnsRefPtrHashtable<ValueObserverHashKey,ValueObserver>*gObserverTable=nullptr;#ifdef DEBUGstaticboolHaveExistingCacheFor(void*aPtr){MOZ_ASSERT(NS_IsMainThread());if(gCacheData){for(size_ti=0,count=gCacheData->Length();i<count;++i){if((*gCacheData)[i]->cacheLocation==aPtr){returntrue;}}}returnfalse;}staticvoidAssertNotAlreadyCached(constchar*aPrefType,constchar*aPref,void*aPtr){if(HaveExistingCacheFor(aPtr)){fprintf_stderr(stderr,"Attempt to add a %s pref cache for preference '%s' at address '%p'""was made. However, a pref was already cached at this address.\n",aPrefType,aPref,aPtr);MOZ_ASSERT(false,"Should not have an existing pref cache for this address");}}#endifstaticvoidReportToConsole(constchar*aMessage,intaLine,boolaError){nsPrintfCStringmessage("** Preference parsing %s (line %d) = %s **\n",(aError?"error":"warning"),aLine,aMessage);nsPrefBranch::ReportToConsole(NS_ConvertUTF8toUTF16(message.get()));}// Although this is a member of Preferences, it measures sPreferences and// several other global structures./* static */int64_tPreferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOfaMallocSizeOf){NS_ENSURE_TRUE(InitStaticMembers(),0);size_tn=aMallocSizeOf(sPreferences);if(gHashTable){// pref keys are allocated in a private arena, which we count elsewhere.// pref stringvals are allocated out of the same private arena.n+=gHashTable->ShallowSizeOfIncludingThis(aMallocSizeOf);}if(gCacheData){n+=gCacheData->ShallowSizeOfIncludingThis(aMallocSizeOf);for(uint32_ti=0,count=gCacheData->Length();i<count;++i){n+=aMallocSizeOf((*gCacheData)[i]);}}if(gObserverTable){n+=gObserverTable->ShallowSizeOfIncludingThis(aMallocSizeOf);for(autoiter=gObserverTable->Iter();!iter.Done();iter.Next()){n+=iter.Key()->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);n+=iter.Data()->mClosures.ShallowSizeOfExcludingThis(aMallocSizeOf);}}if(sRootBranch){n+=reinterpret_cast<nsPrefBranch*>(sRootBranch)->SizeOfIncludingThis(aMallocSizeOf);}if(sDefaultRootBranch){n+=reinterpret_cast<nsPrefBranch*>(sDefaultRootBranch)->SizeOfIncludingThis(aMallocSizeOf);}n+=pref_SizeOfPrivateData(aMallocSizeOf);returnn;}classPreferenceServiceReporterfinal:publicnsIMemoryReporter{~PreferenceServiceReporter(){}public:NS_DECL_ISUPPORTSNS_DECL_NSIMEMORYREPORTERprotected:staticconstuint32_tkSuspectReferentCount=1000;};NS_IMPL_ISUPPORTS(PreferenceServiceReporter,nsIMemoryReporter)MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)NS_IMETHODIMPPreferenceServiceReporter::CollectReports(nsIMemoryReporterCallback*aCb,nsISupports*aClosure,boolaAnonymize){#define REPORT(_path, _kind, _units, _amount, _desc) \ do { \ nsresult rv; \ rv = aCb->Callback(EmptyCString(), _path, _kind, \ _units, _amount, NS_LITERAL_CSTRING(_desc), \ aClosure); \ NS_ENSURE_SUCCESS(rv, rv); \ } while (0)REPORT(NS_LITERAL_CSTRING("explicit/preferences"),KIND_HEAP,UNITS_BYTES,Preferences::SizeOfIncludingThisAndOtherStuff(PreferenceServiceMallocSizeOf),"Memory used by the preferences system.");nsPrefBranch*rootBranch=static_cast<nsPrefBranch*>(Preferences::GetRootBranch());if(!rootBranch){returnNS_OK;}size_tnumStrong=0;size_tnumWeakAlive=0;size_tnumWeakDead=0;nsTArray<nsCString>suspectPreferences;// Count of the number of referents for each preference.nsDataHashtable<nsCStringHashKey,uint32_t>prefCounter;for(autoiter=rootBranch->mObservers.Iter();!iter.Done();iter.Next()){nsAutoPtr<PrefCallback>&callback=iter.Data();nsPrefBranch*prefBranch=callback->GetPrefBranch();constchar*pref=prefBranch->getPrefName(callback->GetDomain().get());if(callback->IsWeak()){nsCOMPtr<nsIObserver>callbackRef=do_QueryReferent(callback->mWeakRef);if(callbackRef){numWeakAlive++;}else{numWeakDead++;}}else{numStrong++;}nsDependentCStringprefString(pref);uint32_toldCount=0;prefCounter.Get(prefString,&oldCount);uint32_tcurrentCount=oldCount+1;prefCounter.Put(prefString,currentCount);// Keep track of preferences that have a suspiciously large number of// referents (a symptom of a leak).if(currentCount==kSuspectReferentCount){suspectPreferences.AppendElement(prefString);}}for(uint32_ti=0;i<suspectPreferences.Length();i++){nsCString&suspect=suspectPreferences[i];uint32_ttotalReferentCount=0;prefCounter.Get(suspect,&totalReferentCount);nsPrintfCStringsuspectPath("preference-service-suspect/""referent(pref=%s)", suspect.get());REPORT(suspectPath,KIND_OTHER,UNITS_COUNT,totalReferentCount,"A preference with a suspiciously large number ""referents (symptom of a leak).");}REPORT(NS_LITERAL_CSTRING("preference-service/referent/strong"),KIND_OTHER,UNITS_COUNT,numStrong,"The number of strong referents held by the preference service.");REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/alive"),KIND_OTHER,UNITS_COUNT,numWeakAlive,"The number of weak referents held by the preference service ""that are still alive.");REPORT(NS_LITERAL_CSTRING("preference-service/referent/weak/dead"),KIND_OTHER,UNITS_COUNT,numWeakDead,"The number of weak referents held by the preference service ""that are dead.");#undef REPORTreturnNS_OK;}namespace{classAddPreferencesMemoryReporterRunnable:publicRunnable{NS_IMETHODRun(){returnRegisterStrongMemoryReporter(newPreferenceServiceReporter());}};}// namespace// staticPreferences*Preferences::GetInstanceForService(){if(sPreferences){NS_ADDREF(sPreferences);returnsPreferences;}NS_ENSURE_TRUE(!sShutdown,nullptr);sRootBranch=newnsPrefBranch("",false);NS_ADDREF(sRootBranch);sDefaultRootBranch=newnsPrefBranch("",true);NS_ADDREF(sDefaultRootBranch);sPreferences=newPreferences();NS_ADDREF(sPreferences);if(NS_FAILED(sPreferences->Init())){// The singleton instance will delete sRootBranch and sDefaultRootBranch.NS_RELEASE(sPreferences);returnnullptr;}gCacheData=newnsTArray<nsAutoPtr<CacheData>>();gObserverTable=newnsRefPtrHashtable<ValueObserverHashKey,ValueObserver>();// Preferences::GetInstanceForService() can be called from GetService(), and// RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To// avoid a potential recursive GetService() call, we can't register the// memory reporter here; instead, do it off a runnable.RefPtr<AddPreferencesMemoryReporterRunnable>runnable=newAddPreferencesMemoryReporterRunnable();NS_DispatchToMainThread(runnable);NS_ADDREF(sPreferences);returnsPreferences;}// staticboolPreferences::InitStaticMembers(){#ifndef MOZ_B2GMOZ_ASSERT(NS_IsMainThread());#endifif(!sShutdown&&!sPreferences){nsCOMPtr<nsIPrefService>prefService=do_GetService(NS_PREFSERVICE_CONTRACTID);}returnsPreferences!=nullptr;}// staticvoidPreferences::Shutdown(){if(!sShutdown){sShutdown=true;// Don't create the singleton instance after here.// Don't set sPreferences to nullptr here. The instance may be grabbed by// other modules. The utility methods of Preferences should be available// until the singleton instance actually released.if(sPreferences){sPreferences->Release();}}}//-----------------------------------------------------------------------------/* * Constructor/Destructor */Preferences::Preferences(){}Preferences::~Preferences(){NS_ASSERTION(sPreferences==this,"Isn't this the singleton instance?");deletegObserverTable;gObserverTable=nullptr;deletegCacheData;gCacheData=nullptr;NS_RELEASE(sRootBranch);NS_RELEASE(sDefaultRootBranch);sPreferences=nullptr;PREF_Cleanup();}/* * nsISupports Implementation */NS_IMPL_ADDREF(Preferences)NS_IMPL_RELEASE(Preferences)NS_INTERFACE_MAP_BEGIN(Preferences)NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,nsIPrefService)NS_INTERFACE_MAP_ENTRY(nsIPrefService)NS_INTERFACE_MAP_ENTRY(nsIObserver)NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)NS_INTERFACE_MAP_END/* * nsIPrefService Implementation */nsresultPreferences::Init(){nsresultrv;PREF_Init();rv=pref_InitInitialObjects();NS_ENSURE_SUCCESS(rv,rv);usingmozilla::dom::ContentChild;if(XRE_IsContentProcess()){InfallibleTArray<PrefSetting>prefs;ContentChild::GetSingleton()->SendReadPrefsArray(&prefs);// Store the arrayfor(uint32_ti=0;i<prefs.Length();++i){pref_SetPref(prefs[i]);}returnNS_OK;}nsXPIDLCStringlockFileName;/* * The following is a small hack which will allow us to only load the library * which supports the netscape.cfg file if the preference is defined. We * test for the existence of the pref, set in the all.js (mozilla) or * all-ns.js (netscape 6), and if it exists we startup the pref config * category which will do the rest. */rv=PREF_CopyCharPref("general.config.filename",getter_Copies(lockFileName),false);if(NS_SUCCEEDED(rv))NS_CreateServicesFromCategory("pref-config-startup",static_cast<nsISupports*>(static_cast<void*>(this)),"pref-config-startup");nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();if(!observerService)returnNS_ERROR_FAILURE;rv=observerService->AddObserver(this,"profile-before-change",true);observerService->AddObserver(this,"load-extension-defaults",true);observerService->AddObserver(this,"suspend_process_notification",true);return(rv);}// staticnsresultPreferences::ResetAndReadUserPrefs(){sPreferences->ResetUserPrefs();returnsPreferences->ReadUserPrefs(nullptr);}NS_IMETHODIMPPreferences::Observe(nsISupports*aSubject,constchar*aTopic,constchar16_t*someData){if(XRE_IsContentProcess())returnNS_ERROR_NOT_AVAILABLE;nsresultrv=NS_OK;if(!nsCRT::strcmp(aTopic,"profile-before-change")){rv=SavePrefFile(nullptr);}elseif(!strcmp(aTopic,"load-extension-defaults")){pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);}elseif(!nsCRT::strcmp(aTopic,"reload-default-prefs")){// Reload the default prefs from file.pref_InitInitialObjects();}elseif(!nsCRT::strcmp(aTopic,"suspend_process_notification")){// Our process is being suspended. The OS may wake our process later,// or it may kill the process. In case our process is going to be killed// from the suspended state, we save preferences before suspending.rv=SavePrefFile(nullptr);}returnrv;}NS_IMETHODIMPPreferences::ReadUserPrefs(nsIFile*aFile){if(XRE_IsContentProcess()){NS_ERROR("cannot load prefs from content process");returnNS_ERROR_NOT_AVAILABLE;}nsresultrv;if(nullptr==aFile){rv=UseDefaultPrefFile();// A user pref file is optional.// Ignore all errors related to it, so we retain 'rv' value :-|(void)UseUserPrefFile();// Migrate the old prerelease telemetry prefif(!Preferences::GetBool(kOldTelemetryPref,true)){Preferences::SetBool(kTelemetryPref,false);Preferences::ClearUser(kOldTelemetryPref);}NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);}else{rv=ReadAndOwnUserPrefFile(aFile);}returnrv;}NS_IMETHODIMPPreferences::ResetPrefs(){if(XRE_IsContentProcess()){NS_ERROR("cannot reset prefs from content process");returnNS_ERROR_NOT_AVAILABLE;}NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);PREF_CleanupPrefs();PREF_Init();returnpref_InitInitialObjects();}NS_IMETHODIMPPreferences::ResetUserPrefs(){if(XRE_IsContentProcess()){NS_ERROR("cannot reset user prefs from content process");returnNS_ERROR_NOT_AVAILABLE;}PREF_ClearAllUserPrefs();returnNS_OK;}NS_IMETHODIMPPreferences::SavePrefFile(nsIFile*aFile){if(XRE_IsContentProcess()){NS_ERROR("cannot save pref file from content process");returnNS_ERROR_NOT_AVAILABLE;}returnSavePrefFileInternal(aFile);}staticnsresultReadExtensionPrefs(nsIFile*aFile){nsresultrv;nsCOMPtr<nsIZipReader>reader=do_CreateInstance(kZipReaderCID,&rv);NS_ENSURE_SUCCESS(rv,rv);rv=reader->Open(aFile);NS_ENSURE_SUCCESS(rv,rv);nsCOMPtr<nsIUTF8StringEnumerator>files;rv=reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),getter_AddRefs(files));NS_ENSURE_SUCCESS(rv,rv);charbuffer[4096];boolmore;while(NS_SUCCEEDED(rv=files->HasMore(&more))&&more){nsAutoCStringentry;rv=files->GetNext(entry);NS_ENSURE_SUCCESS(rv,rv);nsCOMPtr<nsIInputStream>stream;rv=reader->GetInputStream(entry,getter_AddRefs(stream));NS_ENSURE_SUCCESS(rv,rv);uint64_tavail;uint32_tread;PrefParseStateps;PREF_InitParseState(&ps,PREF_ReaderCallback,ReportToConsole,nullptr);while(NS_SUCCEEDED(rv=stream->Available(&avail))&&avail){rv=stream->Read(buffer,4096,&read);if(NS_FAILED(rv)){NS_WARNING("Pref stream read failed");break;}PREF_ParseBuf(&ps,buffer,read);}PREF_FinalizeParseState(&ps);}returnrv;}voidPreferences::SetPreference(constPrefSetting&aPref){pref_SetPref(aPref);}voidPreferences::GetPreference(PrefSetting*aPref){PrefHashEntry*entry=pref_HashTableLookup(aPref->name().get());if(!entry)return;if(pref_EntryHasAdvisablySizedValues(entry)){pref_GetPrefFromEntry(entry,aPref);}}voidPreferences::GetPreferences(InfallibleTArray<PrefSetting>*aPrefs){aPrefs->SetCapacity(gHashTable->Capacity());for(autoiter=gHashTable->Iter();!iter.Done();iter.Next()){autoentry=static_cast<PrefHashEntry*>(iter.Get());if(!pref_EntryHasAdvisablySizedValues(entry)){continue;}dom::PrefSetting*pref=aPrefs->AppendElement();pref_GetPrefFromEntry(entry,pref);}}NS_IMETHODIMPPreferences::GetBranch(constchar*aPrefRoot,nsIPrefBranch**_retval){nsresultrv;if((nullptr!=aPrefRoot)&&(*aPrefRoot!='\0')){// TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)RefPtr<nsPrefBranch>prefBranch=newnsPrefBranch(aPrefRoot,false);prefBranch.forget(_retval);rv=NS_OK;}else{// special case caching the default rootnsCOMPtr<nsIPrefBranch>root(sRootBranch);root.forget(_retval);rv=NS_OK;}returnrv;}NS_IMETHODIMPPreferences::GetDefaultBranch(constchar*aPrefRoot,nsIPrefBranch**_retval){if(!aPrefRoot||!aPrefRoot[0]){nsCOMPtr<nsIPrefBranch>root(sDefaultRootBranch);root.forget(_retval);returnNS_OK;}// TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)RefPtr<nsPrefBranch>prefBranch=newnsPrefBranch(aPrefRoot,true);if(!prefBranch)returnNS_ERROR_OUT_OF_MEMORY;prefBranch.forget(_retval);returnNS_OK;}NS_IMETHODIMPPreferences::GetDirty(bool*_retval){*_retval=gDirty;returnNS_OK;}nsresultPreferences::NotifyServiceObservers(constchar*aTopic){nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();if(!observerService)returnNS_ERROR_FAILURE;nsISupports*subject=(nsISupports*)((nsIPrefService*)this);observerService->NotifyObservers(subject,aTopic,nullptr);returnNS_OK;}nsresultPreferences::UseDefaultPrefFile(){nsCOMPtr<nsIFile>aFile;nsresultrv=NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE,getter_AddRefs(aFile));if(NS_SUCCEEDED(rv)){rv=ReadAndOwnUserPrefFile(aFile);// Most likely cause of failure here is that the file didn't// exist, so save a new one. mUserPrefReadFailed will be// used to catch an error in actually reading the file.if(NS_FAILED(rv)){if(NS_FAILED(SavePrefFileInternal(aFile)))NS_ERROR("Failed to save new shared pref file");elserv=NS_OK;}}returnrv;}nsresultPreferences::UseUserPrefFile(){nsresultrv=NS_OK;nsCOMPtr<nsIFile>aFile;nsDependentCStringprefsDirProp(NS_APP_PREFS_50_DIR);rv=NS_GetSpecialDirectory(prefsDirProp.get(),getter_AddRefs(aFile));if(NS_SUCCEEDED(rv)&&aFile){rv=aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));if(NS_SUCCEEDED(rv)){boolexists=false;aFile->Exists(&exists);if(exists){rv=openPrefFile(aFile);}else{rv=NS_ERROR_FILE_NOT_FOUND;}}}returnrv;}nsresultPreferences::MakeBackupPrefFile(nsIFile*aFile){// Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.// "Invalidprefs.js" is removed if it exists, prior to making the copy.nsAutoStringnewFilename;nsresultrv=aFile->GetLeafName(newFilename);NS_ENSURE_SUCCESS(rv,rv);newFilename.Insert(NS_LITERAL_STRING("Invalid"),0);nsCOMPtr<nsIFile>newFile;rv=aFile->GetParent(getter_AddRefs(newFile));NS_ENSURE_SUCCESS(rv,rv);rv=newFile->Append(newFilename);NS_ENSURE_SUCCESS(rv,rv);boolexists=false;newFile->Exists(&exists);if(exists){rv=newFile->Remove(false);NS_ENSURE_SUCCESS(rv,rv);}rv=aFile->CopyTo(nullptr,newFilename);NS_ENSURE_SUCCESS(rv,rv);returnrv;}nsresultPreferences::ReadAndOwnUserPrefFile(nsIFile*aFile){NS_ENSURE_ARG(aFile);if(mCurrentFile==aFile)returnNS_OK;mCurrentFile=aFile;nsresultrv=NS_OK;boolexists=false;mCurrentFile->Exists(&exists);if(exists){rv=openPrefFile(mCurrentFile);if(NS_FAILED(rv)){// Save a backup copy of the current (invalid) prefs file, since all prefs// from the error line to the end of the file will be lost (bug 361102).// TODO we should notify the user about it (bug 523725).MakeBackupPrefFile(mCurrentFile);}}else{rv=NS_ERROR_FILE_NOT_FOUND;}returnrv;}nsresultPreferences::SavePrefFileInternal(nsIFile*aFile){if(nullptr==aFile){// the gDirty flag tells us if we should write to mCurrentFile// we only check this flag when the caller wants to write to the defaultif(!gDirty)returnNS_OK;// It's possible that we never got a prefs file.nsresultrv=NS_OK;if(mCurrentFile)rv=WritePrefFile(mCurrentFile);returnrv;}else{returnWritePrefFile(aFile);}}nsresultPreferences::WritePrefFile(nsIFile*aFile){constcharoutHeader[]="# Mozilla User Preferences"NS_LINEBREAKNS_LINEBREAK"/* Do not edit this file."NS_LINEBREAK" *"NS_LINEBREAK" * If you make changes to this file while the application is running,"NS_LINEBREAK" * the changes will be overwritten when the application exits."NS_LINEBREAK" *"NS_LINEBREAK" * To make a manual change to preferences, you can visit the URL about:config"NS_LINEBREAK" */"NS_LINEBREAKNS_LINEBREAK;nsCOMPtr<nsIOutputStream>outStreamSink;nsCOMPtr<nsIOutputStream>outStream;uint32_twriteAmount;nsresultrv;if(!gHashTable)returnNS_ERROR_NOT_INITIALIZED;// execute a "safe" save by saving through a tempfilerv=NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),aFile,-1,0600);if(NS_FAILED(rv))returnrv;rv=NS_NewBufferedOutputStream(getter_AddRefs(outStream),outStreamSink,4096);if(NS_FAILED(rv))returnrv;// get the lines that we're supposed to be writing to the fileUniquePtr<char*[]>valueArray=pref_savePrefs(gHashTable);/* Sort the preferences to make a readable file on disk */NS_QuickSort(valueArray.get(),gHashTable->EntryCount(),sizeof(char*),pref_CompareStrings,nullptr);// write out the file headeroutStream->Write(outHeader,sizeof(outHeader)-1,&writeAmount);for(uint32_tvalueIdx=0;valueIdx<gHashTable->EntryCount();valueIdx++){char*&pref=valueArray[valueIdx];if(pref){outStream->Write(pref,strlen(pref),&writeAmount);outStream->Write(NS_LINEBREAK,NS_LINEBREAK_LEN,&writeAmount);free(pref);pref=nullptr;}}// tell the safe output stream to overwrite the real prefs file// (it'll abort if there were any errors during writing)nsCOMPtr<nsISafeOutputStream>safeStream=do_QueryInterface(outStream);NS_ASSERTION(safeStream,"expected a safe output stream!");if(safeStream){rv=safeStream->Finish();if(NS_FAILED(rv)){NS_WARNING("failed to save prefs file! possible data loss");returnrv;}}gDirty=false;returnNS_OK;}staticnsresultopenPrefFile(nsIFile*aFile){nsCOMPtr<nsIInputStream>inStr;nsresultrv=NS_NewLocalFileInputStream(getter_AddRefs(inStr),aFile);if(NS_FAILED(rv))returnrv;int64_tfileSize64;rv=aFile->GetFileSize(&fileSize64);if(NS_FAILED(rv))returnrv;NS_ENSURE_TRUE(fileSize64<=UINT32_MAX,NS_ERROR_FILE_TOO_BIG);uint32_tfileSize=(uint32_t)fileSize64;autofileBuffer=MakeUniqueFallible<char[]>(fileSize);if(fileBuffer==nullptr)returnNS_ERROR_OUT_OF_MEMORY;PrefParseStateps;PREF_InitParseState(&ps,PREF_ReaderCallback,ReportToConsole,nullptr);// Read is not guaranteed to return a buf the size of fileSize,// but usually will.nsresultrv2=NS_OK;uint32_toffset=0;for(;;){uint32_tamtRead=0;rv=inStr->Read(fileBuffer.get(),fileSize,&amtRead);if(NS_FAILED(rv)||amtRead==0)break;if(!PREF_ParseBuf(&ps,fileBuffer.get(),amtRead))rv2=NS_ERROR_FILE_CORRUPTED;offset+=amtRead;if(offset==fileSize){break;}}PREF_FinalizeParseState(&ps);returnNS_FAILED(rv)?rv:rv2;}/* * some stuff that gets called from Pref_Init() */staticintpref_CompareFileNames(nsIFile*aFile1,nsIFile*aFile2,void*/*unused*/){nsAutoCStringfilename1,filename2;aFile1->GetNativeLeafName(filename1);aFile2->GetNativeLeafName(filename2);returnCompare(filename2,filename1);}/** * Load default pref files from a directory. The files in the * directory are sorted reverse-alphabetically; a set of "special file * names" may be specified which are loaded after all the others. */staticnsresultpref_LoadPrefsInDir(nsIFile*aDir,charconst*const*aSpecialFiles,uint32_taSpecialFilesCount){nsresultrv,rv2;boolhasMoreElements;nsCOMPtr<nsISimpleEnumerator>dirIterator;// this may fail in some normal cases, such as embedders who do not use a GRErv=aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));if(NS_FAILED(rv)){// If the directory doesn't exist, then we have no reason to complain. We// loaded everything (and nothing) successfully.if(rv==NS_ERROR_FILE_NOT_FOUND||rv==NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)rv=NS_OK;returnrv;}rv=dirIterator->HasMoreElements(&hasMoreElements);NS_ENSURE_SUCCESS(rv,rv);nsCOMArray<nsIFile>prefFiles(INITIAL_PREF_FILES);nsCOMArray<nsIFile>specialFiles(aSpecialFilesCount);nsCOMPtr<nsIFile>prefFile;while(hasMoreElements&&NS_SUCCEEDED(rv)){nsAutoCStringleafName;nsCOMPtr<nsISupports>supports;rv=dirIterator->GetNext(getter_AddRefs(supports));prefFile=do_QueryInterface(supports);if(NS_FAILED(rv)){break;}prefFile->GetNativeLeafName(leafName);NS_ASSERTION(!leafName.IsEmpty(),"Failure in default prefs: directory enumerator returned empty file?");// Skip non-js filesif(StringEndsWith(leafName,NS_LITERAL_CSTRING(".js"),nsCaseInsensitiveCStringComparator())){boolshouldParse=true;// separate out special filesfor(uint32_ti=0;i<aSpecialFilesCount;++i){if(leafName.Equals(nsDependentCString(aSpecialFiles[i]))){shouldParse=false;// special files should be process in order; we put them into// the array by index; this can make the array sparsespecialFiles.ReplaceObjectAt(prefFile,i);}}if(shouldParse){prefFiles.AppendObject(prefFile);}}rv=dirIterator->HasMoreElements(&hasMoreElements);}if(prefFiles.Count()+specialFiles.Count()==0){NS_WARNING("No default pref files found.");if(NS_SUCCEEDED(rv)){rv=NS_SUCCESS_FILE_DIRECTORY_EMPTY;}returnrv;}prefFiles.Sort(pref_CompareFileNames,nullptr);uint32_tarrayCount=prefFiles.Count();uint32_ti;for(i=0;i<arrayCount;++i){rv2=openPrefFile(prefFiles[i]);if(NS_FAILED(rv2)){NS_ERROR("Default pref file not parsed successfully.");rv=rv2;}}arrayCount=specialFiles.Count();for(i=0;i<arrayCount;++i){// this may be a sparse array; test before parsingnsIFile*file=specialFiles[i];if(file){rv2=openPrefFile(file);if(NS_FAILED(rv2)){NS_ERROR("Special default pref file not parsed successfully.");rv=rv2;}}}returnrv;}staticnsresultpref_LoadPrefsInDirList(constchar*listId){nsresultrv;nsCOMPtr<nsIProperties>dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));if(NS_FAILED(rv))returnrv;nsCOMPtr<nsISimpleEnumerator>list;dirSvc->Get(listId,NS_GET_IID(nsISimpleEnumerator),getter_AddRefs(list));if(!list)returnNS_OK;boolhasMore;while(NS_SUCCEEDED(list->HasMoreElements(&hasMore))&&hasMore){nsCOMPtr<nsISupports>elem;list->GetNext(getter_AddRefs(elem));if(!elem)continue;nsCOMPtr<nsIFile>path=do_QueryInterface(elem);if(!path)continue;nsAutoCStringleaf;path->GetNativeLeafName(leaf);// Do we care if a file provided by this process fails to load?if(Substring(leaf,leaf.Length()-4).EqualsLiteral(".xpi"))ReadExtensionPrefs(path);elsepref_LoadPrefsInDir(path,nullptr,0);}returnNS_OK;}staticnsresultpref_ReadPrefFromJar(nsZipArchive*jarReader,constchar*name){nsZipItemPtr<char>manifest(jarReader,name,true);NS_ENSURE_TRUE(manifest.Buffer(),NS_ERROR_NOT_AVAILABLE);PrefParseStateps;PREF_InitParseState(&ps,PREF_ReaderCallback,ReportToConsole,nullptr);PREF_ParseBuf(&ps,manifest,manifest.Length());PREF_FinalizeParseState(&ps);returnNS_OK;}//----------------------------------------------------------------------------------------// Initialize default preference JavaScript buffers from// appropriate TEXT resources//----------------------------------------------------------------------------------------staticnsresultpref_InitInitialObjects(){nsresultrv;// In omni.jar case, we load the following prefs:// - jar:$gre/omni.jar!/greprefs.js// - jar:$gre/omni.jar!/defaults/pref/*.js// In non omni.jar case, we load:// - $gre/greprefs.js//// In both cases, we also load:// - $gre/defaults/pref/*.js// This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)// on $app == $gre case ; we load all files instead of channel-prefs.js only// to have the same behaviour as $app != $gre, where this is required as// a supported location for GRE preferences.//// When $app != $gre, we additionally load, in omni.jar case:// - jar:$app/omni.jar!/defaults/preferences/*.js// - $app/defaults/preferences/*.js// and in non omni.jar case:// - $app/defaults/preferences/*.js// When $app == $gre, we additionally load, in omni.jar case:// - jar:$gre/omni.jar!/defaults/preferences/*.js// Thus, in omni.jar case, we always load app-specific default preferences// from omni.jar, whether or not $app == $gre.nsZipFind*findPtr;nsAutoPtr<nsZipFind>find;nsTArray<nsCString>prefEntries;constchar*entryName;uint16_tentryNameLen;RefPtr<nsZipArchive>jarReader=mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);if(jarReader){// Load jar:$gre/omni.jar!/greprefs.jsrv=pref_ReadPrefFromJar(jarReader,"greprefs.js");NS_ENSURE_SUCCESS(rv,rv);// Load jar:$gre/omni.jar!/defaults/pref/*.jsrv=jarReader->FindInit("defaults/pref/*.js$",&findPtr);NS_ENSURE_SUCCESS(rv,rv);find=findPtr;while(NS_SUCCEEDED(find->FindNext(&entryName,&entryNameLen))){prefEntries.AppendElement(Substring(entryName,entryNameLen));}prefEntries.Sort();for(uint32_ti=prefEntries.Length();i--;){rv=pref_ReadPrefFromJar(jarReader,prefEntries[i].get());if(NS_FAILED(rv))NS_WARNING("Error parsing preferences.");}}else{// Load $gre/greprefs.jsnsCOMPtr<nsIFile>greprefsFile;rv=NS_GetSpecialDirectory(NS_GRE_DIR,getter_AddRefs(greprefsFile));NS_ENSURE_SUCCESS(rv,rv);rv=greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));NS_ENSURE_SUCCESS(rv,rv);rv=openPrefFile(greprefsFile);if(NS_FAILED(rv))NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");}// Load $gre/defaults/pref/*.jsnsCOMPtr<nsIFile>defaultPrefDir;rv=NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR,getter_AddRefs(defaultPrefDir));NS_ENSURE_SUCCESS(rv,rv);/* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */staticconstchar*specialFiles[]={#if defined(XP_MACOSX)"macprefs.js"#elif defined(XP_WIN)"winpref.js"#elif defined(XP_UNIX)"unix.js"#if defined(_AIX),"aix.js"#endif#elif defined(XP_BEOS)"beos.js"#endif};rv=pref_LoadPrefsInDir(defaultPrefDir,specialFiles,ArrayLength(specialFiles));if(NS_FAILED(rv))NS_WARNING("Error parsing application default preferences.");// Load jar:$app/omni.jar!/defaults/preferences/*.js// or jar:$gre/omni.jar!/defaults/preferences/*.js.RefPtr<nsZipArchive>appJarReader=mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);// GetReader(mozilla::Omnijar::APP) returns null when $app == $gre, in which// case we look for app-specific default preferences in $gre.if(!appJarReader)appJarReader=mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);if(appJarReader){rv=appJarReader->FindInit("defaults/preferences/*.js$",&findPtr);NS_ENSURE_SUCCESS(rv,rv);find=findPtr;prefEntries.Clear();while(NS_SUCCEEDED(find->FindNext(&entryName,&entryNameLen))){prefEntries.AppendElement(Substring(entryName,entryNameLen));}prefEntries.Sort();for(uint32_ti=prefEntries.Length();i--;){rv=pref_ReadPrefFromJar(appJarReader,prefEntries[i].get());if(NS_FAILED(rv))NS_WARNING("Error parsing preferences.");}}rv=pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);NS_ENSURE_SUCCESS(rv,rv);// Set up the correct default for toolkit.telemetry.enabled.// If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta// channel, telemetry is on by default, otherwise not. This is necessary// so that beta users who are testing final release builds don't flipflop// defaults.if(Preferences::GetDefaultType(kTelemetryPref)==nsIPrefBranch::PREF_INVALID){boolprerelease=false;#ifdef MOZ_TELEMETRY_ON_BY_DEFAULTprerelease=true;#elseif(Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")){prerelease=true;}#endifPREF_SetBoolPref(kTelemetryPref,prerelease,true);}NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,nullptr,NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();if(!observerService)returnNS_ERROR_FAILURE;observerService->NotifyObservers(nullptr,NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,nullptr);returnpref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);}/****************************************************************************** * * static utilities * ******************************************************************************/// staticnsresultPreferences::GetBool(constchar*aPref,bool*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_GetBoolPref(aPref,aResult,false);}// staticnsresultPreferences::GetInt(constchar*aPref,int32_t*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_GetIntPref(aPref,aResult,false);}// staticnsresultPreferences::GetFloat(constchar*aPref,float*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);nsAutoCStringresult;nsresultrv=PREF_CopyCharPref(aPref,getter_Copies(result),false);if(NS_SUCCEEDED(rv)){*aResult=result.ToFloat(&rv);}returnrv;}// staticnsAdoptingCStringPreferences::GetCString(constchar*aPref){nsAdoptingCStringresult;PREF_CopyCharPref(aPref,getter_Copies(result),false);returnresult;}// staticnsAdoptingStringPreferences::GetString(constchar*aPref){nsAdoptingStringresult;GetString(aPref,&result);returnresult;}// staticnsresultPreferences::GetCString(constchar*aPref,nsACString*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);nsAutoCStringresult;nsresultrv=PREF_CopyCharPref(aPref,getter_Copies(result),false);if(NS_SUCCEEDED(rv)){*aResult=result;}returnrv;}// staticnsresultPreferences::GetString(constchar*aPref,nsAString*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);nsAutoCStringresult;nsresultrv=PREF_CopyCharPref(aPref,getter_Copies(result),false);if(NS_SUCCEEDED(rv)){CopyUTF8toUTF16(result,*aResult);}returnrv;}// staticnsAdoptingCStringPreferences::GetLocalizedCString(constchar*aPref){nsAdoptingCStringresult;GetLocalizedCString(aPref,&result);returnresult;}// staticnsAdoptingStringPreferences::GetLocalizedString(constchar*aPref){nsAdoptingStringresult;GetLocalizedString(aPref,&result);returnresult;}// staticnsresultPreferences::GetLocalizedCString(constchar*aPref,nsACString*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");nsAutoStringresult;nsresultrv=GetLocalizedString(aPref,&result);if(NS_SUCCEEDED(rv)){CopyUTF16toUTF8(result,*aResult);}returnrv;}// staticnsresultPreferences::GetLocalizedString(constchar*aPref,nsAString*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);nsCOMPtr<nsIPrefLocalizedString>prefLocalString;nsresultrv=sRootBranch->GetComplexValue(aPref,NS_GET_IID(nsIPrefLocalizedString),getter_AddRefs(prefLocalString));if(NS_SUCCEEDED(rv)){NS_ASSERTION(prefLocalString,"Succeeded but the result is NULL");prefLocalString->GetData(getter_Copies(*aResult));}returnrv;}// staticnsresultPreferences::GetComplex(constchar*aPref,constnsIID&aType,void**aResult){NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnsRootBranch->GetComplexValue(aPref,aType,aResult);}// staticnsresultPreferences::SetCString(constchar*aPref,constchar*aValue){ENSURE_MAIN_PROCESS("Cannot SetCString from content process:",aPref);NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_SetCharPref(aPref,aValue,false);}// staticnsresultPreferences::SetCString(constchar*aPref,constnsACString&aValue){ENSURE_MAIN_PROCESS("Cannot SetCString from content process:",aPref);NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_SetCharPref(aPref,PromiseFlatCString(aValue).get(),false);}// staticnsresultPreferences::SetString(constchar*aPref,constchar16ptr_taValue){ENSURE_MAIN_PROCESS("Cannot SetString from content process:",aPref);NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_SetCharPref(aPref,NS_ConvertUTF16toUTF8(aValue).get(),false);}// staticnsresultPreferences::SetString(constchar*aPref,constnsAString&aValue){ENSURE_MAIN_PROCESS("Cannot SetString from content process:",aPref);NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_SetCharPref(aPref,NS_ConvertUTF16toUTF8(aValue).get(),false);}// staticnsresultPreferences::SetBool(constchar*aPref,boolaValue){ENSURE_MAIN_PROCESS("Cannot SetBool from content process:",aPref);NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_SetBoolPref(aPref,aValue,false);}// staticnsresultPreferences::SetInt(constchar*aPref,int32_taValue){ENSURE_MAIN_PROCESS("Cannot SetInt from content process:",aPref);NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_SetIntPref(aPref,aValue,false);}// staticnsresultPreferences::SetFloat(constchar*aPref,floataValue){returnSetCString(aPref,nsPrintfCString("%f",aValue).get());}// staticnsresultPreferences::SetComplex(constchar*aPref,constnsIID&aType,nsISupports*aValue){NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnsRootBranch->SetComplexValue(aPref,aType,aValue);}// staticnsresultPreferences::ClearUser(constchar*aPref){ENSURE_MAIN_PROCESS("Cannot ClearUser from content process:",aPref);NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_ClearUserPref(aPref);}// staticboolPreferences::HasUserValue(constchar*aPref){NS_ENSURE_TRUE(InitStaticMembers(),false);returnPREF_HasUserPref(aPref);}// staticint32_tPreferences::GetType(constchar*aPref){NS_ENSURE_TRUE(InitStaticMembers(),nsIPrefBranch::PREF_INVALID);int32_tresult;returnNS_SUCCEEDED(sRootBranch->GetPrefType(aPref,&result))?result:nsIPrefBranch::PREF_INVALID;}// staticnsresultPreferences::AddStrongObserver(nsIObserver*aObserver,constchar*aPref){NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnsRootBranch->AddObserver(aPref,aObserver,false);}// staticnsresultPreferences::AddWeakObserver(nsIObserver*aObserver,constchar*aPref){NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnsRootBranch->AddObserver(aPref,aObserver,true);}// staticnsresultPreferences::RemoveObserver(nsIObserver*aObserver,constchar*aPref){if(!sPreferences&&sShutdown){returnNS_OK;// Observers have been released automatically.}NS_ENSURE_TRUE(sPreferences,NS_ERROR_NOT_AVAILABLE);returnsRootBranch->RemoveObserver(aPref,aObserver);}// staticnsresultPreferences::AddStrongObservers(nsIObserver*aObserver,constchar**aPrefs){for(uint32_ti=0;aPrefs[i];i++){nsresultrv=AddStrongObserver(aObserver,aPrefs[i]);NS_ENSURE_SUCCESS(rv,rv);}returnNS_OK;}// staticnsresultPreferences::AddWeakObservers(nsIObserver*aObserver,constchar**aPrefs){for(uint32_ti=0;aPrefs[i];i++){nsresultrv=AddWeakObserver(aObserver,aPrefs[i]);NS_ENSURE_SUCCESS(rv,rv);}returnNS_OK;}// staticnsresultPreferences::RemoveObservers(nsIObserver*aObserver,constchar**aPrefs){if(!sPreferences&&sShutdown){returnNS_OK;// Observers have been released automatically.}NS_ENSURE_TRUE(sPreferences,NS_ERROR_NOT_AVAILABLE);for(uint32_ti=0;aPrefs[i];i++){nsresultrv=RemoveObserver(aObserver,aPrefs[i]);NS_ENSURE_SUCCESS(rv,rv);}returnNS_OK;}// staticnsresultPreferences::RegisterCallback(PrefChangedFuncaCallback,constchar*aPref,void*aClosure,MatchKindaMatchKind){NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);ValueObserverHashKeyhashKey(aPref,aCallback,aMatchKind);RefPtr<ValueObserver>observer;gObserverTable->Get(&hashKey,getter_AddRefs(observer));if(observer){observer->AppendClosure(aClosure);returnNS_OK;}observer=newValueObserver(aPref,aCallback,aMatchKind);observer->AppendClosure(aClosure);nsresultrv=AddStrongObserver(observer,aPref);NS_ENSURE_SUCCESS(rv,rv);gObserverTable->Put(observer,observer);returnNS_OK;}// staticnsresultPreferences::RegisterCallbackAndCall(PrefChangedFuncaCallback,constchar*aPref,void*aClosure,MatchKindaMatchKind){nsresultrv=RegisterCallback(aCallback,aPref,aClosure,aMatchKind);if(NS_SUCCEEDED(rv)){(*aCallback)(aPref,aClosure);}returnrv;}// staticnsresultPreferences::UnregisterCallback(PrefChangedFuncaCallback,constchar*aPref,void*aClosure,MatchKindaMatchKind){if(!sPreferences&&sShutdown){returnNS_OK;// Observers have been released automatically.}NS_ENSURE_TRUE(sPreferences,NS_ERROR_NOT_AVAILABLE);ValueObserverHashKeyhashKey(aPref,aCallback,aMatchKind);RefPtr<ValueObserver>observer;gObserverTable->Get(&hashKey,getter_AddRefs(observer));if(!observer){returnNS_OK;}observer->RemoveClosure(aClosure);if(observer->HasNoClosures()){// Delete the callback since its list of closures is empty.gObserverTable->Remove(observer);}returnNS_OK;}staticvoidBoolVarChanged(constchar*aPref,void*aClosure){CacheData*cache=static_cast<CacheData*>(aClosure);*((bool*)cache->cacheLocation)=Preferences::GetBool(aPref,cache->defaultValueBool);}// staticnsresultPreferences::AddBoolVarCache(bool*aCache,constchar*aPref,boolaDefault){NS_ASSERTION(aCache,"aCache must not be NULL");#ifdef DEBUGAssertNotAlreadyCached("bool",aPref,aCache);#endif*aCache=GetBool(aPref,aDefault);CacheData*data=newCacheData();data->cacheLocation=aCache;data->defaultValueBool=aDefault;gCacheData->AppendElement(data);returnRegisterCallback(BoolVarChanged,aPref,data,ExactMatch);}staticvoidIntVarChanged(constchar*aPref,void*aClosure){CacheData*cache=static_cast<CacheData*>(aClosure);*((int32_t*)cache->cacheLocation)=Preferences::GetInt(aPref,cache->defaultValueInt);}// staticnsresultPreferences::AddIntVarCache(int32_t*aCache,constchar*aPref,int32_taDefault){NS_ASSERTION(aCache,"aCache must not be NULL");#ifdef DEBUGAssertNotAlreadyCached("int",aPref,aCache);#endif*aCache=Preferences::GetInt(aPref,aDefault);CacheData*data=newCacheData();data->cacheLocation=aCache;data->defaultValueInt=aDefault;gCacheData->AppendElement(data);returnRegisterCallback(IntVarChanged,aPref,data,ExactMatch);}staticvoidUintVarChanged(constchar*aPref,void*aClosure){CacheData*cache=static_cast<CacheData*>(aClosure);*((uint32_t*)cache->cacheLocation)=Preferences::GetUint(aPref,cache->defaultValueUint);}// staticnsresultPreferences::AddUintVarCache(uint32_t*aCache,constchar*aPref,uint32_taDefault){NS_ASSERTION(aCache,"aCache must not be NULL");#ifdef DEBUGAssertNotAlreadyCached("uint",aPref,aCache);#endif*aCache=Preferences::GetUint(aPref,aDefault);CacheData*data=newCacheData();data->cacheLocation=aCache;data->defaultValueUint=aDefault;gCacheData->AppendElement(data);returnRegisterCallback(UintVarChanged,aPref,data,ExactMatch);}template<MemoryOrderingOrder>staticvoidAtomicUintVarChanged(constchar*aPref,void*aClosure){CacheData*cache=static_cast<CacheData*>(aClosure);*((Atomic<uint32_t,Order>*)cache->cacheLocation)=Preferences::GetUint(aPref,cache->defaultValueUint);}template<MemoryOrderingOrder>// staticnsresultPreferences::AddAtomicUintVarCache(Atomic<uint32_t,Order>*aCache,constchar*aPref,uint32_taDefault){NS_ASSERTION(aCache,"aCache must not be NULL");#ifdef DEBUGAssertNotAlreadyCached("uint",aPref,aCache);#endif*aCache=Preferences::GetUint(aPref,aDefault);CacheData*data=newCacheData();data->cacheLocation=aCache;data->defaultValueUint=aDefault;gCacheData->AppendElement(data);returnRegisterCallback(AtomicUintVarChanged<Order>,aPref,data,ExactMatch);}// Since the definition of this template function is not in a header file,// we need to explicitly specify the instantiations that are required.// Currently only the order=Relaxed variant is needed.templatensresultPreferences::AddAtomicUintVarCache(Atomic<uint32_t,Relaxed>*,constchar*,uint32_t);staticvoidFloatVarChanged(constchar*aPref,void*aClosure){CacheData*cache=static_cast<CacheData*>(aClosure);*((float*)cache->cacheLocation)=Preferences::GetFloat(aPref,cache->defaultValueFloat);}// staticnsresultPreferences::AddFloatVarCache(float*aCache,constchar*aPref,floataDefault){NS_ASSERTION(aCache,"aCache must not be NULL");#ifdef DEBUGAssertNotAlreadyCached("float",aPref,aCache);#endif*aCache=Preferences::GetFloat(aPref,aDefault);CacheData*data=newCacheData();data->cacheLocation=aCache;data->defaultValueFloat=aDefault;gCacheData->AppendElement(data);returnRegisterCallback(FloatVarChanged,aPref,data,ExactMatch);}// staticnsresultPreferences::GetDefaultBool(constchar*aPref,bool*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_GetBoolPref(aPref,aResult,true);}// staticnsresultPreferences::GetDefaultInt(constchar*aPref,int32_t*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnPREF_GetIntPref(aPref,aResult,true);}// staticnsresultPreferences::GetDefaultCString(constchar*aPref,nsACString*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);nsAutoCStringresult;nsresultrv=PREF_CopyCharPref(aPref,getter_Copies(result),true);if(NS_SUCCEEDED(rv)){*aResult=result;}returnrv;}// staticnsresultPreferences::GetDefaultString(constchar*aPref,nsAString*aResult){NS_PRECONDITION(aResult,"aResult must not be NULL");NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);nsAutoCStringresult;nsresultrv=PREF_CopyCharPref(aPref,getter_Copies(result),true);if(NS_SUCCEEDED(rv)){CopyUTF8toUTF16(result,*aResult);}returnrv;}// staticnsresultPreferences::GetDefaultLocalizedCString(constchar*aPref,nsACString*aResult){nsAutoStringresult;nsresultrv=GetDefaultLocalizedString(aPref,&result);if(NS_SUCCEEDED(rv)){CopyUTF16toUTF8(result,*aResult);}returnrv;}// staticnsresultPreferences::GetDefaultLocalizedString(constchar*aPref,nsAString*aResult){NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);nsCOMPtr<nsIPrefLocalizedString>prefLocalString;nsresultrv=sDefaultRootBranch->GetComplexValue(aPref,NS_GET_IID(nsIPrefLocalizedString),getter_AddRefs(prefLocalString));if(NS_SUCCEEDED(rv)){NS_ASSERTION(prefLocalString,"Succeeded but the result is NULL");prefLocalString->GetData(getter_Copies(*aResult));}returnrv;}// staticnsAdoptingStringPreferences::GetDefaultString(constchar*aPref){nsAdoptingStringresult;GetDefaultString(aPref,&result);returnresult;}// staticnsAdoptingCStringPreferences::GetDefaultCString(constchar*aPref){nsAdoptingCStringresult;PREF_CopyCharPref(aPref,getter_Copies(result),true);returnresult;}// staticnsAdoptingStringPreferences::GetDefaultLocalizedString(constchar*aPref){nsAdoptingStringresult;GetDefaultLocalizedString(aPref,&result);returnresult;}// staticnsAdoptingCStringPreferences::GetDefaultLocalizedCString(constchar*aPref){nsAdoptingCStringresult;GetDefaultLocalizedCString(aPref,&result);returnresult;}// staticnsresultPreferences::GetDefaultComplex(constchar*aPref,constnsIID&aType,void**aResult){NS_ENSURE_TRUE(InitStaticMembers(),NS_ERROR_NOT_AVAILABLE);returnsDefaultRootBranch->GetComplexValue(aPref,aType,aResult);}// staticint32_tPreferences::GetDefaultType(constchar*aPref){NS_ENSURE_TRUE(InitStaticMembers(),nsIPrefBranch::PREF_INVALID);int32_tresult;returnNS_SUCCEEDED(sDefaultRootBranch->GetPrefType(aPref,&result))?result:nsIPrefBranch::PREF_INVALID;}}// namespace mozilla#undef ENSURE_MAIN_PROCESS