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