1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Alec Flett <alecf@netscape.com>
24 : * Mats Palmgren <matspal@gmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "mozilla/dom/ContentChild.h"
41 :
42 : #include "mozilla/Util.h"
43 : #include "mozilla/HashFunctions.h"
44 :
45 : #include "nsXULAppAPI.h"
46 :
47 : #include "mozilla/Preferences.h"
48 : #include "nsAppDirectoryServiceDefs.h"
49 : #include "nsDirectoryServiceDefs.h"
50 : #include "nsICategoryManager.h"
51 : #include "nsCategoryManagerUtils.h"
52 : #include "nsNetUtil.h"
53 : #include "nsIFile.h"
54 : #include "nsIInputStream.h"
55 : #include "nsILocalFile.h"
56 : #include "nsIObserverService.h"
57 : #include "nsIStringEnumerator.h"
58 : #include "nsIZipReader.h"
59 : #include "nsPrefBranch.h"
60 : #include "nsXPIDLString.h"
61 : #include "nsCRT.h"
62 : #include "nsCOMArray.h"
63 : #include "nsXPCOMCID.h"
64 : #include "nsAutoPtr.h"
65 :
66 : #include "nsQuickSort.h"
67 : #include "prmem.h"
68 : #include "pldhash.h"
69 :
70 : #include "prefapi.h"
71 : #include "prefread.h"
72 : #include "prefapi_private_data.h"
73 : #include "PrefTuple.h"
74 :
75 : #include "mozilla/Omnijar.h"
76 : #include "nsZipArchive.h"
77 :
78 : #include "nsTArray.h"
79 : #include "nsRefPtrHashtable.h"
80 :
81 : namespace mozilla {
82 :
83 : // Definitions
84 : #define INITIAL_PREF_FILES 10
85 : static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
86 :
87 : // Prototypes
88 : static nsresult openPrefFile(nsIFile* aFile);
89 : static nsresult pref_InitInitialObjects(void);
90 : static nsresult pref_LoadPrefsInDirList(const char *listId);
91 : static nsresult ReadExtensionPrefs(nsIFile *aFile);
92 :
93 : Preferences* Preferences::sPreferences = nsnull;
94 : nsIPrefBranch* Preferences::sRootBranch = nsnull;
95 : nsIPrefBranch* Preferences::sDefaultRootBranch = nsnull;
96 : bool Preferences::sShutdown = false;
97 :
98 148339 : class ValueObserverHashKey : public PLDHashEntryHdr {
99 : public:
100 : typedef ValueObserverHashKey* KeyType;
101 : typedef const ValueObserverHashKey* KeyTypePointer;
102 :
103 101231 : static const ValueObserverHashKey* KeyToPointer(ValueObserverHashKey *aKey)
104 : {
105 101231 : return aKey;
106 : }
107 :
108 101231 : static PLDHashNumber HashKey(const ValueObserverHashKey *aKey)
109 : {
110 101231 : PLDHashNumber hash = HashString(aKey->mPrefName);
111 101231 : return AddToHash(hash, aKey->mCallback);
112 : }
113 :
114 99828 : ValueObserverHashKey(const char *aPref, PrefChangedFunc aCallback) :
115 99828 : mPrefName(aPref), mCallback(aCallback) { }
116 :
117 48511 : ValueObserverHashKey(const ValueObserverHashKey *aOther) :
118 48511 : mPrefName(aOther->mPrefName), mCallback(aOther->mCallback)
119 48511 : { }
120 :
121 2806 : bool KeyEquals(const ValueObserverHashKey *aOther) const
122 : {
123 2806 : return mCallback == aOther->mCallback && mPrefName == aOther->mPrefName;
124 : }
125 :
126 : ValueObserverHashKey *GetKey() const
127 : {
128 : return const_cast<ValueObserverHashKey*>(this);
129 : }
130 :
131 : enum { ALLOW_MEMMOVE = true };
132 :
133 : nsCString mPrefName;
134 : PrefChangedFunc mCallback;
135 : };
136 :
137 : class ValueObserver : public nsIObserver,
138 : public ValueObserverHashKey
139 : {
140 : public:
141 : NS_DECL_ISUPPORTS
142 : NS_DECL_NSIOBSERVER
143 :
144 48511 : ValueObserver(const char *aPref, PrefChangedFunc aCallback)
145 48511 : : ValueObserverHashKey(aPref, aCallback) { }
146 :
147 97022 : ~ValueObserver() {
148 48511 : Preferences::RemoveObserver(this, mPrefName.get());
149 48511 : }
150 :
151 48511 : void AppendClosure(void *aClosure) {
152 48511 : mClosures.AppendElement(aClosure);
153 48511 : }
154 :
155 1403 : void RemoveClosure(void *aClosure) {
156 1403 : mClosures.RemoveElement(aClosure);
157 1403 : }
158 :
159 1403 : bool HasNoClosures() {
160 1403 : return mClosures.Length() == 0;
161 : }
162 :
163 : nsTArray<void*> mClosures;
164 : };
165 :
166 1109805 : NS_IMPL_ISUPPORTS1(ValueObserver, nsIObserver)
167 :
168 : NS_IMETHODIMP
169 22 : ValueObserver::Observe(nsISupports *aSubject,
170 : const char *aTopic,
171 : const PRUnichar *aData)
172 : {
173 22 : NS_ASSERTION(!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
174 : "invalid topic");
175 44 : NS_ConvertUTF16toUTF8 data(aData);
176 44 : for (PRUint32 i = 0; i < mClosures.Length(); i++) {
177 22 : mCallback(data.get(), mClosures.ElementAt(i));
178 : }
179 :
180 22 : return NS_OK;
181 : }
182 :
183 : struct CacheData {
184 : void* cacheLocation;
185 : union {
186 : bool defaultValueBool;
187 : PRInt32 defaultValueInt;
188 : PRUint32 defaultValueUint;
189 : };
190 : };
191 :
192 : static nsTArray<nsAutoPtr<CacheData> >* gCacheData = nsnull;
193 : static nsRefPtrHashtable<ValueObserverHashKey,
194 : ValueObserver>* gObserverTable = nsnull;
195 :
196 : // static
197 : Preferences*
198 1419 : Preferences::GetInstanceForService()
199 : {
200 1419 : if (sPreferences) {
201 0 : NS_ADDREF(sPreferences);
202 0 : return sPreferences;
203 : }
204 :
205 1419 : NS_ENSURE_TRUE(!sShutdown, nsnull);
206 :
207 1419 : sRootBranch = new nsPrefBranch("", false);
208 1419 : NS_ADDREF(sRootBranch);
209 1419 : sDefaultRootBranch = new nsPrefBranch("", true);
210 1419 : NS_ADDREF(sDefaultRootBranch);
211 :
212 1419 : sPreferences = new Preferences();
213 1419 : NS_ADDREF(sPreferences);
214 :
215 1419 : if (NS_FAILED(sPreferences->Init())) {
216 : // The singleton instance will delete sRootBranch and sDefaultRootBranch.
217 0 : NS_RELEASE(sPreferences);
218 0 : return nsnull;
219 : }
220 :
221 1419 : gCacheData = new nsTArray<nsAutoPtr<CacheData> >();
222 :
223 1419 : gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
224 1419 : gObserverTable->Init();
225 :
226 1419 : NS_ADDREF(sPreferences);
227 1419 : return sPreferences;
228 : }
229 :
230 : // static
231 : bool
232 192732 : Preferences::InitStaticMembers()
233 : {
234 192732 : if (!sShutdown && !sPreferences) {
235 : nsCOMPtr<nsIPrefService> prefService =
236 0 : do_GetService(NS_PREFSERVICE_CONTRACTID);
237 : }
238 :
239 192732 : return sPreferences != nsnull;
240 : }
241 :
242 : // static
243 : void
244 1419 : Preferences::Shutdown()
245 : {
246 1419 : if (!sShutdown) {
247 1419 : sShutdown = true; // Don't create the singleton instance after here.
248 :
249 : // Don't set NULL to sPreferences here. The instance may be grabbed by
250 : // other modules. The utility methods of Preferences should be available
251 : // until the singleton instance actually released.
252 1419 : if (sPreferences) {
253 1419 : sPreferences->Release();
254 : }
255 : }
256 1419 : }
257 :
258 : //-----------------------------------------------------------------------------
259 :
260 : /*
261 : * Constructor/Destructor
262 : */
263 :
264 1419 : Preferences::Preferences()
265 : {
266 1419 : }
267 :
268 4257 : Preferences::~Preferences()
269 : {
270 1419 : NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?");
271 :
272 1419 : delete gObserverTable;
273 1419 : gObserverTable = nsnull;
274 :
275 1419 : delete gCacheData;
276 1419 : gCacheData = nsnull;
277 :
278 1419 : NS_RELEASE(sRootBranch);
279 1419 : NS_RELEASE(sDefaultRootBranch);
280 :
281 1419 : sPreferences = nsnull;
282 :
283 1419 : PREF_Cleanup();
284 5676 : }
285 :
286 :
287 : /*
288 : * nsISupports Implementation
289 : */
290 :
291 99849 : NS_IMPL_THREADSAFE_ADDREF(Preferences)
292 99849 : NS_IMPL_THREADSAFE_RELEASE(Preferences)
293 :
294 81222 : NS_INTERFACE_MAP_BEGIN(Preferences)
295 81222 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefService)
296 76772 : NS_INTERFACE_MAP_ENTRY(nsIPrefService)
297 70131 : NS_INTERFACE_MAP_ENTRY(nsIObserver)
298 68499 : NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
299 21292 : NS_INTERFACE_MAP_ENTRY(nsIPrefBranch2)
300 21292 : NS_INTERFACE_MAP_ENTRY(nsIPrefBranchInternal)
301 21292 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
302 18454 : NS_INTERFACE_MAP_END
303 :
304 :
305 : /*
306 : * nsIPrefService Implementation
307 : */
308 :
309 : nsresult
310 1419 : Preferences::Init()
311 : {
312 : nsresult rv;
313 :
314 1419 : rv = PREF_Init();
315 1419 : NS_ENSURE_SUCCESS(rv, rv);
316 :
317 1419 : rv = pref_InitInitialObjects();
318 1419 : NS_ENSURE_SUCCESS(rv, rv);
319 :
320 : using mozilla::dom::ContentChild;
321 1419 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
322 0 : InfallibleTArray<PrefTuple> array;
323 0 : ContentChild::GetSingleton()->SendReadPrefsArray(&array);
324 :
325 : // Store the array
326 0 : nsTArray<PrefTuple>::size_type index = array.Length();
327 0 : while (index-- > 0) {
328 0 : pref_SetPrefTuple(array[index], true);
329 : }
330 0 : return NS_OK;
331 : }
332 :
333 2838 : nsXPIDLCString lockFileName;
334 : /*
335 : * The following is a small hack which will allow us to only load the library
336 : * which supports the netscape.cfg file if the preference is defined. We
337 : * test for the existence of the pref, set in the all.js (mozilla) or
338 : * all-ns.js (netscape 6), and if it exists we startup the pref config
339 : * category which will do the rest.
340 : */
341 :
342 1419 : rv = PREF_CopyCharPref("general.config.filename", getter_Copies(lockFileName), false);
343 1419 : if (NS_SUCCEEDED(rv))
344 : NS_CreateServicesFromCategory("pref-config-startup",
345 : static_cast<nsISupports *>(static_cast<void *>(this)),
346 0 : "pref-config-startup");
347 :
348 : nsCOMPtr<nsIObserverService> observerService =
349 2838 : mozilla::services::GetObserverService();
350 1419 : if (!observerService)
351 0 : return NS_ERROR_FAILURE;
352 :
353 1419 : rv = observerService->AddObserver(this, "profile-before-change", true);
354 :
355 1419 : observerService->AddObserver(this, "load-extension-defaults", true);
356 :
357 1419 : return(rv);
358 : }
359 :
360 : // static
361 : nsresult
362 0 : Preferences::ResetAndReadUserPrefs()
363 : {
364 0 : sPreferences->ResetUserPrefs();
365 0 : return sPreferences->ReadUserPrefs(nsnull);
366 : }
367 :
368 : NS_IMETHODIMP
369 816 : Preferences::Observe(nsISupports *aSubject, const char *aTopic,
370 : const PRUnichar *someData)
371 : {
372 816 : if (XRE_GetProcessType() == GeckoProcessType_Content)
373 0 : return NS_ERROR_NOT_AVAILABLE;
374 :
375 816 : nsresult rv = NS_OK;
376 :
377 816 : if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
378 814 : if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
379 0 : if (mCurrentFile) {
380 0 : mCurrentFile->Remove(false);
381 0 : mCurrentFile = nsnull;
382 : }
383 : } else {
384 814 : rv = SavePrefFile(nsnull);
385 : }
386 2 : } else if (!strcmp(aTopic, "load-extension-defaults")) {
387 1 : pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
388 1 : } else if (!nsCRT::strcmp(aTopic, "reload-default-prefs")) {
389 : // Reload the default prefs from file.
390 1 : pref_InitInitialObjects();
391 : }
392 816 : return rv;
393 : }
394 :
395 :
396 : NS_IMETHODIMP
397 4 : Preferences::ReadUserPrefs(nsIFile *aFile)
398 : {
399 4 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
400 0 : NS_ERROR("cannot load prefs from content process");
401 0 : return NS_ERROR_NOT_AVAILABLE;
402 : }
403 :
404 : nsresult rv;
405 :
406 4 : if (nsnull == aFile) {
407 0 : rv = UseDefaultPrefFile();
408 0 : UseUserPrefFile();
409 :
410 0 : NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID);
411 :
412 : } else {
413 4 : rv = ReadAndOwnUserPrefFile(aFile);
414 : }
415 4 : return rv;
416 : }
417 :
418 : NS_IMETHODIMP
419 1 : Preferences::ResetPrefs()
420 : {
421 1 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
422 0 : NS_ERROR("cannot set prefs from content process");
423 0 : return NS_ERROR_NOT_AVAILABLE;
424 : }
425 :
426 1 : NotifyServiceObservers(NS_PREFSERVICE_RESET_TOPIC_ID);
427 1 : PREF_CleanupPrefs();
428 :
429 1 : nsresult rv = PREF_Init();
430 1 : NS_ENSURE_SUCCESS(rv, rv);
431 :
432 1 : return pref_InitInitialObjects();
433 : }
434 :
435 : NS_IMETHODIMP
436 0 : Preferences::ResetUserPrefs()
437 : {
438 0 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
439 0 : NS_ERROR("cannot set prefs from content process");
440 0 : return NS_ERROR_NOT_AVAILABLE;
441 : }
442 :
443 0 : PREF_ClearAllUserPrefs();
444 0 : return NS_OK;
445 : }
446 :
447 : NS_IMETHODIMP
448 2117 : Preferences::SavePrefFile(nsIFile *aFile)
449 : {
450 2117 : if (XRE_GetProcessType() == GeckoProcessType_Content) {
451 0 : NS_ERROR("cannot save prefs from content process");
452 0 : return NS_ERROR_NOT_AVAILABLE;
453 : }
454 :
455 2117 : return SavePrefFileInternal(aFile);
456 : }
457 :
458 : static nsresult
459 0 : ReadExtensionPrefs(nsIFile *aFile)
460 : {
461 : nsresult rv;
462 0 : nsCOMPtr<nsIZipReader> reader = do_CreateInstance(kZipReaderCID, &rv);
463 0 : NS_ENSURE_SUCCESS(rv, rv);
464 :
465 0 : rv = reader->Open(aFile);
466 0 : NS_ENSURE_SUCCESS(rv, rv);
467 :
468 0 : nsCOMPtr<nsIUTF8StringEnumerator> files;
469 0 : rv = reader->FindEntries(nsDependentCString("defaults/preferences/*.(J|j)(S|s)$"),
470 0 : getter_AddRefs(files));
471 0 : NS_ENSURE_SUCCESS(rv, rv);
472 :
473 : char buffer[4096];
474 :
475 : bool more;
476 0 : while (NS_SUCCEEDED(rv = files->HasMore(&more)) && more) {
477 0 : nsCAutoString entry;
478 0 : rv = files->GetNext(entry);
479 0 : NS_ENSURE_SUCCESS(rv, rv);
480 :
481 0 : nsCOMPtr<nsIInputStream> stream;
482 0 : rv = reader->GetInputStream(entry, getter_AddRefs(stream));
483 0 : NS_ENSURE_SUCCESS(rv, rv);
484 :
485 : PRUint32 avail, read;
486 :
487 : PrefParseState ps;
488 0 : PREF_InitParseState(&ps, PREF_ReaderCallback, NULL);
489 0 : while (NS_SUCCEEDED(rv = stream->Available(&avail)) && avail) {
490 0 : rv = stream->Read(buffer, 4096, &read);
491 0 : if (NS_FAILED(rv)) {
492 0 : NS_WARNING("Pref stream read failed");
493 0 : break;
494 : }
495 :
496 0 : rv = PREF_ParseBuf(&ps, buffer, read);
497 0 : if (NS_FAILED(rv)) {
498 0 : NS_WARNING("Pref stream parse failed");
499 0 : break;
500 : }
501 : }
502 0 : PREF_FinalizeParseState(&ps);
503 : }
504 0 : return rv;
505 : }
506 :
507 : void
508 0 : Preferences::SetPreference(const PrefTuple *aPref)
509 : {
510 0 : pref_SetPrefTuple(*aPref, true);
511 0 : }
512 :
513 : void
514 0 : Preferences::ClearContentPref(const char *aPref)
515 : {
516 0 : PREF_ClearUserPref(aPref);
517 0 : }
518 :
519 : bool
520 0 : Preferences::MirrorPreference(const char *aPref, PrefTuple *aTuple)
521 : {
522 0 : PrefHashEntry *entry = pref_HashTableLookup(aPref);
523 0 : if (!entry)
524 0 : return false;
525 :
526 0 : pref_GetTupleFromEntry(entry, aTuple);
527 0 : return true;
528 : }
529 :
530 : void
531 0 : Preferences::MirrorPreferences(nsTArray<PrefTuple,
532 : nsTArrayInfallibleAllocator> *aArray)
533 : {
534 0 : aArray->SetCapacity(PL_DHASH_TABLE_SIZE(&gHashTable));
535 0 : PL_DHashTableEnumerate(&gHashTable, pref_MirrorPrefs, aArray);
536 0 : }
537 :
538 : NS_IMETHODIMP
539 2939 : Preferences::GetBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
540 : {
541 : nsresult rv;
542 :
543 2939 : if ((nsnull != aPrefRoot) && (*aPrefRoot != '\0')) {
544 : // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
545 2874 : nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, false);
546 2874 : if (!prefBranch)
547 0 : return NS_ERROR_OUT_OF_MEMORY;
548 :
549 2874 : rv = CallQueryInterface(prefBranch, _retval);
550 : } else {
551 : // special case caching the default root
552 65 : rv = CallQueryInterface(sRootBranch, _retval);
553 : }
554 2939 : return rv;
555 : }
556 :
557 : NS_IMETHODIMP
558 2745 : Preferences::GetDefaultBranch(const char *aPrefRoot, nsIPrefBranch **_retval)
559 : {
560 2745 : if (!aPrefRoot || !aPrefRoot[0]) {
561 2732 : return CallQueryInterface(sDefaultRootBranch, _retval);
562 : }
563 :
564 : // TODO: - cache this stuff and allow consumers to share branches (hold weak references I think)
565 13 : nsPrefBranch* prefBranch = new nsPrefBranch(aPrefRoot, true);
566 13 : if (!prefBranch)
567 0 : return NS_ERROR_OUT_OF_MEMORY;
568 :
569 13 : return CallQueryInterface(prefBranch, _retval);
570 : }
571 :
572 :
573 : nsresult
574 1 : Preferences::NotifyServiceObservers(const char *aTopic)
575 : {
576 : nsCOMPtr<nsIObserverService> observerService =
577 2 : mozilla::services::GetObserverService();
578 1 : if (!observerService)
579 0 : return NS_ERROR_FAILURE;
580 :
581 1 : nsISupports *subject = (nsISupports *)((nsIPrefService *)this);
582 1 : observerService->NotifyObservers(subject, aTopic, nsnull);
583 :
584 1 : return NS_OK;
585 : }
586 :
587 : nsresult
588 0 : Preferences::UseDefaultPrefFile()
589 : {
590 : nsresult rv, rv2;
591 0 : nsCOMPtr<nsIFile> aFile;
592 :
593 0 : rv = NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE, getter_AddRefs(aFile));
594 0 : if (NS_SUCCEEDED(rv)) {
595 0 : rv = ReadAndOwnUserPrefFile(aFile);
596 : // Most likely cause of failure here is that the file didn't
597 : // exist, so save a new one. mUserPrefReadFailed will be
598 : // used to catch an error in actually reading the file.
599 0 : if (NS_FAILED(rv)) {
600 0 : rv2 = SavePrefFileInternal(aFile);
601 0 : NS_ASSERTION(NS_SUCCEEDED(rv2), "Failed to save new shared pref file");
602 : }
603 : }
604 :
605 0 : return rv;
606 : }
607 :
608 : nsresult
609 0 : Preferences::UseUserPrefFile()
610 : {
611 0 : nsresult rv = NS_OK;
612 0 : nsCOMPtr<nsIFile> aFile;
613 0 : nsDependentCString prefsDirProp(NS_APP_PREFS_50_DIR);
614 :
615 0 : rv = NS_GetSpecialDirectory(prefsDirProp.get(), getter_AddRefs(aFile));
616 0 : if (NS_SUCCEEDED(rv) && aFile) {
617 0 : rv = aFile->AppendNative(NS_LITERAL_CSTRING("user.js"));
618 0 : if (NS_SUCCEEDED(rv)) {
619 0 : bool exists = false;
620 0 : aFile->Exists(&exists);
621 0 : if (exists) {
622 0 : rv = openPrefFile(aFile);
623 : } else {
624 0 : rv = NS_ERROR_FILE_NOT_FOUND;
625 : }
626 : }
627 : }
628 0 : return rv;
629 : }
630 :
631 : nsresult
632 0 : Preferences::MakeBackupPrefFile(nsIFile *aFile)
633 : {
634 : // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
635 : // "Invalidprefs.js" is removed if it exists, prior to making the copy.
636 0 : nsAutoString newFilename;
637 0 : nsresult rv = aFile->GetLeafName(newFilename);
638 0 : NS_ENSURE_SUCCESS(rv, rv);
639 0 : newFilename.Insert(NS_LITERAL_STRING("Invalid"), 0);
640 0 : nsCOMPtr<nsIFile> newFile;
641 0 : rv = aFile->GetParent(getter_AddRefs(newFile));
642 0 : NS_ENSURE_SUCCESS(rv, rv);
643 0 : rv = newFile->Append(newFilename);
644 0 : NS_ENSURE_SUCCESS(rv, rv);
645 0 : bool exists = false;
646 0 : newFile->Exists(&exists);
647 0 : if (exists) {
648 0 : rv = newFile->Remove(false);
649 0 : NS_ENSURE_SUCCESS(rv, rv);
650 : }
651 0 : rv = aFile->CopyTo(nsnull, newFilename);
652 0 : NS_ENSURE_SUCCESS(rv, rv);
653 0 : return rv;
654 : }
655 :
656 : nsresult
657 4 : Preferences::ReadAndOwnUserPrefFile(nsIFile *aFile)
658 : {
659 4 : NS_ENSURE_ARG(aFile);
660 :
661 4 : if (mCurrentFile == aFile)
662 0 : return NS_OK;
663 4 : mCurrentFile = aFile;
664 :
665 4 : nsresult rv = NS_OK;
666 4 : bool exists = false;
667 4 : mCurrentFile->Exists(&exists);
668 4 : if (exists) {
669 4 : rv = openPrefFile(mCurrentFile);
670 4 : if (NS_FAILED(rv)) {
671 : // Save a backup copy of the current (invalid) prefs file, since all prefs
672 : // from the error line to the end of the file will be lost (bug 361102).
673 : // TODO we should notify the user about it (bug 523725).
674 0 : MakeBackupPrefFile(mCurrentFile);
675 : }
676 : } else {
677 0 : rv = NS_ERROR_FILE_NOT_FOUND;
678 : }
679 :
680 4 : return rv;
681 : }
682 :
683 : nsresult
684 2117 : Preferences::SavePrefFileInternal(nsIFile *aFile)
685 : {
686 2117 : if (nsnull == aFile) {
687 : // the gDirty flag tells us if we should write to mCurrentFile
688 : // we only check this flag when the caller wants to write to the default
689 2115 : if (!gDirty)
690 0 : return NS_OK;
691 :
692 : // It's possible that we never got a prefs file.
693 2115 : nsresult rv = NS_OK;
694 2115 : if (mCurrentFile)
695 1 : rv = WritePrefFile(mCurrentFile);
696 :
697 2115 : return rv;
698 : } else {
699 2 : return WritePrefFile(aFile);
700 : }
701 : }
702 :
703 : nsresult
704 3 : Preferences::WritePrefFile(nsIFile* aFile)
705 : {
706 : const char outHeader[] =
707 : "# Mozilla User Preferences"
708 : NS_LINEBREAK
709 : NS_LINEBREAK
710 : "/* Do not edit this file."
711 : NS_LINEBREAK
712 : " *"
713 : NS_LINEBREAK
714 : " * If you make changes to this file while the application is running,"
715 : NS_LINEBREAK
716 : " * the changes will be overwritten when the application exits."
717 : NS_LINEBREAK
718 : " *"
719 : NS_LINEBREAK
720 : " * To make a manual change to preferences, you can visit the URL about:config"
721 : NS_LINEBREAK
722 : " */"
723 : NS_LINEBREAK
724 3 : NS_LINEBREAK;
725 :
726 6 : nsCOMPtr<nsIOutputStream> outStreamSink;
727 6 : nsCOMPtr<nsIOutputStream> outStream;
728 : PRUint32 writeAmount;
729 : nsresult rv;
730 :
731 3 : if (!gHashTable.ops)
732 0 : return NS_ERROR_NOT_INITIALIZED;
733 :
734 : // execute a "safe" save by saving through a tempfile
735 3 : rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink),
736 : aFile,
737 : -1,
738 3 : 0600);
739 3 : if (NS_FAILED(rv))
740 0 : return rv;
741 3 : rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), outStreamSink, 4096);
742 3 : if (NS_FAILED(rv))
743 0 : return rv;
744 :
745 3 : char** valueArray = (char **)PR_Calloc(sizeof(char *), gHashTable.entryCount);
746 3 : if (!valueArray)
747 0 : return NS_ERROR_OUT_OF_MEMORY;
748 :
749 : pref_saveArgs saveArgs;
750 3 : saveArgs.prefArray = valueArray;
751 3 : saveArgs.saveTypes = SAVE_ALL;
752 :
753 : // get the lines that we're supposed to be writing to the file
754 3 : PL_DHashTableEnumerate(&gHashTable, pref_savePref, &saveArgs);
755 :
756 : /* Sort the preferences to make a readable file on disk */
757 3 : NS_QuickSort(valueArray, gHashTable.entryCount, sizeof(char *), pref_CompareStrings, NULL);
758 :
759 : // write out the file header
760 3 : outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount);
761 :
762 3 : char** walker = valueArray;
763 4868 : for (PRUint32 valueIdx = 0; valueIdx < gHashTable.entryCount; valueIdx++, walker++) {
764 4865 : if (*walker) {
765 15 : outStream->Write(*walker, strlen(*walker), &writeAmount);
766 15 : outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount);
767 15 : NS_Free(*walker);
768 : }
769 : }
770 3 : PR_Free(valueArray);
771 :
772 : // tell the safe output stream to overwrite the real prefs file
773 : // (it'll abort if there were any errors during writing)
774 6 : nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
775 3 : NS_ASSERTION(safeStream, "expected a safe output stream!");
776 3 : if (safeStream) {
777 3 : rv = safeStream->Finish();
778 3 : if (NS_FAILED(rv)) {
779 0 : NS_WARNING("failed to save prefs file! possible dataloss");
780 0 : return rv;
781 : }
782 : }
783 :
784 3 : gDirty = false;
785 3 : return NS_OK;
786 : }
787 :
788 8531 : static nsresult openPrefFile(nsIFile* aFile)
789 : {
790 17062 : nsCOMPtr<nsIInputStream> inStr;
791 :
792 8531 : nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
793 8531 : if (NS_FAILED(rv))
794 0 : return rv;
795 :
796 : PRUint32 fileSize;
797 8531 : rv = inStr->Available(&fileSize);
798 8531 : if (NS_FAILED(rv))
799 0 : return rv;
800 :
801 25593 : nsAutoArrayPtr<char> fileBuffer(new char[fileSize]);
802 8531 : if (fileBuffer == nsnull)
803 0 : return NS_ERROR_OUT_OF_MEMORY;
804 :
805 : PrefParseState ps;
806 8531 : PREF_InitParseState(&ps, PREF_ReaderCallback, NULL);
807 :
808 : // Read is not guaranteed to return a buf the size of fileSize,
809 : // but usually will.
810 8531 : nsresult rv2 = NS_OK;
811 8531 : for (;;) {
812 17062 : PRUint32 amtRead = 0;
813 17062 : rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead);
814 17062 : if (NS_FAILED(rv) || amtRead == 0)
815 : break;
816 8531 : if (!PREF_ParseBuf(&ps, fileBuffer, amtRead))
817 0 : rv2 = NS_ERROR_FILE_CORRUPTED;
818 : }
819 :
820 8531 : PREF_FinalizeParseState(&ps);
821 :
822 8531 : return NS_FAILED(rv) ? rv : rv2;
823 : }
824 :
825 : /*
826 : * some stuff that gets called from Pref_Init()
827 : */
828 :
829 : static int
830 14210 : pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2, void* /*unused*/)
831 : {
832 28420 : nsCAutoString filename1, filename2;
833 14210 : aFile1->GetNativeLeafName(filename1);
834 14210 : aFile2->GetNativeLeafName(filename2);
835 :
836 14210 : return Compare(filename2, filename1);
837 : }
838 :
839 : /**
840 : * Load default pref files from a directory. The files in the
841 : * directory are sorted reverse-alphabetically; a set of "special file
842 : * names" may be specified which are loaded after all the others.
843 : */
844 : static nsresult
845 2811 : pref_LoadPrefsInDir(nsIFile* aDir, char const *const *aSpecialFiles, PRUint32 aSpecialFilesCount)
846 : {
847 : nsresult rv, rv2;
848 : bool hasMoreElements;
849 :
850 5622 : nsCOMPtr<nsISimpleEnumerator> dirIterator;
851 :
852 : // this may fail in some normal cases, such as embedders who do not use a GRE
853 2811 : rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
854 2811 : if (NS_FAILED(rv)) {
855 : // If the directory doesn't exist, then we have no reason to complain. We
856 : // loaded everything (and nothing) successfully.
857 1389 : if (rv == NS_ERROR_FILE_NOT_FOUND)
858 0 : rv = NS_OK;
859 1389 : return rv;
860 : }
861 :
862 1422 : rv = dirIterator->HasMoreElements(&hasMoreElements);
863 1422 : NS_ENSURE_SUCCESS(rv, rv);
864 :
865 2844 : nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES);
866 2844 : nsCOMArray<nsIFile> specialFiles(aSpecialFilesCount);
867 2844 : nsCOMPtr<nsIFile> prefFile;
868 :
869 9950 : while (hasMoreElements && NS_SUCCEEDED(rv)) {
870 14212 : nsCAutoString leafName;
871 :
872 7106 : rv = dirIterator->GetNext(getter_AddRefs(prefFile));
873 7106 : if (NS_FAILED(rv)) {
874 : break;
875 : }
876 :
877 7106 : prefFile->GetNativeLeafName(leafName);
878 7106 : NS_ASSERTION(!leafName.IsEmpty(), "Failure in default prefs: directory enumerator returned empty file?");
879 :
880 : // Skip non-js files
881 7106 : if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".js"),
882 7106 : nsCaseInsensitiveCStringComparator())) {
883 7106 : bool shouldParse = true;
884 : // separate out special files
885 14211 : for (PRUint32 i = 0; i < aSpecialFilesCount; ++i) {
886 7105 : if (leafName.Equals(nsDependentCString(aSpecialFiles[i]))) {
887 0 : shouldParse = false;
888 : // special files should be process in order; we put them into
889 : // the array by index; this can make the array sparse
890 0 : specialFiles.ReplaceObjectAt(prefFile, i);
891 : }
892 : }
893 :
894 7106 : if (shouldParse) {
895 7106 : prefFiles.AppendObject(prefFile);
896 : }
897 : }
898 :
899 14212 : rv = dirIterator->HasMoreElements(&hasMoreElements);
900 : }
901 :
902 1422 : if (prefFiles.Count() + specialFiles.Count() == 0) {
903 0 : NS_WARNING("No default pref files found.");
904 0 : if (NS_SUCCEEDED(rv)) {
905 0 : rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
906 : }
907 0 : return rv;
908 : }
909 :
910 1422 : prefFiles.Sort(pref_CompareFileNames, nsnull);
911 :
912 1422 : PRUint32 arrayCount = prefFiles.Count();
913 : PRUint32 i;
914 8528 : for (i = 0; i < arrayCount; ++i) {
915 7106 : rv2 = openPrefFile(prefFiles[i]);
916 7106 : if (NS_FAILED(rv2)) {
917 0 : NS_ERROR("Default pref file not parsed successfully.");
918 0 : rv = rv2;
919 : }
920 : }
921 :
922 1422 : arrayCount = specialFiles.Count();
923 1422 : for (i = 0; i < arrayCount; ++i) {
924 : // this may be a sparse array; test before parsing
925 0 : nsIFile* file = specialFiles[i];
926 0 : if (file) {
927 0 : rv2 = openPrefFile(file);
928 0 : if (NS_FAILED(rv2)) {
929 0 : NS_ERROR("Special default pref file not parsed successfully.");
930 0 : rv = rv2;
931 : }
932 : }
933 : }
934 :
935 1422 : return rv;
936 : }
937 :
938 2843 : static nsresult pref_LoadPrefsInDirList(const char *listId)
939 : {
940 : nsresult rv;
941 5686 : nsCOMPtr<nsIProperties> dirSvc(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
942 2843 : if (NS_FAILED(rv))
943 0 : return rv;
944 :
945 5686 : nsCOMPtr<nsISimpleEnumerator> list;
946 2843 : dirSvc->Get(listId,
947 : NS_GET_IID(nsISimpleEnumerator),
948 2843 : getter_AddRefs(list));
949 2843 : if (!list)
950 1453 : return NS_OK;
951 :
952 : bool hasMore;
953 4170 : while (NS_SUCCEEDED(list->HasMoreElements(&hasMore)) && hasMore) {
954 2780 : nsCOMPtr<nsISupports> elem;
955 1390 : list->GetNext(getter_AddRefs(elem));
956 1390 : if (!elem)
957 0 : continue;
958 :
959 2780 : nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
960 1390 : if (!path)
961 0 : continue;
962 :
963 4170 : nsCAutoString leaf;
964 1390 : path->GetNativeLeafName(leaf);
965 :
966 : // Do we care if a file provided by this process fails to load?
967 1390 : if (Substring(leaf, leaf.Length() - 4).Equals(NS_LITERAL_CSTRING(".xpi")))
968 0 : ReadExtensionPrefs(path);
969 : else
970 1390 : pref_LoadPrefsInDir(path, nsnull, 0);
971 : }
972 1390 : return NS_OK;
973 : }
974 :
975 0 : static nsresult pref_ReadPrefFromJar(nsZipArchive* jarReader, const char *name)
976 : {
977 0 : nsZipItemPtr<char> manifest(jarReader, name, true);
978 0 : NS_ENSURE_TRUE(manifest.Buffer(), NS_ERROR_NOT_AVAILABLE);
979 :
980 : PrefParseState ps;
981 0 : PREF_InitParseState(&ps, PREF_ReaderCallback, NULL);
982 0 : nsresult rv = PREF_ParseBuf(&ps, manifest, manifest.Length());
983 0 : PREF_FinalizeParseState(&ps);
984 :
985 0 : return rv;
986 : }
987 :
988 : //----------------------------------------------------------------------------------------
989 : // Initialize default preference JavaScript buffers from
990 : // appropriate TEXT resources
991 : //----------------------------------------------------------------------------------------
992 1421 : static nsresult pref_InitInitialObjects()
993 : {
994 : nsresult rv;
995 :
996 : // In omni.jar case, we load the following prefs:
997 : // - jar:$gre/omni.jar!/greprefs.js
998 : // - jar:$gre/omni.jar!/defaults/pref/*.js
999 : // In non omni.jar case, we load:
1000 : // - $gre/greprefs.js
1001 : //
1002 : // In both cases, we also load:
1003 : // - $gre/defaults/pref/*.js
1004 : // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
1005 : // on $app == $gre case ; we load all files instead of channel-prefs.js only
1006 : // to have the same behaviour as $app != $gre, where this is required as
1007 : // a supported location for GRE preferences.
1008 : //
1009 : // When $app != $gre, we additionally load, in omni.jar case:
1010 : // - jar:$app/omni.jar!/defaults/preferences/*.js
1011 : // - $app/defaults/preferences/*.js
1012 : // and in non omni.jar case:
1013 : // - $app/defaults/preferences/*.js
1014 :
1015 : nsZipFind *findPtr;
1016 2842 : nsAutoPtr<nsZipFind> find;
1017 2842 : nsTArray<nsCString> prefEntries;
1018 : const char *entryName;
1019 : PRUint16 entryNameLen;
1020 :
1021 2842 : nsRefPtr<nsZipArchive> jarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::GRE);
1022 1421 : if (jarReader) {
1023 : // Load jar:$gre/omni.jar!/greprefs.js
1024 0 : rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
1025 0 : NS_ENSURE_SUCCESS(rv, rv);
1026 :
1027 : // Load jar:$gre/omni.jar!/defaults/pref/*.js
1028 0 : rv = jarReader->FindInit("defaults/pref/*.js$", &findPtr);
1029 0 : NS_ENSURE_SUCCESS(rv, rv);
1030 :
1031 0 : find = findPtr;
1032 0 : while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
1033 0 : prefEntries.AppendElement(Substring(entryName, entryNameLen));
1034 : }
1035 :
1036 0 : prefEntries.Sort();
1037 0 : for (PRUint32 i = prefEntries.Length(); i--; ) {
1038 0 : rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
1039 0 : if (NS_FAILED(rv))
1040 0 : NS_WARNING("Error parsing preferences.");
1041 : }
1042 : } else {
1043 : // Load $gre/greprefs.js
1044 2842 : nsCOMPtr<nsIFile> greprefsFile;
1045 1421 : rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greprefsFile));
1046 1421 : NS_ENSURE_SUCCESS(rv, rv);
1047 :
1048 1421 : rv = greprefsFile->AppendNative(NS_LITERAL_CSTRING("greprefs.js"));
1049 1421 : NS_ENSURE_SUCCESS(rv, rv);
1050 :
1051 1421 : rv = openPrefFile(greprefsFile);
1052 1421 : if (NS_FAILED(rv))
1053 0 : NS_WARNING("Error parsing GRE default preferences. Is this an old-style embedding app?");
1054 : }
1055 :
1056 : // Load $gre/defaults/pref/*.js
1057 2842 : nsCOMPtr<nsIFile> defaultPrefDir;
1058 :
1059 1421 : rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR, getter_AddRefs(defaultPrefDir));
1060 1421 : NS_ENSURE_SUCCESS(rv, rv);
1061 :
1062 : /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */
1063 : static const char* specialFiles[] = {
1064 : #if defined(XP_MACOSX)
1065 : "macprefs.js"
1066 : #elif defined(XP_WIN)
1067 : "winpref.js"
1068 : #elif defined(XP_UNIX)
1069 : "unix.js"
1070 : #if defined(VMS)
1071 : , "openvms.js"
1072 : #elif defined(_AIX)
1073 : , "aix.js"
1074 : #endif
1075 : #elif defined(XP_OS2)
1076 : "os2pref.js"
1077 : #elif defined(XP_BEOS)
1078 : "beos.js"
1079 : #endif
1080 : };
1081 :
1082 1421 : rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, ArrayLength(specialFiles));
1083 1421 : if (NS_FAILED(rv))
1084 0 : NS_WARNING("Error parsing application default preferences.");
1085 :
1086 : // Load jar:$app/omni.jar!/defaults/preferences/*.js
1087 2842 : nsRefPtr<nsZipArchive> appJarReader = mozilla::Omnijar::GetReader(mozilla::Omnijar::APP);
1088 1421 : if (appJarReader) {
1089 0 : rv = appJarReader->FindInit("defaults/preferences/*.js$", &findPtr);
1090 0 : NS_ENSURE_SUCCESS(rv, rv);
1091 0 : find = findPtr;
1092 0 : prefEntries.Clear();
1093 0 : while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))) {
1094 0 : prefEntries.AppendElement(Substring(entryName, entryNameLen));
1095 : }
1096 0 : prefEntries.Sort();
1097 0 : for (PRUint32 i = prefEntries.Length(); i--; ) {
1098 0 : rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
1099 0 : if (NS_FAILED(rv))
1100 0 : NS_WARNING("Error parsing preferences.");
1101 : }
1102 : }
1103 :
1104 1421 : rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
1105 1421 : NS_ENSURE_SUCCESS(rv, rv);
1106 :
1107 : NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID,
1108 1421 : nsnull, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID);
1109 :
1110 : nsCOMPtr<nsIObserverService> observerService =
1111 2842 : mozilla::services::GetObserverService();
1112 1421 : if (!observerService)
1113 0 : return NS_ERROR_FAILURE;
1114 :
1115 1421 : observerService->NotifyObservers(nsnull, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nsnull);
1116 :
1117 1421 : return pref_LoadPrefsInDirList(NS_EXT_PREFS_DEFAULTS_DIR_LIST);
1118 : }
1119 :
1120 :
1121 : /******************************************************************************
1122 : *
1123 : * static utilities
1124 : *
1125 : ******************************************************************************/
1126 :
1127 : // static
1128 : nsresult
1129 33717 : Preferences::GetBool(const char* aPref, bool* aResult)
1130 : {
1131 33717 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1132 33717 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1133 33717 : return PREF_GetBoolPref(aPref, aResult, false);
1134 : }
1135 :
1136 : // static
1137 : nsresult
1138 36949 : Preferences::GetInt(const char* aPref, PRInt32* aResult)
1139 : {
1140 36949 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1141 36949 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1142 36949 : return PREF_GetIntPref(aPref, aResult, false);
1143 : }
1144 :
1145 : // static
1146 : nsAdoptingCString
1147 261 : Preferences::GetCString(const char* aPref)
1148 : {
1149 261 : nsAdoptingCString result;
1150 261 : PREF_CopyCharPref(aPref, getter_Copies(result), false);
1151 : return result;
1152 : }
1153 :
1154 : // static
1155 : nsAdoptingString
1156 1405 : Preferences::GetString(const char* aPref)
1157 : {
1158 1405 : nsAdoptingString result;
1159 1405 : GetString(aPref, &result);
1160 : return result;
1161 : }
1162 :
1163 : // static
1164 : nsresult
1165 0 : Preferences::GetCString(const char* aPref, nsACString* aResult)
1166 : {
1167 0 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1168 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1169 0 : nsCAutoString result;
1170 0 : nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
1171 0 : if (NS_SUCCEEDED(rv)) {
1172 0 : *aResult = result;
1173 : }
1174 0 : return rv;
1175 : }
1176 :
1177 : // static
1178 : nsresult
1179 1647 : Preferences::GetString(const char* aPref, nsAString* aResult)
1180 : {
1181 1647 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1182 1647 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1183 3294 : nsCAutoString result;
1184 1647 : nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), false);
1185 1647 : if (NS_SUCCEEDED(rv)) {
1186 1647 : CopyUTF8toUTF16(result, *aResult);
1187 : }
1188 1647 : return rv;
1189 : }
1190 :
1191 : // static
1192 : nsAdoptingCString
1193 0 : Preferences::GetLocalizedCString(const char* aPref)
1194 : {
1195 0 : nsAdoptingCString result;
1196 0 : GetLocalizedCString(aPref, &result);
1197 : return result;
1198 : }
1199 :
1200 : // static
1201 : nsAdoptingString
1202 0 : Preferences::GetLocalizedString(const char* aPref)
1203 : {
1204 0 : nsAdoptingString result;
1205 0 : GetLocalizedString(aPref, &result);
1206 : return result;
1207 : }
1208 :
1209 : // static
1210 : nsresult
1211 0 : Preferences::GetLocalizedCString(const char* aPref, nsACString* aResult)
1212 : {
1213 0 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1214 0 : nsAutoString result;
1215 0 : nsresult rv = GetLocalizedString(aPref, &result);
1216 0 : if (NS_SUCCEEDED(rv)) {
1217 0 : CopyUTF16toUTF8(result, *aResult);
1218 : }
1219 0 : return rv;
1220 : }
1221 :
1222 : // static
1223 : nsresult
1224 0 : Preferences::GetLocalizedString(const char* aPref, nsAString* aResult)
1225 : {
1226 0 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1227 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1228 0 : nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
1229 : nsresult rv = sRootBranch->GetComplexValue(aPref,
1230 : NS_GET_IID(nsIPrefLocalizedString),
1231 0 : getter_AddRefs(prefLocalString));
1232 0 : if (NS_SUCCEEDED(rv)) {
1233 0 : NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
1234 0 : prefLocalString->GetData(getter_Copies(*aResult));
1235 : }
1236 0 : return rv;
1237 : }
1238 :
1239 : // static
1240 : nsresult
1241 0 : Preferences::GetComplex(const char* aPref, const nsIID &aType, void** aResult)
1242 : {
1243 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1244 0 : return sRootBranch->GetComplexValue(aPref, aType, aResult);
1245 : }
1246 :
1247 : // static
1248 : nsresult
1249 0 : Preferences::SetCString(const char* aPref, const char* aValue)
1250 : {
1251 0 : NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, NS_ERROR_NOT_AVAILABLE);
1252 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1253 0 : return PREF_SetCharPref(aPref, aValue, false);
1254 : }
1255 :
1256 : // static
1257 : nsresult
1258 0 : Preferences::SetCString(const char* aPref, const nsACString &aValue)
1259 : {
1260 0 : NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, NS_ERROR_NOT_AVAILABLE);
1261 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1262 0 : return PREF_SetCharPref(aPref, PromiseFlatCString(aValue).get(), false);
1263 : }
1264 :
1265 : // static
1266 : nsresult
1267 0 : Preferences::SetString(const char* aPref, const PRUnichar* aValue)
1268 : {
1269 0 : NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, NS_ERROR_NOT_AVAILABLE);
1270 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1271 0 : return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
1272 : }
1273 :
1274 : // static
1275 : nsresult
1276 0 : Preferences::SetString(const char* aPref, const nsAString &aValue)
1277 : {
1278 0 : NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, NS_ERROR_NOT_AVAILABLE);
1279 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1280 0 : return PREF_SetCharPref(aPref, NS_ConvertUTF16toUTF8(aValue).get(), false);
1281 : }
1282 :
1283 : // static
1284 : nsresult
1285 0 : Preferences::SetBool(const char* aPref, bool aValue)
1286 : {
1287 0 : NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, NS_ERROR_NOT_AVAILABLE);
1288 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1289 0 : return PREF_SetBoolPref(aPref, aValue, false);
1290 : }
1291 :
1292 : // static
1293 : nsresult
1294 16 : Preferences::SetInt(const char* aPref, PRInt32 aValue)
1295 : {
1296 16 : NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, NS_ERROR_NOT_AVAILABLE);
1297 16 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1298 16 : return PREF_SetIntPref(aPref, aValue, false);
1299 : }
1300 :
1301 : // static
1302 : nsresult
1303 0 : Preferences::SetComplex(const char* aPref, const nsIID &aType,
1304 : nsISupports* aValue)
1305 : {
1306 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1307 0 : return sRootBranch->SetComplexValue(aPref, aType, aValue);
1308 : }
1309 :
1310 : // static
1311 : nsresult
1312 113 : Preferences::ClearUser(const char* aPref)
1313 : {
1314 113 : NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, NS_ERROR_NOT_AVAILABLE);
1315 113 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1316 113 : return PREF_ClearUserPref(aPref);
1317 : }
1318 :
1319 : // static
1320 : bool
1321 288 : Preferences::HasUserValue(const char* aPref)
1322 : {
1323 288 : NS_ENSURE_TRUE(InitStaticMembers(), false);
1324 288 : return PREF_HasUserPref(aPref);
1325 : }
1326 :
1327 : // static
1328 : nsresult
1329 56944 : Preferences::AddStrongObserver(nsIObserver* aObserver,
1330 : const char* aPref)
1331 : {
1332 56944 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1333 56944 : return sRootBranch->AddObserver(aPref, aObserver, false);
1334 : }
1335 :
1336 : // static
1337 : nsresult
1338 11474 : Preferences::AddWeakObserver(nsIObserver* aObserver,
1339 : const char* aPref)
1340 : {
1341 11474 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1342 11474 : return sRootBranch->AddObserver(aPref, aObserver, true);
1343 : }
1344 :
1345 : // static
1346 : nsresult
1347 54127 : Preferences::RemoveObserver(nsIObserver* aObserver,
1348 : const char* aPref)
1349 : {
1350 54127 : if (!sPreferences && sShutdown) {
1351 3 : return NS_OK; // Observers have been released automatically.
1352 : }
1353 54124 : NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1354 54124 : return sRootBranch->RemoveObserver(aPref, aObserver);
1355 : }
1356 :
1357 : // static
1358 : nsresult
1359 2811 : Preferences::AddStrongObservers(nsIObserver* aObserver,
1360 : const char** aPrefs)
1361 : {
1362 11244 : for (PRUint32 i = 0; aPrefs[i]; i++) {
1363 8433 : nsresult rv = AddStrongObserver(aObserver, aPrefs[i]);
1364 8433 : NS_ENSURE_SUCCESS(rv, rv);
1365 : }
1366 2811 : return NS_OK;
1367 : }
1368 :
1369 : // static
1370 : nsresult
1371 1666 : Preferences::AddWeakObservers(nsIObserver* aObserver,
1372 : const char** aPrefs)
1373 : {
1374 13046 : for (PRUint32 i = 0; aPrefs[i]; i++) {
1375 11380 : nsresult rv = AddWeakObserver(aObserver, aPrefs[i]);
1376 11380 : NS_ENSURE_SUCCESS(rv, rv);
1377 : }
1378 1666 : return NS_OK;
1379 : }
1380 :
1381 : // static
1382 : nsresult
1383 4213 : Preferences::RemoveObservers(nsIObserver* aObserver,
1384 : const char** aPrefs)
1385 : {
1386 4213 : if (!sPreferences && sShutdown) {
1387 2810 : return NS_OK; // Observers have been released automatically.
1388 : }
1389 1403 : NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1390 :
1391 7015 : for (PRUint32 i = 0; aPrefs[i]; i++) {
1392 5612 : nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
1393 5612 : NS_ENSURE_SUCCESS(rv, rv);
1394 : }
1395 1403 : return NS_OK;
1396 : }
1397 :
1398 : // static
1399 : nsresult
1400 48511 : Preferences::RegisterCallback(PrefChangedFunc aCallback,
1401 : const char* aPref,
1402 : void* aClosure)
1403 : {
1404 48511 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1405 :
1406 97022 : ValueObserverHashKey hashKey(aPref, aCallback);
1407 97022 : nsRefPtr<ValueObserver> observer;
1408 48511 : gObserverTable->Get(&hashKey, getter_AddRefs(observer));
1409 48511 : if (observer) {
1410 0 : observer->AppendClosure(aClosure);
1411 0 : return NS_OK;
1412 : }
1413 :
1414 48511 : observer = new ValueObserver(aPref, aCallback);
1415 48511 : observer->AppendClosure(aClosure);
1416 48511 : nsresult rv = AddStrongObserver(observer, aPref);
1417 48511 : NS_ENSURE_SUCCESS(rv, rv);
1418 48511 : return gObserverTable->Put(observer, observer) ? NS_OK :
1419 48511 : NS_ERROR_OUT_OF_MEMORY;
1420 : }
1421 :
1422 : // static
1423 : nsresult
1424 2806 : Preferences::UnregisterCallback(PrefChangedFunc aCallback,
1425 : const char* aPref,
1426 : void* aClosure)
1427 : {
1428 2806 : if (!sPreferences && sShutdown) {
1429 0 : return NS_OK; // Observers have been released automatically.
1430 : }
1431 2806 : NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
1432 :
1433 5612 : ValueObserverHashKey hashKey(aPref, aCallback);
1434 5612 : nsRefPtr<ValueObserver> observer;
1435 2806 : gObserverTable->Get(&hashKey, getter_AddRefs(observer));
1436 2806 : if (!observer) {
1437 1403 : return NS_OK;
1438 : }
1439 :
1440 1403 : observer->RemoveClosure(aClosure);
1441 1403 : if (observer->HasNoClosures()) {
1442 : // Delete the callback since its list of closures is empty.
1443 1403 : gObserverTable->Remove(observer);
1444 : }
1445 1403 : return NS_OK;
1446 : }
1447 :
1448 12 : static int BoolVarChanged(const char* aPref, void* aClosure)
1449 : {
1450 12 : CacheData* cache = static_cast<CacheData*>(aClosure);
1451 : *((bool*)cache->cacheLocation) =
1452 12 : Preferences::GetBool(aPref, cache->defaultValueBool);
1453 12 : return 0;
1454 : }
1455 :
1456 : // static
1457 : nsresult
1458 19805 : Preferences::AddBoolVarCache(bool* aCache,
1459 : const char* aPref,
1460 : bool aDefault)
1461 : {
1462 19805 : NS_ASSERTION(aCache, "aCache must not be NULL");
1463 19805 : *aCache = GetBool(aPref, aDefault);
1464 19805 : CacheData* data = new CacheData();
1465 19805 : data->cacheLocation = aCache;
1466 19805 : data->defaultValueBool = aDefault;
1467 19805 : gCacheData->AppendElement(data);
1468 19805 : return RegisterCallback(BoolVarChanged, aPref, data);
1469 : }
1470 :
1471 3 : static int IntVarChanged(const char* aPref, void* aClosure)
1472 : {
1473 3 : CacheData* cache = static_cast<CacheData*>(aClosure);
1474 : *((PRInt32*)cache->cacheLocation) =
1475 3 : Preferences::GetInt(aPref, cache->defaultValueInt);
1476 3 : return 0;
1477 : }
1478 :
1479 : // static
1480 : nsresult
1481 18307 : Preferences::AddIntVarCache(PRInt32* aCache,
1482 : const char* aPref,
1483 : PRInt32 aDefault)
1484 : {
1485 18307 : NS_ASSERTION(aCache, "aCache must not be NULL");
1486 18307 : *aCache = Preferences::GetInt(aPref, aDefault);
1487 18307 : CacheData* data = new CacheData();
1488 18307 : data->cacheLocation = aCache;
1489 18307 : data->defaultValueInt = aDefault;
1490 18307 : gCacheData->AppendElement(data);
1491 18307 : return RegisterCallback(IntVarChanged, aPref, data);
1492 : }
1493 :
1494 5 : static int UintVarChanged(const char* aPref, void* aClosure)
1495 : {
1496 5 : CacheData* cache = static_cast<CacheData*>(aClosure);
1497 : *((PRUint32*)cache->cacheLocation) =
1498 5 : Preferences::GetUint(aPref, cache->defaultValueUint);
1499 5 : return 0;
1500 : }
1501 :
1502 : // static
1503 : nsresult
1504 7035 : Preferences::AddUintVarCache(PRUint32* aCache,
1505 : const char* aPref,
1506 : PRUint32 aDefault)
1507 : {
1508 7035 : NS_ASSERTION(aCache, "aCache must not be NULL");
1509 7035 : *aCache = Preferences::GetUint(aPref, aDefault);
1510 7035 : CacheData* data = new CacheData();
1511 7035 : data->cacheLocation = aCache;
1512 7035 : data->defaultValueUint = aDefault;
1513 7035 : gCacheData->AppendElement(data);
1514 7035 : return RegisterCallback(UintVarChanged, aPref, data);
1515 : }
1516 :
1517 : // static
1518 : nsresult
1519 0 : Preferences::GetDefaultBool(const char* aPref, bool* aResult)
1520 : {
1521 0 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1522 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1523 0 : return PREF_GetBoolPref(aPref, aResult, true);
1524 : }
1525 :
1526 : // static
1527 : nsresult
1528 1404 : Preferences::GetDefaultInt(const char* aPref, PRInt32* aResult)
1529 : {
1530 1404 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1531 1404 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1532 1404 : return PREF_GetIntPref(aPref, aResult, true);
1533 : }
1534 :
1535 : // static
1536 : nsresult
1537 0 : Preferences::GetDefaultCString(const char* aPref, nsACString* aResult)
1538 : {
1539 0 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1540 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1541 0 : nsCAutoString result;
1542 0 : nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
1543 0 : if (NS_SUCCEEDED(rv)) {
1544 0 : *aResult = result;
1545 : }
1546 0 : return rv;
1547 : }
1548 :
1549 : // static
1550 : nsresult
1551 0 : Preferences::GetDefaultString(const char* aPref, nsAString* aResult)
1552 : {
1553 0 : NS_PRECONDITION(aResult, "aResult must not be NULL");
1554 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1555 0 : nsCAutoString result;
1556 0 : nsresult rv = PREF_CopyCharPref(aPref, getter_Copies(result), true);
1557 0 : if (NS_SUCCEEDED(rv)) {
1558 0 : CopyUTF8toUTF16(result, *aResult);
1559 : }
1560 0 : return rv;
1561 : }
1562 :
1563 : // static
1564 : nsresult
1565 0 : Preferences::GetDefaultLocalizedCString(const char* aPref,
1566 : nsACString* aResult)
1567 : {
1568 0 : nsAutoString result;
1569 0 : nsresult rv = GetDefaultLocalizedString(aPref, &result);
1570 0 : if (NS_SUCCEEDED(rv)) {
1571 0 : CopyUTF16toUTF8(result, *aResult);
1572 : }
1573 0 : return rv;
1574 : }
1575 :
1576 : // static
1577 : nsresult
1578 0 : Preferences::GetDefaultLocalizedString(const char* aPref,
1579 : nsAString* aResult)
1580 : {
1581 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1582 0 : nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
1583 : nsresult rv =
1584 : sDefaultRootBranch->GetComplexValue(aPref,
1585 : NS_GET_IID(nsIPrefLocalizedString),
1586 0 : getter_AddRefs(prefLocalString));
1587 0 : if (NS_SUCCEEDED(rv)) {
1588 0 : NS_ASSERTION(prefLocalString, "Succeeded but the result is NULL");
1589 0 : prefLocalString->GetData(getter_Copies(*aResult));
1590 : }
1591 0 : return rv;
1592 : }
1593 :
1594 : // static
1595 : nsAdoptingString
1596 0 : Preferences::GetDefaultString(const char* aPref)
1597 : {
1598 0 : nsAdoptingString result;
1599 0 : GetDefaultString(aPref, &result);
1600 : return result;
1601 : }
1602 :
1603 : // static
1604 : nsAdoptingCString
1605 0 : Preferences::GetDefaultCString(const char* aPref)
1606 : {
1607 0 : nsAdoptingCString result;
1608 0 : PREF_CopyCharPref(aPref, getter_Copies(result), true);
1609 : return result;
1610 : }
1611 :
1612 : // static
1613 : nsAdoptingString
1614 0 : Preferences::GetDefaultLocalizedString(const char* aPref)
1615 : {
1616 0 : nsAdoptingString result;
1617 0 : GetDefaultLocalizedString(aPref, &result);
1618 : return result;
1619 : }
1620 :
1621 : // static
1622 : nsAdoptingCString
1623 0 : Preferences::GetDefaultLocalizedCString(const char* aPref)
1624 : {
1625 0 : nsAdoptingCString result;
1626 0 : GetDefaultLocalizedCString(aPref, &result);
1627 : return result;
1628 : }
1629 :
1630 : // static
1631 : nsresult
1632 0 : Preferences::GetDefaultComplex(const char* aPref, const nsIID &aType,
1633 : void** aResult)
1634 : {
1635 0 : NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
1636 0 : return sDefaultRootBranch->GetComplexValue(aPref, aType, aResult);
1637 : }
1638 :
1639 : } // namespace mozilla
|