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
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.
23 * Alec Flett <alecf@netscape.com>
24 * Brian Nesse <bnesse@netscape.com>
25 * Frederic Plourde <frederic.plourde@collabora.co.uk>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 #include "mozilla/dom/ContentChild.h"
43 #include "nsXULAppAPI.h"
46 #include "nsPrefBranch.h"
47 #include "nsILocalFile.h"
48 #include "nsIObserverService.h"
50 #include "nsISupportsPrimitives.h"
51 #include "nsIDirectoryService.h"
53 #include "nsReadableUtils.h"
54 #include "nsXPIDLString.h"
55 #include "nsIStringBundle.h"
62 #include "mozilla/Services.h"
64 #include "prefapi_private_data.h"
67 struct EnumerateData
{
69 nsTArray
<nsCString
> *pref_list
;
73 static PLDHashOperator
74 pref_enumChild(PLDHashTable
*table
, PLDHashEntryHdr
*heh
,
75 PRUint32 i
, void *arg
);
78 using mozilla::dom::ContentChild
;
83 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
84 ContentChild
* cpc
= ContentChild::GetSingleton();
86 NS_RUNTIMEABORT("Content Protocol is NULL! We're going to crash!");
95 * Constructor/Destructor
98 nsPrefBranch::nsPrefBranch(const char *aPrefRoot
, PRBool aDefaultBranch
)
100 mPrefRoot
= aPrefRoot
;
101 mPrefRootLength
= mPrefRoot
.Length();
102 mIsDefault
= aDefaultBranch
;
103 mFreeingObserverList
= PR_FALSE
;
106 nsCOMPtr
<nsIObserverService
> observerService
=
107 mozilla::services::GetObserverService();
108 if (observerService
) {
109 ++mRefCnt
; // Our refcnt must be > 0 when we call this, or we'll get deleted!
110 // add weak so we don't have to clean up at shutdown
111 observerService
->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, PR_TRUE
);
116 nsPrefBranch::~nsPrefBranch()
120 nsCOMPtr
<nsIObserverService
> observerService
=
121 mozilla::services::GetObserverService();
123 observerService
->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
);
128 * nsISupports Implementation
131 NS_IMPL_THREADSAFE_ADDREF(nsPrefBranch
)
132 NS_IMPL_THREADSAFE_RELEASE(nsPrefBranch
)
134 NS_INTERFACE_MAP_BEGIN(nsPrefBranch
)
135 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIPrefBranch
)
136 NS_INTERFACE_MAP_ENTRY(nsIPrefBranch
)
137 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranch2
, !mIsDefault
)
138 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranchInternal
, !mIsDefault
)
139 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
140 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
145 * nsIPrefBranch Implementation
148 NS_IMETHODIMP
nsPrefBranch::GetRoot(char **aRoot
)
150 NS_ENSURE_ARG_POINTER(aRoot
);
151 mPrefRoot
.Truncate(mPrefRootLength
);
152 *aRoot
= ToNewCString(mPrefRoot
);
156 NS_IMETHODIMP
nsPrefBranch::GetPrefType(const char *aPrefName
, PRInt32
*_retval
)
158 NS_ENSURE_ARG(aPrefName
);
159 const char *pref
= getPrefName(aPrefName
);
160 *_retval
= PREF_GetPrefType(pref
);
164 NS_IMETHODIMP
nsPrefBranch::GetBoolPref(const char *aPrefName
, PRBool
*_retval
)
166 NS_ENSURE_ARG(aPrefName
);
167 const char *pref
= getPrefName(aPrefName
);
168 return PREF_GetBoolPref(pref
, _retval
, mIsDefault
);
171 NS_IMETHODIMP
nsPrefBranch::SetBoolPref(const char *aPrefName
, PRInt32 aValue
)
174 if (GetContentChild()) {
175 NS_ERROR("cannot set pref from content process");
176 return NS_ERROR_NOT_AVAILABLE
;
180 NS_ENSURE_ARG(aPrefName
);
181 const char *pref
= getPrefName(aPrefName
);
182 return PREF_SetBoolPref(pref
, aValue
, mIsDefault
);
185 NS_IMETHODIMP
nsPrefBranch::GetCharPref(const char *aPrefName
, char **_retval
)
187 NS_ENSURE_ARG(aPrefName
);
188 const char *pref
= getPrefName(aPrefName
);
189 return PREF_CopyCharPref(pref
, _retval
, mIsDefault
);
192 NS_IMETHODIMP
nsPrefBranch::SetCharPref(const char *aPrefName
, const char *aValue
)
195 if (GetContentChild()) {
196 NS_ERROR("cannot set pref from content process");
197 return NS_ERROR_NOT_AVAILABLE
;
201 NS_ENSURE_ARG(aPrefName
);
202 NS_ENSURE_ARG(aValue
);
203 const char *pref
= getPrefName(aPrefName
);
204 return PREF_SetCharPref(pref
, aValue
, mIsDefault
);
207 NS_IMETHODIMP
nsPrefBranch::GetIntPref(const char *aPrefName
, PRInt32
*_retval
)
209 NS_ENSURE_ARG(aPrefName
);
210 const char *pref
= getPrefName(aPrefName
);
211 return PREF_GetIntPref(pref
, _retval
, mIsDefault
);
214 NS_IMETHODIMP
nsPrefBranch::SetIntPref(const char *aPrefName
, PRInt32 aValue
)
217 if (GetContentChild()) {
218 NS_ERROR("cannot set pref from content process");
219 return NS_ERROR_NOT_AVAILABLE
;
223 NS_ENSURE_ARG(aPrefName
);
224 const char *pref
= getPrefName(aPrefName
);
225 return PREF_SetIntPref(pref
, aValue
, mIsDefault
);
228 NS_IMETHODIMP
nsPrefBranch::GetComplexValue(const char *aPrefName
, const nsIID
& aType
, void **_retval
)
230 NS_ENSURE_ARG(aPrefName
);
233 nsXPIDLCString utf8String
;
235 // we have to do this one first because it's different than all the rest
236 if (aType
.Equals(NS_GET_IID(nsIPrefLocalizedString
))) {
237 nsCOMPtr
<nsIPrefLocalizedString
> theString(do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID
, &rv
));
238 if (NS_FAILED(rv
)) return rv
;
240 const char *pref
= getPrefName(aPrefName
);
241 PRBool bNeedDefault
= PR_FALSE
;
244 bNeedDefault
= PR_TRUE
;
246 // if there is no user (or locked) value
247 if (!PREF_HasUserPref(pref
) && !PREF_PrefIsLocked(pref
)) {
248 bNeedDefault
= PR_TRUE
;
252 // if we need to fetch the default value, do that instead, otherwise use the
253 // value we pulled in at the top of this function
255 nsXPIDLString utf16String
;
256 rv
= GetDefaultFromPropertiesFile(pref
, getter_Copies(utf16String
));
257 if (NS_SUCCEEDED(rv
)) {
258 theString
->SetData(utf16String
.get());
261 rv
= GetCharPref(aPrefName
, getter_Copies(utf8String
));
262 if (NS_SUCCEEDED(rv
)) {
263 theString
->SetData(NS_ConvertUTF8toUTF16(utf8String
).get());
267 if (NS_SUCCEEDED(rv
)) {
268 const char *pref
= getPrefName(aPrefName
);
269 PRBool bNeedDefault
= PR_FALSE
;
272 bNeedDefault
= PR_TRUE
;
274 // if there is no user (or locked) value
275 if (!PREF_HasUserPref(pref
) && !PREF_PrefIsLocked(pref
)) {
276 bNeedDefault
= PR_TRUE
;
280 // if we need to fetch the default value, do that instead, otherwise use the
281 // value we pulled in at the top of this function
283 nsXPIDLString utf16String
;
284 rv
= GetDefaultFromPropertiesFile(pref
, getter_Copies(utf16String
));
285 if (NS_SUCCEEDED(rv
)) {
286 rv
= theString
->SetData(utf16String
.get());
289 rv
= GetCharPref(aPrefName
, getter_Copies(utf8String
));
290 if (NS_SUCCEEDED(rv
)) {
291 rv
= theString
->SetData(NS_ConvertUTF8toUTF16(utf8String
).get());
294 if (NS_SUCCEEDED(rv
)) {
295 nsIPrefLocalizedString
*temp
= theString
;
298 *_retval
= (void *)temp
;
305 // if we can't get the pref, there's no point in being here
306 rv
= GetCharPref(aPrefName
, getter_Copies(utf8String
));
311 if (aType
.Equals(NS_GET_IID(nsILocalFile
))) {
313 if (GetContentChild()) {
314 NS_ERROR("cannot get nsILocalFile pref from content process");
315 return NS_ERROR_NOT_AVAILABLE
;
319 nsCOMPtr
<nsILocalFile
> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID
, &rv
));
321 if (NS_SUCCEEDED(rv
)) {
322 rv
= file
->SetPersistentDescriptor(utf8String
);
323 if (NS_SUCCEEDED(rv
)) {
324 file
.forget(reinterpret_cast<nsILocalFile
**>(_retval
));
331 if (aType
.Equals(NS_GET_IID(nsIRelativeFilePref
))) {
333 if (GetContentChild()) {
334 NS_ERROR("cannot get nsIRelativeFilePref from content process");
335 return NS_ERROR_NOT_AVAILABLE
;
339 nsACString::const_iterator keyBegin
, strEnd
;
340 utf8String
.BeginReading(keyBegin
);
341 utf8String
.EndReading(strEnd
);
343 // The pref has the format: [fromKey]a/b/c
344 if (*keyBegin
++ != '[')
345 return NS_ERROR_FAILURE
;
346 nsACString::const_iterator
keyEnd(keyBegin
);
347 if (!FindCharInReadable(']', keyEnd
, strEnd
))
348 return NS_ERROR_FAILURE
;
349 nsCAutoString
key(Substring(keyBegin
, keyEnd
));
351 nsCOMPtr
<nsILocalFile
> fromFile
;
352 nsCOMPtr
<nsIProperties
> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
));
355 rv
= directoryService
->Get(key
.get(), NS_GET_IID(nsILocalFile
), getter_AddRefs(fromFile
));
359 nsCOMPtr
<nsILocalFile
> theFile
;
360 rv
= NS_NewNativeLocalFile(EmptyCString(), PR_TRUE
, getter_AddRefs(theFile
));
363 rv
= theFile
->SetRelativeDescriptor(fromFile
, Substring(++keyEnd
, strEnd
));
366 nsCOMPtr
<nsIRelativeFilePref
> relativePref
;
367 rv
= NS_NewRelativeFilePref(theFile
, key
, getter_AddRefs(relativePref
));
371 relativePref
.forget(reinterpret_cast<nsIRelativeFilePref
**>(_retval
));
375 if (aType
.Equals(NS_GET_IID(nsISupportsString
))) {
376 nsCOMPtr
<nsISupportsString
> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
, &rv
));
378 if (NS_SUCCEEDED(rv
)) {
379 theString
->SetData(NS_ConvertUTF8toUTF16(utf8String
));
380 theString
.forget(reinterpret_cast<nsISupportsString
**>(_retval
));
385 NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type");
386 return NS_NOINTERFACE
;
389 NS_IMETHODIMP
nsPrefBranch::SetComplexValue(const char *aPrefName
, const nsIID
& aType
, nsISupports
*aValue
)
392 if (GetContentChild()) {
393 NS_ERROR("cannot set pref from content process");
394 return NS_ERROR_NOT_AVAILABLE
;
398 NS_ENSURE_ARG(aPrefName
);
400 nsresult rv
= NS_NOINTERFACE
;
402 if (aType
.Equals(NS_GET_IID(nsILocalFile
))) {
403 nsCOMPtr
<nsILocalFile
> file
= do_QueryInterface(aValue
);
405 return NS_NOINTERFACE
;
406 nsCAutoString descriptorString
;
408 rv
= file
->GetPersistentDescriptor(descriptorString
);
409 if (NS_SUCCEEDED(rv
)) {
410 rv
= SetCharPref(aPrefName
, descriptorString
.get());
415 if (aType
.Equals(NS_GET_IID(nsIRelativeFilePref
))) {
416 nsCOMPtr
<nsIRelativeFilePref
> relFilePref
= do_QueryInterface(aValue
);
418 return NS_NOINTERFACE
;
420 nsCOMPtr
<nsILocalFile
> file
;
421 relFilePref
->GetFile(getter_AddRefs(file
));
423 return NS_NOINTERFACE
;
424 nsCAutoString relativeToKey
;
425 (void) relFilePref
->GetRelativeToKey(relativeToKey
);
427 nsCOMPtr
<nsILocalFile
> relativeToFile
;
428 nsCOMPtr
<nsIProperties
> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
, &rv
));
431 rv
= directoryService
->Get(relativeToKey
.get(), NS_GET_IID(nsILocalFile
), getter_AddRefs(relativeToFile
));
435 nsCAutoString relDescriptor
;
436 rv
= file
->GetRelativeDescriptor(relativeToFile
, relDescriptor
);
440 nsCAutoString descriptorString
;
441 descriptorString
.Append('[');
442 descriptorString
.Append(relativeToKey
);
443 descriptorString
.Append(']');
444 descriptorString
.Append(relDescriptor
);
445 return SetCharPref(aPrefName
, descriptorString
.get());
448 if (aType
.Equals(NS_GET_IID(nsISupportsString
))) {
449 nsCOMPtr
<nsISupportsString
> theString
= do_QueryInterface(aValue
);
452 nsAutoString wideString
;
454 rv
= theString
->GetData(wideString
);
455 if (NS_SUCCEEDED(rv
)) {
456 rv
= SetCharPref(aPrefName
, NS_ConvertUTF16toUTF8(wideString
).get());
462 if (aType
.Equals(NS_GET_IID(nsIPrefLocalizedString
))) {
463 nsCOMPtr
<nsIPrefLocalizedString
> theString
= do_QueryInterface(aValue
);
466 nsXPIDLString wideString
;
468 rv
= theString
->GetData(getter_Copies(wideString
));
469 if (NS_SUCCEEDED(rv
)) {
470 rv
= SetCharPref(aPrefName
, NS_ConvertUTF16toUTF8(wideString
).get());
476 NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type");
477 return NS_NOINTERFACE
;
480 NS_IMETHODIMP
nsPrefBranch::ClearUserPref(const char *aPrefName
)
483 if (GetContentChild()) {
484 NS_ERROR("cannot set pref from content process");
485 return NS_ERROR_NOT_AVAILABLE
;
489 NS_ENSURE_ARG(aPrefName
);
490 const char *pref
= getPrefName(aPrefName
);
491 return PREF_ClearUserPref(pref
);
494 NS_IMETHODIMP
nsPrefBranch::PrefHasUserValue(const char *aPrefName
, PRBool
*_retval
)
496 NS_ENSURE_ARG_POINTER(_retval
);
497 NS_ENSURE_ARG(aPrefName
);
498 const char *pref
= getPrefName(aPrefName
);
499 *_retval
= PREF_HasUserPref(pref
);
503 NS_IMETHODIMP
nsPrefBranch::LockPref(const char *aPrefName
)
506 if (GetContentChild()) {
507 NS_ERROR("cannot lock pref from content process");
508 return NS_ERROR_NOT_AVAILABLE
;
512 NS_ENSURE_ARG(aPrefName
);
513 const char *pref
= getPrefName(aPrefName
);
514 return PREF_LockPref(pref
, PR_TRUE
);
517 NS_IMETHODIMP
nsPrefBranch::PrefIsLocked(const char *aPrefName
, PRBool
*_retval
)
520 if (GetContentChild()) {
521 NS_ERROR("cannot check lock pref from content process");
522 return NS_ERROR_NOT_AVAILABLE
;
526 NS_ENSURE_ARG_POINTER(_retval
);
527 NS_ENSURE_ARG(aPrefName
);
528 const char *pref
= getPrefName(aPrefName
);
529 *_retval
= PREF_PrefIsLocked(pref
);
533 NS_IMETHODIMP
nsPrefBranch::UnlockPref(const char *aPrefName
)
536 if (GetContentChild()) {
537 NS_ERROR("cannot unlock pref from content process");
538 return NS_ERROR_NOT_AVAILABLE
;
542 NS_ENSURE_ARG(aPrefName
);
543 const char *pref
= getPrefName(aPrefName
);
544 return PREF_LockPref(pref
, PR_FALSE
);
547 /* void resetBranch (in string startingAt); */
548 NS_IMETHODIMP
nsPrefBranch::ResetBranch(const char *aStartingAt
)
550 return NS_ERROR_NOT_IMPLEMENTED
;
553 NS_IMETHODIMP
nsPrefBranch::DeleteBranch(const char *aStartingAt
)
556 if (GetContentChild()) {
557 NS_ERROR("cannot set pref from content process");
558 return NS_ERROR_NOT_AVAILABLE
;
562 NS_ENSURE_ARG(aStartingAt
);
563 const char *pref
= getPrefName(aStartingAt
);
564 return PREF_DeleteBranch(pref
);
567 NS_IMETHODIMP
nsPrefBranch::GetChildList(const char *aStartingAt
, PRUint32
*aCount
, char ***aChildArray
)
573 nsAutoTArray
<nsCString
, 32> prefArray
;
575 NS_ENSURE_ARG(aStartingAt
);
576 NS_ENSURE_ARG_POINTER(aCount
);
577 NS_ENSURE_ARG_POINTER(aChildArray
);
579 *aChildArray
= nsnull
;
583 return NS_ERROR_NOT_INITIALIZED
;
585 // this will contain a list of all the pref name strings
586 // allocate on the stack for speed
588 ed
.parent
= getPrefName(aStartingAt
);
589 ed
.pref_list
= &prefArray
;
590 PL_DHashTableEnumerate(&gHashTable
, pref_enumChild
, &ed
);
592 // now that we've built up the list, run the callback on
593 // all the matching elements
594 numPrefs
= prefArray
.Length();
597 outArray
= (char **)nsMemory::Alloc(numPrefs
* sizeof(char *));
599 return NS_ERROR_OUT_OF_MEMORY
;
601 for (dwIndex
= 0; dwIndex
< numPrefs
; ++dwIndex
) {
602 // we need to lop off mPrefRoot in case the user is planning to pass this
603 // back to us because if they do we are going to add mPrefRoot again.
604 const nsCString
& element
= prefArray
[dwIndex
];
605 outArray
[dwIndex
] = (char *)nsMemory::Clone(
606 element
.get() + mPrefRootLength
, element
.Length() - mPrefRootLength
+ 1);
608 if (!outArray
[dwIndex
]) {
609 // we ran out of memory... this is annoying
610 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(dwIndex
, outArray
);
611 return NS_ERROR_OUT_OF_MEMORY
;
614 *aChildArray
= outArray
;
623 * nsIPrefBranch2 methods
626 NS_IMETHODIMP
nsPrefBranch::AddObserver(const char *aDomain
, nsIObserver
*aObserver
, PRBool aHoldWeak
)
628 PrefCallback
*pCallback
;
631 NS_ENSURE_ARG(aDomain
);
632 NS_ENSURE_ARG(aObserver
);
634 // hold a weak reference to the observer if so requested
636 nsCOMPtr
<nsISupportsWeakReference
> weakRefFactory
= do_QueryInterface(aObserver
);
637 if (!weakRefFactory
) {
638 // the caller didn't give us a object that supports weak reference... tell them
639 return NS_ERROR_INVALID_ARG
;
642 // Construct a PrefCallback with a weak reference to the observer.
643 pCallback
= new PrefCallback(aDomain
, weakRefFactory
, this);
646 // Construct a PrefCallback with a strong reference to the observer.
647 pCallback
= new PrefCallback(aDomain
, aObserver
, this);
650 if (mObservers
.Get(pCallback
)) {
651 NS_WARNING("Ignoring duplicate observer.");
656 PRBool putSucceeded
= mObservers
.Put(pCallback
, pCallback
);
660 return NS_ERROR_FAILURE
;
663 // We must pass a fully qualified preference name to the callback
664 // aDomain == nsnull is the only possible failure, and we trapped it with
665 // NS_ENSURE_ARG above.
666 pref
= getPrefName(aDomain
);
667 PREF_RegisterCallback(pref
, NotifyObserver
, pCallback
);
671 NS_IMETHODIMP
nsPrefBranch::RemoveObserver(const char *aDomain
, nsIObserver
*aObserver
)
673 NS_ENSURE_ARG(aDomain
);
674 NS_ENSURE_ARG(aObserver
);
678 // If we're in the middle of a call to freeObserverList, don't process this
679 // RemoveObserver call -- the observer in question will be removed soon, if
680 // it hasn't been already.
682 // It's important that we don't touch mObservers in any way -- even a Get()
683 // which retuns null might cause the hashtable to resize itself, which will
684 // break the Enumerator in freeObserverList.
685 if (mFreeingObserverList
)
688 // Remove the relevant PrefCallback from mObservers and get an owning
689 // pointer to it. Unregister the callback first, and then let the owning
690 // pointer go out of scope and destroy the callback.
691 PrefCallback
key(aDomain
, aObserver
, this);
692 nsAutoPtr
<PrefCallback
> pCallback
;
693 mObservers
.RemoveAndForget(&key
, pCallback
);
695 // aDomain == nsnull is the only possible failure, trapped above
696 const char *pref
= getPrefName(aDomain
);
697 rv
= PREF_UnregisterCallback(pref
, NotifyObserver
, pCallback
);
703 NS_IMETHODIMP
nsPrefBranch::Observe(nsISupports
*aSubject
, const char *aTopic
, const PRUnichar
*someData
)
705 // watch for xpcom shutdown and free our observers to eliminate any cyclic references
706 if (!nsCRT::strcmp(aTopic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
)) {
713 nsresult
nsPrefBranch::NotifyObserver(const char *newpref
, void *data
)
715 PrefCallback
*pCallback
= (PrefCallback
*)data
;
717 nsCOMPtr
<nsIObserver
> observer
= pCallback
->GetObserver();
719 // The observer has expired. Let's remove this callback.
720 pCallback
->GetPrefBranch()->RemoveExpiredCallback(pCallback
);
724 // remove any root this string may contain so as to not confuse the observer
725 // by passing them something other than what they passed us as a topic
726 PRUint32 len
= pCallback
->GetPrefBranch()->GetRootLength();
727 nsCAutoString
suffix(newpref
+ len
);
729 observer
->Observe(static_cast<nsIPrefBranch
*>(pCallback
->GetPrefBranch()),
730 NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
,
731 NS_ConvertASCIItoUTF16(suffix
).get());
736 FreeObserverFunc(PrefCallback
*aKey
,
737 nsAutoPtr
<PrefCallback
> &aCallback
,
740 // Calling NS_RELEASE below might trigger a call to
741 // nsPrefBranch::RemoveObserver, since some classes remove themselves from
742 // the pref branch on destruction. We don't need to worry about this causing
743 // double-frees, however, because freeObserverList sets mFreeingObserverList
744 // to true, which prevents RemoveObserver calls from doing anything.
746 nsPrefBranch
*prefBranch
= aCallback
->GetPrefBranch();
747 const char *pref
= prefBranch
->getPrefName(aCallback
->GetDomain().get());
748 PREF_UnregisterCallback(pref
, nsPrefBranch::NotifyObserver
, aCallback
);
750 return PL_DHASH_REMOVE
;
753 void nsPrefBranch::freeObserverList(void)
755 // We need to prevent anyone from modifying mObservers while we're
756 // enumerating over it. In particular, some clients will call
757 // RemoveObserver() when they're destructed; we need to keep those calls from
758 // touching mObservers.
759 mFreeingObserverList
= PR_TRUE
;
760 mObservers
.Enumerate(&FreeObserverFunc
, nsnull
);
761 mFreeingObserverList
= PR_FALSE
;
765 nsPrefBranch::RemoveExpiredCallback(PrefCallback
*aCallback
)
767 NS_PRECONDITION(aCallback
->IsExpired(), "Callback should be expired.");
768 mObservers
.Remove(aCallback
);
771 nsresult
nsPrefBranch::GetDefaultFromPropertiesFile(const char *aPrefName
, PRUnichar
**return_buf
)
775 // the default value contains a URL to a .properties file
777 nsXPIDLCString propertyFileURL
;
778 rv
= PREF_CopyCharPref(aPrefName
, getter_Copies(propertyFileURL
), PR_TRUE
);
782 nsCOMPtr
<nsIStringBundleService
> bundleService
=
783 mozilla::services::GetStringBundleService();
785 return NS_ERROR_FAILURE
;
787 nsCOMPtr
<nsIStringBundle
> bundle
;
788 rv
= bundleService
->CreateBundle(propertyFileURL
,
789 getter_AddRefs(bundle
));
793 // string names are in unicode
794 nsAutoString stringId
;
795 stringId
.AssignASCII(aPrefName
);
797 return bundle
->GetStringFromName(stringId
.get(), return_buf
);
800 const char *nsPrefBranch::getPrefName(const char *aPrefName
)
802 NS_ASSERTION(aPrefName
, "null pref name!");
804 // for speed, avoid strcpy if we can:
805 if (mPrefRoot
.IsEmpty())
808 // isn't there a better way to do this? this is really kind of gross.
809 mPrefRoot
.Truncate(mPrefRootLength
);
810 mPrefRoot
.Append(aPrefName
);
811 return mPrefRoot
.get();
814 static PLDHashOperator
815 pref_enumChild(PLDHashTable
*table
, PLDHashEntryHdr
*heh
,
816 PRUint32 i
, void *arg
)
818 PrefHashEntry
*he
= static_cast<PrefHashEntry
*>(heh
);
819 EnumerateData
*d
= reinterpret_cast<EnumerateData
*>(arg
);
820 if (strncmp(he
->key
, d
->parent
, strlen(d
->parent
)) == 0) {
821 d
->pref_list
->AppendElement(he
->key
);
823 return PL_DHASH_NEXT
;
826 //----------------------------------------------------------------------------
827 // nsPrefLocalizedString
828 //----------------------------------------------------------------------------
830 nsPrefLocalizedString::nsPrefLocalizedString()
834 nsPrefLocalizedString::~nsPrefLocalizedString()
840 * nsISupports Implementation
843 NS_IMPL_THREADSAFE_ADDREF(nsPrefLocalizedString
)
844 NS_IMPL_THREADSAFE_RELEASE(nsPrefLocalizedString
)
846 NS_INTERFACE_MAP_BEGIN(nsPrefLocalizedString
)
847 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIPrefLocalizedString
)
848 NS_INTERFACE_MAP_ENTRY(nsIPrefLocalizedString
)
849 NS_INTERFACE_MAP_ENTRY(nsISupportsString
)
852 nsresult
nsPrefLocalizedString::Init()
855 mUnicodeString
= do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
, &rv
);
861 nsPrefLocalizedString::GetData(PRUnichar
**_retval
)
865 nsresult rv
= GetData(data
);
869 *_retval
= ToNewUnicode(data
);
871 return NS_ERROR_OUT_OF_MEMORY
;
877 nsPrefLocalizedString::SetData(const PRUnichar
*aData
)
880 return SetData(EmptyString());
881 return SetData(nsDependentString(aData
));
885 nsPrefLocalizedString::SetDataWithLength(PRUint32 aLength
,
886 const PRUnichar
*aData
)
889 return SetData(EmptyString());
890 return SetData(Substring(aData
, aData
+ aLength
));
893 //----------------------------------------------------------------------------
894 // nsRelativeFilePref
895 //----------------------------------------------------------------------------
897 NS_IMPL_THREADSAFE_ISUPPORTS1(nsRelativeFilePref
, nsIRelativeFilePref
)
899 nsRelativeFilePref::nsRelativeFilePref()
903 nsRelativeFilePref::~nsRelativeFilePref()
907 NS_IMETHODIMP
nsRelativeFilePref::GetFile(nsILocalFile
**aFile
)
909 NS_ENSURE_ARG_POINTER(aFile
);
911 NS_IF_ADDREF(*aFile
);
915 NS_IMETHODIMP
nsRelativeFilePref::SetFile(nsILocalFile
*aFile
)
921 NS_IMETHODIMP
nsRelativeFilePref::GetRelativeToKey(nsACString
& aRelativeToKey
)
923 aRelativeToKey
.Assign(mRelativeToKey
);
927 NS_IMETHODIMP
nsRelativeFilePref::SetRelativeToKey(const nsACString
& aRelativeToKey
)
929 mRelativeToKey
.Assign(aRelativeToKey
);