b=450088 backing out (new reftest failed)
[wine-gecko.git] / modules / libpref / src / nsPrefBranch.cpp
bloba3618bc1f6119970983540f804ed1b82017613ed
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
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/
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.
15 * The Original Code is Mozilla Communicator client code.
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.
22 * Contributor(s):
23 * Alec Flett <alecf@netscape.com>
24 * Brian Nesse <bnesse@netscape.com>
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.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsPrefBranch.h"
41 #include "nsILocalFile.h"
42 #include "nsIObserverService.h"
43 #include "nsXPCOM.h"
44 #include "nsISupportsPrimitives.h"
45 #include "nsIDirectoryService.h"
46 #include "nsString.h"
47 #include "nsReadableUtils.h"
48 #include "nsXPIDLString.h"
49 #include "nsIStringBundle.h"
50 #include "prefapi.h"
51 #include "prmem.h"
52 #include "pldhash.h"
53 #include "nsPrefsCID.h"
55 #ifndef MOZ_NO_XPCOM_OBSOLETE
56 #include "nsIFileSpec.h" // this should be removed eventually
57 #endif
59 #include "plstr.h"
60 #include "nsCRT.h"
62 #include "prefapi_private_data.h"
64 // Definitions
65 struct EnumerateData {
66 const char *parent;
67 nsVoidArray *pref_list;
70 struct PrefCallbackData {
71 nsPrefBranch *pBranch;
72 nsIObserver *pObserver;
73 nsIWeakReference *pWeakRef;
77 // Prototypes
78 static PLDHashOperator
79 pref_enumChild(PLDHashTable *table, PLDHashEntryHdr *heh,
80 PRUint32 i, void *arg);
81 static nsresult
82 NotifyObserver(const char *newpref, void *data);
85 * Constructor/Destructor
88 nsPrefBranch::nsPrefBranch(const char *aPrefRoot, PRBool aDefaultBranch)
89 : mObservers(nsnull)
91 mPrefRoot = aPrefRoot;
92 mPrefRootLength = mPrefRoot.Length();
93 mIsDefault = aDefaultBranch;
95 nsCOMPtr<nsIObserverService> observerService =
96 do_GetService("@mozilla.org/observer-service;1");
97 if (observerService) {
98 ++mRefCnt; // Our refcnt must be > 0 when we call this, or we'll get deleted!
99 // add weak so we don't have to clean up at shutdown
100 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
101 --mRefCnt;
105 nsPrefBranch::~nsPrefBranch()
107 freeObserverList();
112 * nsISupports Implementation
115 NS_IMPL_THREADSAFE_ADDREF(nsPrefBranch)
116 NS_IMPL_THREADSAFE_RELEASE(nsPrefBranch)
118 NS_INTERFACE_MAP_BEGIN(nsPrefBranch)
119 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefBranch)
120 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
121 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranch2, !mIsDefault)
122 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranchInternal, !mIsDefault)
123 NS_INTERFACE_MAP_ENTRY(nsISecurityPref)
124 NS_INTERFACE_MAP_ENTRY(nsIObserver)
125 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
126 NS_INTERFACE_MAP_END
130 * nsIPrefBranch Implementation
133 NS_IMETHODIMP nsPrefBranch::GetRoot(char * *aRoot)
135 NS_ENSURE_ARG_POINTER(aRoot);
137 mPrefRoot.Truncate(mPrefRootLength);
138 *aRoot = ToNewCString(mPrefRoot);
139 return NS_OK;
142 NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, PRInt32 *_retval)
144 const char *pref;
145 nsresult rv;
147 rv = getValidatedPrefName(aPrefName, &pref);
148 if (NS_FAILED(rv))
149 return rv;
151 *_retval = PREF_GetPrefType(pref);
152 return NS_OK;
155 NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, PRBool *_retval)
157 const char *pref;
158 nsresult rv;
160 rv = getValidatedPrefName(aPrefName, &pref);
161 if (NS_SUCCEEDED(rv)) {
162 rv = PREF_GetBoolPref(pref, _retval, mIsDefault);
164 return rv;
167 NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, PRInt32 aValue)
169 const char *pref;
170 nsresult rv;
172 rv = getValidatedPrefName(aPrefName, &pref);
173 if (NS_SUCCEEDED(rv)) {
174 rv = PREF_SetBoolPref(pref, aValue, mIsDefault);
176 return rv;
179 NS_IMETHODIMP nsPrefBranch::GetCharPref(const char *aPrefName, char **_retval)
181 const char *pref;
182 nsresult rv;
184 rv = getValidatedPrefName(aPrefName, &pref);
185 if (NS_SUCCEEDED(rv)) {
186 rv = PREF_CopyCharPref(pref, _retval, mIsDefault);
188 return rv;
191 NS_IMETHODIMP nsPrefBranch::SetCharPref(const char *aPrefName, const char *aValue)
193 const char *pref;
194 nsresult rv;
196 NS_ENSURE_ARG_POINTER(aValue);
197 rv = getValidatedPrefName(aPrefName, &pref);
198 if (NS_SUCCEEDED(rv)) {
199 rv = PREF_SetCharPref(pref, aValue, mIsDefault);
201 return rv;
204 NS_IMETHODIMP nsPrefBranch::GetIntPref(const char *aPrefName, PRInt32 *_retval)
206 const char *pref;
207 nsresult rv;
209 rv = getValidatedPrefName(aPrefName, &pref);
210 if (NS_SUCCEEDED(rv)) {
211 rv = PREF_GetIntPref(pref, _retval, mIsDefault);
213 return rv;
216 NS_IMETHODIMP nsPrefBranch::SetIntPref(const char *aPrefName, PRInt32 aValue)
218 const char *pref;
219 nsresult rv;
221 rv = getValidatedPrefName(aPrefName, &pref);
222 if (NS_SUCCEEDED(rv)) {
223 rv = PREF_SetIntPref(pref, aValue, mIsDefault);
225 return rv;
228 NS_IMETHODIMP nsPrefBranch::GetComplexValue(const char *aPrefName, const nsIID & aType, void * *_retval)
230 nsresult rv;
231 nsXPIDLCString utf8String;
233 // we have to do this one first because it's different than all the rest
234 if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
235 nsCOMPtr<nsIPrefLocalizedString> theString(do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv));
237 if (NS_SUCCEEDED(rv)) {
238 const char *pref;
239 PRBool bNeedDefault = PR_FALSE;
241 rv = getValidatedPrefName(aPrefName, &pref);
242 if (NS_FAILED(rv))
243 return rv;
245 if (mIsDefault) {
246 bNeedDefault = PR_TRUE;
247 } else {
248 // if there is no user (or locked) value
249 if (!PREF_HasUserPref(pref) && !PREF_PrefIsLocked(pref)) {
250 bNeedDefault = PR_TRUE;
254 // if we need to fetch the default value, do that instead, otherwise use the
255 // value we pulled in at the top of this function
256 if (bNeedDefault) {
257 nsXPIDLString utf16String;
258 rv = GetDefaultFromPropertiesFile(pref, getter_Copies(utf16String));
259 if (NS_SUCCEEDED(rv)) {
260 rv = theString->SetData(utf16String.get());
262 } else {
263 rv = GetCharPref(aPrefName, getter_Copies(utf8String));
264 if (NS_SUCCEEDED(rv)) {
265 rv = theString->SetData(NS_ConvertUTF8toUTF16(utf8String).get());
268 if (NS_SUCCEEDED(rv)) {
269 nsIPrefLocalizedString *temp = theString;
271 NS_ADDREF(temp);
272 *_retval = (void *)temp;
276 return rv;
279 // if we can't get the pref, there's no point in being here
280 rv = GetCharPref(aPrefName, getter_Copies(utf8String));
281 if (NS_FAILED(rv)) {
282 return rv;
285 if (aType.Equals(NS_GET_IID(nsILocalFile))) {
286 nsCOMPtr<nsILocalFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
288 if (NS_SUCCEEDED(rv)) {
289 rv = file->SetPersistentDescriptor(utf8String);
290 if (NS_SUCCEEDED(rv)) {
291 nsILocalFile *temp = file;
293 NS_ADDREF(temp);
294 *_retval = (void *)temp;
295 return NS_OK;
298 return rv;
301 if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
302 nsACString::const_iterator keyBegin, strEnd;
303 utf8String.BeginReading(keyBegin);
304 utf8String.EndReading(strEnd);
306 // The pref has the format: [fromKey]a/b/c
307 if (*keyBegin++ != '[')
308 return NS_ERROR_FAILURE;
309 nsACString::const_iterator keyEnd(keyBegin);
310 if (!FindCharInReadable(']', keyEnd, strEnd))
311 return NS_ERROR_FAILURE;
312 nsCAutoString key(Substring(keyBegin, keyEnd));
314 nsCOMPtr<nsILocalFile> fromFile;
315 nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
316 if (NS_FAILED(rv))
317 return rv;
318 rv = directoryService->Get(key.get(), NS_GET_IID(nsILocalFile), getter_AddRefs(fromFile));
319 if (NS_FAILED(rv))
320 return rv;
322 nsCOMPtr<nsILocalFile> theFile;
323 rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(theFile));
324 if (NS_FAILED(rv))
325 return rv;
326 rv = theFile->SetRelativeDescriptor(fromFile, Substring(++keyEnd, strEnd));
327 if (NS_FAILED(rv))
328 return rv;
329 nsCOMPtr<nsIRelativeFilePref> relativePref;
330 rv = NS_NewRelativeFilePref(theFile, key, getter_AddRefs(relativePref));
331 if (NS_FAILED(rv))
332 return rv;
334 *_retval = relativePref;
335 NS_ADDREF(static_cast<nsIRelativeFilePref*>(*_retval));
336 return NS_OK;
339 if (aType.Equals(NS_GET_IID(nsISupportsString))) {
340 nsCOMPtr<nsISupportsString> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
342 if (NS_SUCCEEDED(rv)) {
343 rv = theString->SetData(NS_ConvertUTF8toUTF16(utf8String));
344 if (NS_SUCCEEDED(rv)) {
345 nsISupportsString *temp = theString;
347 NS_ADDREF(temp);
348 *_retval = (void *)temp;
349 return NS_OK;
352 return rv;
355 // This is deprecated and you should not be using it
356 #ifndef MOZ_NO_XPCOM_OBSOLETE
357 if (aType.Equals(NS_GET_IID(nsIFileSpec))) {
358 nsCOMPtr<nsIFileSpec> file(do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv));
360 if (NS_SUCCEEDED(rv)) {
361 nsIFileSpec *temp = file;
362 PRBool valid;
364 file->SetPersistentDescriptorString(utf8String); // only returns NS_OK
365 file->IsValid(&valid);
366 if (!valid) {
367 /* if the string wasn't a valid persistent descriptor, it might be a valid native path */
368 file->SetNativePath(utf8String);
370 NS_ADDREF(temp);
371 *_retval = (void *)temp;
372 return NS_OK;
374 return rv;
376 #endif
378 NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type");
379 return NS_NOINTERFACE;
382 NS_IMETHODIMP nsPrefBranch::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
384 nsresult rv = NS_NOINTERFACE;
386 if (aType.Equals(NS_GET_IID(nsILocalFile))) {
387 nsCOMPtr<nsILocalFile> file = do_QueryInterface(aValue);
388 if (!file)
389 return NS_NOINTERFACE;
390 nsCAutoString descriptorString;
392 rv = file->GetPersistentDescriptor(descriptorString);
393 if (NS_SUCCEEDED(rv)) {
394 rv = SetCharPref(aPrefName, descriptorString.get());
396 return rv;
399 if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
400 nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue);
401 if (!relFilePref)
402 return NS_NOINTERFACE;
404 nsCOMPtr<nsILocalFile> file;
405 relFilePref->GetFile(getter_AddRefs(file));
406 if (!file)
407 return NS_NOINTERFACE;
408 nsCAutoString relativeToKey;
409 (void) relFilePref->GetRelativeToKey(relativeToKey);
411 nsCOMPtr<nsILocalFile> relativeToFile;
412 nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
413 if (NS_FAILED(rv))
414 return rv;
415 rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsILocalFile), getter_AddRefs(relativeToFile));
416 if (NS_FAILED(rv))
417 return rv;
419 nsCAutoString relDescriptor;
420 rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor);
421 if (NS_FAILED(rv))
422 return rv;
424 nsCAutoString descriptorString;
425 descriptorString.Append('[');
426 descriptorString.Append(relativeToKey);
427 descriptorString.Append(']');
428 descriptorString.Append(relDescriptor);
429 return SetCharPref(aPrefName, descriptorString.get());
432 if (aType.Equals(NS_GET_IID(nsISupportsString))) {
433 nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
435 if (theString) {
436 nsAutoString wideString;
438 rv = theString->GetData(wideString);
439 if (NS_SUCCEEDED(rv)) {
440 rv = SetCharPref(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
443 return rv;
446 if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
447 nsCOMPtr<nsIPrefLocalizedString> theString = do_QueryInterface(aValue);
449 if (theString) {
450 nsXPIDLString wideString;
452 rv = theString->GetData(getter_Copies(wideString));
453 if (NS_SUCCEEDED(rv)) {
454 rv = SetCharPref(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
457 return rv;
460 #ifndef MOZ_NO_XPCOM_OBSOLETE
461 // This is deprecated and you should not be using it
462 if (aType.Equals(NS_GET_IID(nsIFileSpec))) {
463 nsCOMPtr<nsIFileSpec> file = do_QueryInterface(aValue);
464 if (!file)
465 return NS_NOINTERFACE;
466 nsXPIDLCString descriptorString;
468 rv = file->GetPersistentDescriptorString(getter_Copies(descriptorString));
469 if (NS_SUCCEEDED(rv)) {
470 rv = SetCharPref(aPrefName, descriptorString);
472 return rv;
474 #endif
476 NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type");
477 return NS_NOINTERFACE;
480 NS_IMETHODIMP nsPrefBranch::ClearUserPref(const char *aPrefName)
482 const char *pref;
483 nsresult rv;
485 rv = getValidatedPrefName(aPrefName, &pref);
486 if (NS_SUCCEEDED(rv)) {
487 rv = PREF_ClearUserPref(pref);
489 return rv;
492 NS_IMETHODIMP nsPrefBranch::PrefHasUserValue(const char *aPrefName, PRBool *_retval)
494 const char *pref;
495 nsresult rv;
497 NS_ENSURE_ARG_POINTER(_retval);
499 rv = getValidatedPrefName(aPrefName, &pref);
500 if (NS_SUCCEEDED(rv)) {
501 *_retval = PREF_HasUserPref(pref);
503 return rv;
506 NS_IMETHODIMP nsPrefBranch::LockPref(const char *aPrefName)
508 const char *pref;
509 nsresult rv;
511 rv = getValidatedPrefName(aPrefName, &pref);
512 if (NS_SUCCEEDED(rv)) {
513 rv = PREF_LockPref(pref, PR_TRUE);
515 return rv;
518 NS_IMETHODIMP nsPrefBranch::PrefIsLocked(const char *aPrefName, PRBool *_retval)
520 const char *pref;
521 nsresult rv;
523 NS_ENSURE_ARG_POINTER(_retval);
525 rv = getValidatedPrefName(aPrefName, &pref);
526 if (NS_SUCCEEDED(rv)) {
527 *_retval = PREF_PrefIsLocked(pref);
529 return rv;
532 NS_IMETHODIMP nsPrefBranch::UnlockPref(const char *aPrefName)
534 const char *pref;
535 nsresult rv;
537 rv = getValidatedPrefName(aPrefName, &pref);
538 if (NS_SUCCEEDED(rv)) {
539 rv = PREF_LockPref(pref, PR_FALSE);
541 return rv;
544 /* void resetBranch (in string startingAt); */
545 NS_IMETHODIMP nsPrefBranch::ResetBranch(const char *aStartingAt)
547 return NS_ERROR_NOT_IMPLEMENTED;
550 NS_IMETHODIMP nsPrefBranch::DeleteBranch(const char *aStartingAt)
552 const char *pref;
553 nsresult rv;
555 rv = getValidatedPrefName(aStartingAt, &pref);
556 if (NS_SUCCEEDED(rv)) {
557 rv = PREF_DeleteBranch(pref);
559 return rv;
562 NS_IMETHODIMP nsPrefBranch::GetChildList(const char *aStartingAt, PRUint32 *aCount, char ***aChildArray)
564 char** outArray;
565 char* theElement;
566 PRInt32 numPrefs;
567 PRInt32 dwIndex;
568 EnumerateData ed;
569 nsAutoVoidArray prefArray;
571 NS_ENSURE_ARG_POINTER(aStartingAt);
572 NS_ENSURE_ARG_POINTER(aCount);
573 NS_ENSURE_ARG_POINTER(aChildArray);
575 if (!gHashTable.ops) {
576 *aChildArray = nsnull;
577 *aCount = 0;
578 return NS_ERROR_NOT_INITIALIZED;
581 // this will contain a list of all the pref name strings
582 // allocate on the stack for speed
584 ed.parent = getPrefName(aStartingAt);
585 ed.pref_list = &prefArray;
586 PL_DHashTableEnumerate(&gHashTable, pref_enumChild, &ed);
588 // now that we've built up the list, run the callback on
589 // all the matching elements
590 numPrefs = prefArray.Count();
592 if (numPrefs) {
593 outArray = (char **)nsMemory::Alloc(numPrefs * sizeof(char *));
594 if (!outArray)
595 return NS_ERROR_OUT_OF_MEMORY;
597 for (dwIndex = 0; dwIndex < numPrefs; ++dwIndex) {
598 // we need to lop off mPrefRoot in case the user is planning to pass this
599 // back to us because if they do we are going to add mPrefRoot again.
600 theElement = ((char *)prefArray.ElementAt(dwIndex)) + mPrefRootLength;
601 outArray[dwIndex] = (char *)nsMemory::Clone(theElement, strlen(theElement) + 1);
603 if (!outArray[dwIndex]) {
604 // we ran out of memory... this is annoying
605 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(dwIndex, outArray);
606 return NS_ERROR_OUT_OF_MEMORY;
609 *aChildArray = outArray;
610 } else {
611 *aChildArray = nsnull;
612 } /* endif */
613 *aCount = numPrefs;
615 return NS_OK;
620 * nsIPrefBranch2 methods
623 NS_IMETHODIMP nsPrefBranch::AddObserver(const char *aDomain, nsIObserver *aObserver, PRBool aHoldWeak)
625 PrefCallbackData *pCallback;
626 const char *pref;
628 NS_ENSURE_ARG_POINTER(aDomain);
629 NS_ENSURE_ARG_POINTER(aObserver);
631 if (!mObservers) {
632 mObservers = new nsAutoVoidArray();
633 if (nsnull == mObservers)
634 return NS_ERROR_OUT_OF_MEMORY;
637 pCallback = (PrefCallbackData *)nsMemory::Alloc(sizeof(PrefCallbackData));
638 if (nsnull == pCallback)
639 return NS_ERROR_OUT_OF_MEMORY;
641 pCallback->pBranch = this;
642 pCallback->pObserver = aObserver;
644 // hold a weak reference to the observer if so requested
645 if (aHoldWeak) {
646 nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver);
647 if (!weakRefFactory) {
648 // the caller didn't give us a object that supports weak reference... tell them
649 nsMemory::Free(pCallback);
650 return NS_ERROR_INVALID_ARG;
652 nsCOMPtr<nsIWeakReference> tmp = do_GetWeakReference(weakRefFactory);
653 NS_ADDREF(pCallback->pWeakRef = tmp);
654 } else {
655 pCallback->pWeakRef = nsnull;
656 NS_ADDREF(pCallback->pObserver);
659 mObservers->AppendElement(pCallback);
660 mObserverDomains.AppendCString(nsCString(aDomain));
662 // We must pass a fully qualified preference name to the callback
663 pref = getPrefName(aDomain); // aDomain == nsnull only possible failure, trapped above
664 PREF_RegisterCallback(pref, NotifyObserver, pCallback);
665 return NS_OK;
668 NS_IMETHODIMP nsPrefBranch::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
670 const char *pref;
671 PrefCallbackData *pCallback;
672 PRInt32 count;
673 PRInt32 i;
674 nsresult rv;
675 nsCAutoString domain;
677 NS_ENSURE_ARG_POINTER(aDomain);
678 NS_ENSURE_ARG_POINTER(aObserver);
680 if (!mObservers)
681 return NS_OK;
683 // need to find the index of observer, so we can remove it from the domain list too
684 count = mObservers->Count();
685 if (count == 0)
686 return NS_OK;
688 for (i = 0; i < count; i++) {
689 pCallback = (PrefCallbackData *)mObservers->ElementAt(i);
690 if (pCallback) {
691 if (pCallback->pObserver == aObserver) {
692 mObserverDomains.CStringAt(i, domain);
693 if (domain.Equals(aDomain)) {
694 // We must pass a fully qualified preference name to remove the callback
695 pref = getPrefName(aDomain); // aDomain == nsnull only possible failure, trapped above
696 rv = PREF_UnregisterCallback(pref, NotifyObserver, pCallback);
697 if (NS_SUCCEEDED(rv)) {
698 // Remove this observer from our array so that nobody else can remove
699 // what we're trying to remove ourselves right now.
700 mObservers->RemoveElementAt(i);
701 mObserverDomains.RemoveCStringAt(i);
702 if (pCallback->pWeakRef) {
703 NS_RELEASE(pCallback->pWeakRef);
704 } else {
705 NS_RELEASE(pCallback->pObserver);
707 nsMemory::Free(pCallback);
709 return rv;
715 return NS_OK;
718 NS_IMETHODIMP nsPrefBranch::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
720 // watch for xpcom shutdown and free our observers to eliminate any cyclic references
721 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
722 freeObserverList();
724 return NS_OK;
727 static nsresult NotifyObserver(const char *newpref, void *data)
729 PrefCallbackData *pData = (PrefCallbackData *)data;
731 // remove any root this string may contain so as to not confuse the observer
732 // by passing them something other than what they passed us as a topic
733 PRUint32 len = pData->pBranch->GetRootLength();
734 nsCAutoString suffix(newpref + len);
736 nsCOMPtr<nsIObserver> observer;
737 if (pData->pWeakRef) {
738 observer = do_QueryReferent(pData->pWeakRef);
739 if (!observer) {
740 // this weak referenced observer went away, remove them from the list
741 pData->pBranch->RemoveObserver(newpref, pData->pObserver);
742 return NS_OK;
744 } else {
745 observer = pData->pObserver;
748 observer->Observe(static_cast<nsIPrefBranch *>(pData->pBranch),
749 NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
750 NS_ConvertASCIItoUTF16(suffix).get());
751 return NS_OK;
755 void nsPrefBranch::freeObserverList(void)
757 const char *pref;
758 PrefCallbackData *pCallback;
760 if (mObservers) {
761 // unregister the observers
762 PRInt32 count;
764 count = mObservers->Count();
765 if (count > 0) {
766 PRInt32 i;
767 nsCAutoString domain;
768 for (i = 0; i < count; ++i) {
769 pCallback = (PrefCallbackData *)mObservers->ElementAt(i);
770 if (pCallback) {
771 mObserverDomains.CStringAt(i, domain);
772 // We must pass a fully qualified preference name to remove the callback
773 pref = getPrefName(domain.get()); // can't fail because domain must be valid
774 // Remove this observer from our array so that nobody else can remove
775 // what we're trying to remove right now.
776 mObservers->ReplaceElementAt(nsnull, i);
777 PREF_UnregisterCallback(pref, NotifyObserver, pCallback);
778 if (pCallback->pWeakRef) {
779 NS_RELEASE(pCallback->pWeakRef);
780 } else {
781 NS_RELEASE(pCallback->pObserver);
783 nsMemory::Free(pCallback);
787 // now empty the observer domains array in bulk
788 mObserverDomains.Clear();
790 delete mObservers;
791 mObservers = 0;
795 nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char *aPrefName, PRUnichar **return_buf)
797 nsresult rv;
799 // the default value contains a URL to a .properties file
801 nsXPIDLCString propertyFileURL;
802 rv = PREF_CopyCharPref(aPrefName, getter_Copies(propertyFileURL), PR_TRUE);
803 if (NS_FAILED(rv))
804 return rv;
806 nsCOMPtr<nsIStringBundleService> bundleService =
807 do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
808 if (NS_FAILED(rv))
809 return rv;
811 nsCOMPtr<nsIStringBundle> bundle;
812 rv = bundleService->CreateBundle(propertyFileURL,
813 getter_AddRefs(bundle));
814 if (NS_FAILED(rv))
815 return rv;
817 // string names are in unicode
818 nsAutoString stringId;
819 stringId.AssignASCII(aPrefName);
821 return bundle->GetStringFromName(stringId.get(), return_buf);
824 const char *nsPrefBranch::getPrefName(const char *aPrefName)
826 // for speed, avoid strcpy if we can:
827 if (mPrefRoot.IsEmpty())
828 return aPrefName;
830 // isn't there a better way to do this? this is really kind of gross.
831 mPrefRoot.Truncate(mPrefRootLength);
833 // only append if anything to append
834 if ((nsnull != aPrefName) && (*aPrefName != '\0'))
835 mPrefRoot.Append(aPrefName);
837 return mPrefRoot.get();
840 nsresult nsPrefBranch::getValidatedPrefName(const char *aPrefName, const char **_retval)
842 static const char capabilityPrefix[] = "capability.";
844 NS_ENSURE_ARG_POINTER(aPrefName);
845 const char *fullPref = getPrefName(aPrefName);
847 // now that we have the pref, check it against the ScriptSecurityManager
848 if ((fullPref[0] == 'c') &&
849 PL_strncmp(fullPref, capabilityPrefix, sizeof(capabilityPrefix)-1) == 0)
851 nsresult rv;
852 nsCOMPtr<nsIPrefSecurityCheck> secCheck =
853 do_GetService(NS_GLOBAL_PREF_SECURITY_CHECK, &rv);
855 if (NS_FAILED(rv))
856 return NS_ERROR_FAILURE;
858 PRBool enabled;
859 rv = secCheck->CanAccessSecurityPreferences(&enabled);
860 if (NS_FAILED(rv) || !enabled)
861 return NS_ERROR_FAILURE;
864 *_retval = fullPref;
865 return NS_OK;
868 static PLDHashOperator
869 pref_enumChild(PLDHashTable *table, PLDHashEntryHdr *heh,
870 PRUint32 i, void *arg)
872 PrefHashEntry *he = static_cast<PrefHashEntry*>(heh);
873 EnumerateData *d = reinterpret_cast<EnumerateData *>(arg);
874 if (PL_strncmp(he->key, d->parent, PL_strlen(d->parent)) == 0) {
875 d->pref_list->AppendElement((void*)he->key);
877 return PL_DHASH_NEXT;
882 * nsISecurityPref methods
884 * Pref access without security check - these are here
885 * to support nsScriptSecurityManager.
886 * These functions are part of nsISecurityPref, not nsIPref.
887 * **PLEASE** do not call these functions from elsewhere
889 NS_IMETHODIMP nsPrefBranch::SecurityGetBoolPref(const char *pref, PRBool * return_val)
891 return PREF_GetBoolPref(getPrefName(pref), return_val, PR_FALSE);
894 NS_IMETHODIMP nsPrefBranch::SecuritySetBoolPref(const char *pref, PRBool value)
896 return PREF_SetBoolPref(getPrefName(pref), value);
899 NS_IMETHODIMP nsPrefBranch::SecurityGetCharPref(const char *pref, char ** return_buf)
901 return PREF_CopyCharPref(getPrefName(pref), return_buf, PR_FALSE);
904 NS_IMETHODIMP nsPrefBranch::SecuritySetCharPref(const char *pref, const char* value)
906 return PREF_SetCharPref(getPrefName(pref), value);
909 NS_IMETHODIMP nsPrefBranch::SecurityGetIntPref(const char *pref, PRInt32 * return_val)
911 return PREF_GetIntPref(getPrefName(pref), return_val, PR_FALSE);
914 NS_IMETHODIMP nsPrefBranch::SecuritySetIntPref(const char *pref, PRInt32 value)
916 return PREF_SetIntPref(getPrefName(pref), value);
919 NS_IMETHODIMP nsPrefBranch::SecurityClearUserPref(const char *pref_name)
921 return PREF_ClearUserPref(getPrefName(pref_name));
924 //----------------------------------------------------------------------------
925 // nsPrefLocalizedString
926 //----------------------------------------------------------------------------
928 nsPrefLocalizedString::nsPrefLocalizedString()
932 nsPrefLocalizedString::~nsPrefLocalizedString()
938 * nsISupports Implementation
941 NS_IMPL_THREADSAFE_ADDREF(nsPrefLocalizedString)
942 NS_IMPL_THREADSAFE_RELEASE(nsPrefLocalizedString)
944 NS_INTERFACE_MAP_BEGIN(nsPrefLocalizedString)
945 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefLocalizedString)
946 NS_INTERFACE_MAP_ENTRY(nsIPrefLocalizedString)
947 NS_INTERFACE_MAP_ENTRY(nsISupportsString)
948 NS_INTERFACE_MAP_END
950 nsresult nsPrefLocalizedString::Init()
952 nsresult rv;
953 mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
955 return rv;
958 NS_IMETHODIMP
959 nsPrefLocalizedString::GetData(PRUnichar** _retval)
961 nsAutoString data;
963 nsresult rv = GetData(data);
964 if (NS_FAILED(rv))
965 return rv;
967 *_retval = ToNewUnicode(data);
968 if (!*_retval)
969 return NS_ERROR_OUT_OF_MEMORY;
971 return NS_OK;
974 NS_IMETHODIMP
975 nsPrefLocalizedString::SetData(const PRUnichar *aData)
977 if (!aData)
978 return SetData(EmptyString());
979 return SetData(nsDependentString(aData));
982 NS_IMETHODIMP
983 nsPrefLocalizedString::SetDataWithLength(PRUint32 aLength,
984 const PRUnichar* aData)
986 if (!aData)
987 return SetData(EmptyString());
988 return SetData(Substring(aData, aData + aLength));
991 //----------------------------------------------------------------------------
992 // nsRelativeFilePref
993 //----------------------------------------------------------------------------
995 NS_IMPL_THREADSAFE_ISUPPORTS1(nsRelativeFilePref, nsIRelativeFilePref)
997 nsRelativeFilePref::nsRelativeFilePref()
1001 nsRelativeFilePref::~nsRelativeFilePref()
1005 NS_IMETHODIMP nsRelativeFilePref::GetFile(nsILocalFile * *aFile)
1007 NS_ENSURE_ARG_POINTER(aFile);
1008 *aFile = mFile;
1009 NS_IF_ADDREF(*aFile);
1010 return NS_OK;
1013 NS_IMETHODIMP nsRelativeFilePref::SetFile(nsILocalFile * aFile)
1015 mFile = aFile;
1016 return NS_OK;
1019 NS_IMETHODIMP nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey)
1021 aRelativeToKey.Assign(mRelativeToKey);
1022 return NS_OK;
1025 NS_IMETHODIMP nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey)
1027 mRelativeToKey.Assign(aRelativeToKey);
1028 return NS_OK;