Back to index

lightning-sunbird  0.9+nobinonly
nsPrefBranch.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Alec Flett <alecf@netscape.com>
00024  *   Brian Nesse <bnesse@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsPrefBranch.h"
00041 #include "nsILocalFile.h"
00042 #include "nsIObserverService.h"
00043 #include "nsXPCOM.h"
00044 #include "nsISupportsPrimitives.h"
00045 #include "nsIDirectoryService.h"
00046 #include "nsString.h"
00047 #include "nsReadableUtils.h"
00048 #include "nsXPIDLString.h"
00049 #include "nsIStringBundle.h"
00050 #include "prefapi.h"
00051 #include "prmem.h"
00052 #include "pldhash.h"
00053 #include "nsPrefsCID.h"
00054 
00055 #ifndef MOZ_NO_XPCOM_OBSOLETE
00056 #include "nsIFileSpec.h"  // this should be removed eventually
00057 #endif
00058 
00059 #include "plstr.h"
00060 #include "nsCRT.h"
00061 
00062 #include "prefapi_private_data.h"
00063 
00064 // Definitions
00065 struct EnumerateData {
00066   const char  *parent;
00067   nsVoidArray *pref_list;
00068 };
00069 
00070 struct PrefCallbackData {
00071   nsIPrefBranch *pBranch;
00072   nsISupports   *pObserver;
00073   PRBool        bIsWeakRef;
00074 };
00075 
00076 
00077 // Prototypes
00078 PR_STATIC_CALLBACK(PLDHashOperator)
00079   pref_enumChild(PLDHashTable *table, PLDHashEntryHdr *heh,
00080                  PRUint32 i, void *arg);
00081 PR_STATIC_CALLBACK(nsresult)
00082   NotifyObserver(const char *newpref, void *data);
00083 
00084 /*
00085  * Constructor/Destructor
00086  */
00087 
00088 nsPrefBranch::nsPrefBranch(const char *aPrefRoot, PRBool aDefaultBranch)
00089   : mObservers(nsnull)
00090 {
00091   mPrefRoot = aPrefRoot;
00092   mPrefRootLength = mPrefRoot.Length();
00093   mIsDefault = aDefaultBranch;
00094 
00095   nsCOMPtr<nsIObserverService> observerService = 
00096            do_GetService("@mozilla.org/observer-service;1");
00097   if (observerService) {
00098     ++mRefCnt;    // Our refcnt must be > 0 when we call this, or we'll get deleted!
00099     // add weak so we don't have to clean up at shutdown
00100     observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
00101     --mRefCnt;
00102   }
00103 }
00104 
00105 nsPrefBranch::~nsPrefBranch()
00106 {
00107   freeObserverList();
00108 }
00109 
00110 
00111 /*
00112  * nsISupports Implementation
00113  */
00114 
00115 NS_IMPL_THREADSAFE_ADDREF(nsPrefBranch)
00116 NS_IMPL_THREADSAFE_RELEASE(nsPrefBranch)
00117 
00118 NS_INTERFACE_MAP_BEGIN(nsPrefBranch)
00119   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefBranch)
00120   NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
00121   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranch2, !mIsDefault)
00122   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranchInternal, !mIsDefault)
00123   NS_INTERFACE_MAP_ENTRY(nsISecurityPref)
00124   NS_INTERFACE_MAP_ENTRY(nsIObserver)
00125   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00126 NS_INTERFACE_MAP_END
00127 
00128 
00129 /*
00130  * nsIPrefBranch Implementation
00131  */
00132 
00133 NS_IMETHODIMP nsPrefBranch::GetRoot(char * *aRoot)
00134 {
00135   NS_ENSURE_ARG_POINTER(aRoot);
00136 
00137   mPrefRoot.Truncate(mPrefRootLength);
00138   *aRoot = ToNewCString(mPrefRoot);
00139   return NS_OK;
00140 }
00141 
00142 NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, PRInt32 *_retval)
00143 {
00144   const char *pref;
00145   nsresult   rv;
00146 
00147   rv = getValidatedPrefName(aPrefName, &pref);
00148   if (NS_FAILED(rv))
00149     return rv;
00150 
00151   *_retval = PREF_GetPrefType(pref);
00152   return NS_OK;
00153 }
00154 
00155 NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, PRBool *_retval)
00156 {
00157   const char *pref;
00158   nsresult   rv;
00159 
00160   rv = getValidatedPrefName(aPrefName, &pref);
00161   if (NS_SUCCEEDED(rv)) {
00162     rv = PREF_GetBoolPref(pref, _retval, mIsDefault);
00163   }
00164   return rv;
00165 }
00166 
00167 NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, PRInt32 aValue)
00168 {
00169   const char *pref;
00170   nsresult   rv;
00171 
00172   rv = getValidatedPrefName(aPrefName, &pref);
00173   if (NS_SUCCEEDED(rv)) {
00174     rv = PREF_SetBoolPref(pref, aValue, mIsDefault);
00175   }
00176   return rv;
00177 }
00178 
00179 NS_IMETHODIMP nsPrefBranch::GetCharPref(const char *aPrefName, char **_retval)
00180 {
00181   const char *pref;
00182   nsresult   rv;
00183 
00184   rv = getValidatedPrefName(aPrefName, &pref);
00185   if (NS_SUCCEEDED(rv)) {
00186     rv = PREF_CopyCharPref(pref, _retval, mIsDefault);
00187   }
00188   return rv;
00189 }
00190 
00191 NS_IMETHODIMP nsPrefBranch::SetCharPref(const char *aPrefName, const char *aValue)
00192 {
00193   const char *pref;
00194   nsresult   rv;
00195 
00196   NS_ENSURE_ARG_POINTER(aValue);
00197   rv = getValidatedPrefName(aPrefName, &pref);
00198   if (NS_SUCCEEDED(rv)) {
00199     rv = PREF_SetCharPref(pref, aValue, mIsDefault);
00200   }
00201   return rv;
00202 }
00203 
00204 NS_IMETHODIMP nsPrefBranch::GetIntPref(const char *aPrefName, PRInt32 *_retval)
00205 {
00206   const char *pref;
00207   nsresult   rv;
00208 
00209   rv = getValidatedPrefName(aPrefName, &pref);
00210   if (NS_SUCCEEDED(rv)) {
00211     rv = PREF_GetIntPref(pref, _retval, mIsDefault);
00212   }
00213   return rv;
00214 }
00215 
00216 NS_IMETHODIMP nsPrefBranch::SetIntPref(const char *aPrefName, PRInt32 aValue)
00217 {
00218   const char *pref;
00219   nsresult   rv;
00220 
00221   rv = getValidatedPrefName(aPrefName, &pref);
00222   if (NS_SUCCEEDED(rv)) {
00223     rv = PREF_SetIntPref(pref, aValue, mIsDefault);
00224   }
00225   return rv;
00226 }
00227 
00228 NS_IMETHODIMP nsPrefBranch::GetComplexValue(const char *aPrefName, const nsIID & aType, void * *_retval)
00229 {
00230   nsresult       rv;
00231   nsXPIDLCString utf8String;
00232 
00233   // we have to do this one first because it's different than all the rest
00234   if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
00235     nsCOMPtr<nsIPrefLocalizedString> theString(do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv));
00236 
00237     if (NS_SUCCEEDED(rv)) {
00238       const char *pref;
00239       PRBool  bNeedDefault = PR_FALSE;
00240 
00241       rv = getValidatedPrefName(aPrefName, &pref);
00242       if (NS_FAILED(rv))
00243         return rv;
00244 
00245       if (mIsDefault) {
00246         bNeedDefault = PR_TRUE;
00247       } else {
00248         // if there is no user (or locked) value
00249         if (!PREF_HasUserPref(pref) && !PREF_PrefIsLocked(pref)) {
00250           bNeedDefault = PR_TRUE;
00251         }
00252       }
00253 
00254       // if we need to fetch the default value, do that instead, otherwise use the
00255       // value we pulled in at the top of this function
00256       if (bNeedDefault) {
00257         nsXPIDLString utf16String;
00258         rv = GetDefaultFromPropertiesFile(pref, getter_Copies(utf16String));
00259         if (NS_SUCCEEDED(rv)) {
00260           rv = theString->SetData(utf16String.get());
00261         }
00262       } else {
00263         rv = GetCharPref(aPrefName, getter_Copies(utf8String));
00264         if (NS_SUCCEEDED(rv)) {
00265           rv = theString->SetData(NS_ConvertUTF8toUCS2(utf8String).get());
00266         }
00267       }
00268       if (NS_SUCCEEDED(rv)) {
00269         nsIPrefLocalizedString *temp = theString;
00270 
00271         NS_ADDREF(temp);
00272         *_retval = (void *)temp;
00273       }
00274     }
00275 
00276     return rv;
00277   }
00278 
00279   // if we can't get the pref, there's no point in being here
00280   rv = GetCharPref(aPrefName, getter_Copies(utf8String));
00281   if (NS_FAILED(rv)) {
00282     return rv;
00283   }
00284 
00285   if (aType.Equals(NS_GET_IID(nsILocalFile))) {
00286     nsCOMPtr<nsILocalFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
00287 
00288     if (NS_SUCCEEDED(rv)) {
00289       rv = file->SetPersistentDescriptor(utf8String);
00290       if (NS_SUCCEEDED(rv)) {
00291         nsILocalFile *temp = file;
00292 
00293         NS_ADDREF(temp);
00294         *_retval = (void *)temp;
00295         return NS_OK;
00296       }
00297     }
00298     return rv;
00299   }
00300 
00301   if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
00302     nsACString::const_iterator keyBegin, strEnd;
00303     utf8String.BeginReading(keyBegin);
00304     utf8String.EndReading(strEnd);    
00305 
00306     // The pref has the format: [fromKey]a/b/c
00307     if (*keyBegin++ != '[')        
00308         return NS_ERROR_FAILURE;
00309     nsACString::const_iterator keyEnd(keyBegin);
00310     if (!FindCharInReadable(']', keyEnd, strEnd))
00311         return NS_ERROR_FAILURE;
00312     nsCAutoString key(Substring(keyBegin, keyEnd));
00313     
00314     nsCOMPtr<nsILocalFile> fromFile;        
00315     nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
00316     if (NS_FAILED(rv))
00317       return rv;
00318     rv = directoryService->Get(key.get(), NS_GET_IID(nsILocalFile), getter_AddRefs(fromFile));
00319     if (NS_FAILED(rv))
00320       return rv;
00321     
00322     nsCOMPtr<nsILocalFile> theFile;
00323     rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(theFile));
00324     if (NS_FAILED(rv))
00325       return rv;
00326     rv = theFile->SetRelativeDescriptor(fromFile, Substring(++keyEnd, strEnd));
00327     if (NS_FAILED(rv))
00328       return rv;
00329     nsCOMPtr<nsIRelativeFilePref> relativePref;
00330     rv = NS_NewRelativeFilePref(theFile, key, getter_AddRefs(relativePref));
00331     if (NS_FAILED(rv))
00332       return rv;
00333 
00334     *_retval = relativePref;
00335     NS_ADDREF(NS_STATIC_CAST(nsIRelativeFilePref*, *_retval));
00336     return NS_OK;
00337   }
00338 
00339   if (aType.Equals(NS_GET_IID(nsISupportsString))) {
00340     nsCOMPtr<nsISupportsString> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
00341 
00342     if (NS_SUCCEEDED(rv)) {
00343       rv = theString->SetData(NS_ConvertUTF8toUCS2(utf8String));
00344       if (NS_SUCCEEDED(rv)) {
00345         nsISupportsString *temp = theString;
00346 
00347         NS_ADDREF(temp);
00348         *_retval = (void *)temp;
00349         return NS_OK;
00350       }
00351     }
00352     return rv;
00353   }
00354 
00355   // This is deprecated and you should not be using it
00356 #ifndef MOZ_NO_XPCOM_OBSOLETE
00357   if (aType.Equals(NS_GET_IID(nsIFileSpec))) {
00358     nsCOMPtr<nsIFileSpec> file(do_CreateInstance(NS_FILESPEC_CONTRACTID, &rv));
00359 
00360     if (NS_SUCCEEDED(rv)) {
00361       nsIFileSpec *temp = file;
00362       PRBool      valid;
00363 
00364       file->SetPersistentDescriptorString(utf8String);  // only returns NS_OK
00365       file->IsValid(&valid);
00366       if (!valid) {
00367         /* if the string wasn't a valid persistent descriptor, it might be a valid native path */
00368         file->SetNativePath(utf8String);
00369       }
00370       NS_ADDREF(temp);
00371       *_retval = (void *)temp;
00372       return NS_OK;
00373     }
00374     return rv;
00375   }
00376 #endif
00377 
00378   NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type");
00379   return NS_NOINTERFACE;
00380 }
00381 
00382 NS_IMETHODIMP nsPrefBranch::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
00383 {
00384   nsresult   rv = NS_NOINTERFACE;
00385 
00386   if (aType.Equals(NS_GET_IID(nsILocalFile))) {
00387     nsCOMPtr<nsILocalFile> file = do_QueryInterface(aValue);
00388     nsCAutoString descriptorString;
00389 
00390     rv = file->GetPersistentDescriptor(descriptorString);
00391     if (NS_SUCCEEDED(rv)) {
00392       rv = SetCharPref(aPrefName, descriptorString.get());
00393     }
00394     return rv;
00395   }
00396 
00397   if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
00398     nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue);
00399     if (!relFilePref)
00400       return NS_NOINTERFACE;
00401     
00402     nsCOMPtr<nsILocalFile> file;
00403     relFilePref->GetFile(getter_AddRefs(file));
00404     if (!file)
00405       return NS_ERROR_FAILURE;
00406     nsCAutoString relativeToKey;
00407     (void) relFilePref->GetRelativeToKey(relativeToKey);
00408 
00409     nsCOMPtr<nsILocalFile> relativeToFile;        
00410     nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
00411     if (NS_FAILED(rv))
00412       return rv;
00413     rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsILocalFile), getter_AddRefs(relativeToFile));
00414     if (NS_FAILED(rv))
00415       return rv;
00416 
00417     nsCAutoString relDescriptor;
00418     rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor);
00419     if (NS_FAILED(rv))
00420       return rv;
00421     
00422     nsCAutoString descriptorString;
00423     descriptorString.Append('[');
00424     descriptorString.Append(relativeToKey);
00425     descriptorString.Append(']');
00426     descriptorString.Append(relDescriptor);
00427     return SetCharPref(aPrefName, descriptorString.get());
00428   }
00429 
00430   if (aType.Equals(NS_GET_IID(nsISupportsString))) {
00431     nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
00432 
00433     if (theString) {
00434       nsAutoString wideString;
00435 
00436       rv = theString->GetData(wideString);
00437       if (NS_SUCCEEDED(rv)) {
00438         rv = SetCharPref(aPrefName, NS_ConvertUCS2toUTF8(wideString).get());
00439       }
00440     }
00441     return rv;
00442   }
00443 
00444   if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
00445     nsCOMPtr<nsIPrefLocalizedString> theString = do_QueryInterface(aValue);
00446 
00447     if (theString) {
00448       nsXPIDLString wideString;
00449 
00450       rv = theString->GetData(getter_Copies(wideString));
00451       if (NS_SUCCEEDED(rv)) {
00452         rv = SetCharPref(aPrefName, NS_ConvertUCS2toUTF8(wideString).get());
00453       }
00454     }
00455     return rv;
00456   }
00457 
00458 #ifndef MOZ_NO_XPCOM_OBSOLETE
00459   // This is deprecated and you should not be using it
00460   if (aType.Equals(NS_GET_IID(nsIFileSpec))) {
00461     nsCOMPtr<nsIFileSpec> file = do_QueryInterface(aValue);
00462     nsXPIDLCString descriptorString;
00463 
00464     rv = file->GetPersistentDescriptorString(getter_Copies(descriptorString));
00465     if (NS_SUCCEEDED(rv)) {
00466       rv = SetCharPref(aPrefName, descriptorString);
00467     }
00468     return rv;
00469   }
00470 #endif
00471 
00472   NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type");
00473   return NS_NOINTERFACE;
00474 }
00475 
00476 NS_IMETHODIMP nsPrefBranch::ClearUserPref(const char *aPrefName)
00477 {
00478   const char *pref;
00479   nsresult   rv;
00480 
00481   rv = getValidatedPrefName(aPrefName, &pref);
00482   if (NS_SUCCEEDED(rv)) {
00483     rv = PREF_ClearUserPref(pref);
00484   }
00485   return rv;
00486 }
00487 
00488 NS_IMETHODIMP nsPrefBranch::PrefHasUserValue(const char *aPrefName, PRBool *_retval)
00489 {
00490   const char *pref;
00491   nsresult   rv;
00492 
00493   NS_ENSURE_ARG_POINTER(_retval);
00494 
00495   rv = getValidatedPrefName(aPrefName, &pref);
00496   if (NS_SUCCEEDED(rv)) {
00497     *_retval = PREF_HasUserPref(pref);
00498   }
00499   return rv;
00500 }
00501 
00502 NS_IMETHODIMP nsPrefBranch::LockPref(const char *aPrefName)
00503 {
00504   const char *pref;
00505   nsresult   rv;
00506 
00507   rv = getValidatedPrefName(aPrefName, &pref);
00508   if (NS_SUCCEEDED(rv)) {
00509     rv = PREF_LockPref(pref, PR_TRUE);
00510   }
00511   return rv;
00512 }
00513 
00514 NS_IMETHODIMP nsPrefBranch::PrefIsLocked(const char *aPrefName, PRBool *_retval)
00515 {
00516   const char *pref;
00517   nsresult   rv;
00518 
00519   NS_ENSURE_ARG_POINTER(_retval);
00520 
00521   rv = getValidatedPrefName(aPrefName, &pref);
00522   if (NS_SUCCEEDED(rv)) {
00523     *_retval = PREF_PrefIsLocked(pref);
00524   }
00525   return rv;
00526 }
00527 
00528 NS_IMETHODIMP nsPrefBranch::UnlockPref(const char *aPrefName)
00529 {
00530   const char *pref;
00531   nsresult   rv;
00532 
00533   rv = getValidatedPrefName(aPrefName, &pref);
00534   if (NS_SUCCEEDED(rv)) {
00535     rv = PREF_LockPref(pref, PR_FALSE);
00536   }
00537   return rv;
00538 }
00539 
00540 /* void resetBranch (in string startingAt); */
00541 NS_IMETHODIMP nsPrefBranch::ResetBranch(const char *aStartingAt)
00542 {
00543   return NS_ERROR_NOT_IMPLEMENTED;
00544 }
00545 
00546 NS_IMETHODIMP nsPrefBranch::DeleteBranch(const char *aStartingAt)
00547 {
00548   const char *pref;
00549   nsresult   rv;
00550 
00551   rv = getValidatedPrefName(aStartingAt, &pref);
00552   if (NS_SUCCEEDED(rv)) {
00553     rv = PREF_DeleteBranch(pref);
00554   }
00555   return rv;
00556 }
00557 
00558 NS_IMETHODIMP nsPrefBranch::GetChildList(const char *aStartingAt, PRUint32 *aCount, char ***aChildArray)
00559 {
00560   char**          outArray;
00561   char*           theElement;
00562   PRInt32         numPrefs;
00563   PRInt32         dwIndex;
00564   EnumerateData   ed;
00565   nsAutoVoidArray prefArray;
00566 
00567   NS_ENSURE_ARG_POINTER(aStartingAt);
00568   NS_ENSURE_ARG_POINTER(aCount);
00569   NS_ENSURE_ARG_POINTER(aChildArray);
00570 
00571   if (!gHashTable.ops) {
00572     *aChildArray = nsnull;
00573     *aCount = 0;
00574     return NS_ERROR_NOT_INITIALIZED;
00575   }
00576 
00577   // this will contain a list of all the pref name strings
00578   // allocate on the stack for speed
00579 
00580   ed.parent = getPrefName(aStartingAt);
00581   ed.pref_list = &prefArray;
00582   PL_DHashTableEnumerate(&gHashTable, pref_enumChild, &ed);
00583 
00584   // now that we've built up the list, run the callback on
00585   // all the matching elements
00586   numPrefs = prefArray.Count();
00587 
00588   if (numPrefs) {
00589     outArray = (char **)nsMemory::Alloc(numPrefs * sizeof(char *));
00590     if (!outArray)
00591       return NS_ERROR_OUT_OF_MEMORY;
00592 
00593     for (dwIndex = 0; dwIndex < numPrefs; ++dwIndex) {
00594       // we need to lop off mPrefRoot in case the user is planning to pass this
00595       // back to us because if they do we are going to add mPrefRoot again.
00596       theElement = ((char *)prefArray.ElementAt(dwIndex)) + mPrefRootLength;
00597       outArray[dwIndex] = (char *)nsMemory::Clone(theElement, strlen(theElement) + 1);
00598  
00599       if (!outArray[dwIndex]) {
00600         // we ran out of memory... this is annoying
00601         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(dwIndex, outArray);
00602         return NS_ERROR_OUT_OF_MEMORY;
00603       }
00604     }
00605     *aChildArray = outArray;
00606   } else {
00607     *aChildArray = nsnull;
00608   } /* endif */
00609   *aCount = numPrefs;
00610 
00611   return NS_OK;
00612 }
00613 
00614 
00615 /*
00616  *  nsIPrefBranch2 methods
00617  */
00618 
00619 NS_IMETHODIMP nsPrefBranch::AddObserver(const char *aDomain, nsIObserver *aObserver, PRBool aHoldWeak)
00620 {
00621   PrefCallbackData *pCallback;
00622   const char *pref;
00623 
00624   NS_ENSURE_ARG_POINTER(aDomain);
00625   NS_ENSURE_ARG_POINTER(aObserver);
00626 
00627   if (!mObservers) {
00628     mObservers = new nsAutoVoidArray();
00629     if (nsnull == mObservers)
00630       return NS_ERROR_OUT_OF_MEMORY;
00631   }
00632 
00633   pCallback = (PrefCallbackData *)nsMemory::Alloc(sizeof(PrefCallbackData));
00634   if (nsnull == pCallback)
00635     return NS_ERROR_OUT_OF_MEMORY;
00636 
00637   pCallback->pBranch = NS_STATIC_CAST(nsIPrefBranch *, this);
00638   pCallback->bIsWeakRef = aHoldWeak;
00639 
00640   // hold a weak reference to the observer if so requested
00641   nsCOMPtr<nsISupports> observerRef;
00642   if (aHoldWeak) {
00643     nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver);
00644     if (!weakRefFactory) {
00645       // the caller didn't give us a object that supports weak reference... tell them
00646       nsMemory::Free(pCallback);
00647       return NS_ERROR_INVALID_ARG;
00648     }
00649     nsCOMPtr<nsIWeakReference> tmp = do_GetWeakReference(weakRefFactory);
00650     observerRef = tmp;
00651   } else {
00652     observerRef = aObserver;
00653   }
00654   pCallback->pObserver = observerRef;
00655   NS_ADDREF(pCallback->pObserver);
00656 
00657   mObservers->AppendElement(pCallback);
00658   mObserverDomains.AppendCString(nsCString(aDomain));
00659 
00660   // We must pass a fully qualified preference name to the callback
00661   pref = getPrefName(aDomain); // aDomain == nsnull only possible failure, trapped above
00662   PREF_RegisterCallback(pref, NotifyObserver, pCallback);
00663   return NS_OK;
00664 }
00665 
00666 NS_IMETHODIMP nsPrefBranch::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
00667 {
00668   const char *pref;
00669   PrefCallbackData *pCallback;
00670   PRInt32 count;
00671   PRInt32 i;
00672   nsresult rv;
00673   nsCAutoString domain;
00674 
00675   NS_ENSURE_ARG_POINTER(aDomain);
00676   NS_ENSURE_ARG_POINTER(aObserver);
00677 
00678   if (!mObservers)
00679     return NS_OK;
00680     
00681   // need to find the index of observer, so we can remove it from the domain list too
00682   count = mObservers->Count();
00683   if (count == 0)
00684     return NS_OK;
00685 
00686   for (i = 0; i < count; i++) {
00687     pCallback = (PrefCallbackData *)mObservers->ElementAt(i);
00688     if (pCallback) {
00689      nsCOMPtr<nsISupports> observerRef;
00690      if (pCallback->bIsWeakRef) {
00691        nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver);
00692        if (weakRefFactory) {
00693          nsCOMPtr<nsIWeakReference> tmp = do_GetWeakReference(aObserver);
00694          observerRef = tmp;
00695        }
00696      }
00697      if (!observerRef)
00698        observerRef = aObserver;
00699 
00700       if (pCallback->pObserver == observerRef) {
00701         mObserverDomains.CStringAt(i, domain);
00702         if (domain.Equals(aDomain)) {
00703           // We must pass a fully qualified preference name to remove the callback
00704           pref = getPrefName(aDomain); // aDomain == nsnull only possible failure, trapped above
00705           rv = PREF_UnregisterCallback(pref, NotifyObserver, pCallback);
00706           if (NS_SUCCEEDED(rv)) {
00707             // Remove this observer from our array so that nobody else can remove
00708             // what we're trying to remove ourselves right now.
00709             mObservers->RemoveElementAt(i);
00710             mObserverDomains.RemoveCStringAt(i);
00711             NS_RELEASE(pCallback->pObserver);
00712             nsMemory::Free(pCallback);
00713           }
00714           return rv;
00715         }
00716       }
00717     }
00718   }
00719 
00720   return NS_OK;
00721 }
00722 
00723 NS_IMETHODIMP nsPrefBranch::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
00724 {
00725   // watch for xpcom shutdown and free our observers to eliminate any cyclic references
00726   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
00727     freeObserverList();
00728   }
00729   return NS_OK;
00730 }
00731 
00732 PR_STATIC_CALLBACK(nsresult) NotifyObserver(const char *newpref, void *data)
00733 {
00734   PrefCallbackData *pData = (PrefCallbackData *)data;
00735   nsPrefBranch *prefBranch = NS_STATIC_CAST(nsPrefBranch *, pData->pBranch);
00736 
00737   // remove any root this string may contain so as to not confuse the observer
00738   // by passing them something other than what they passed us as a topic
00739   PRUint32 len = prefBranch->GetRootLength();
00740   nsCAutoString suffix(newpref + len);  
00741 
00742   nsCOMPtr<nsIObserver> observer;
00743   if (pData->bIsWeakRef) {
00744     nsIWeakReference *weakRef = NS_STATIC_CAST(nsIWeakReference *, pData->pObserver);
00745     observer = do_QueryReferent(weakRef);
00746     if (!observer) {
00747       // this weak referenced observer went away, remove them from the list
00748       nsCOMPtr<nsIPrefBranch2> pbi = do_QueryInterface(pData->pBranch);
00749       if (pbi) {
00750         observer = NS_STATIC_CAST(nsIObserver *, pData->pObserver);
00751         pbi->RemoveObserver(newpref, observer);
00752       }
00753       return NS_OK;
00754     }
00755   } else
00756     observer = NS_STATIC_CAST(nsIObserver *, pData->pObserver);
00757 
00758   observer->Observe(pData->pBranch, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
00759                     NS_ConvertASCIItoUCS2(suffix).get());
00760   return NS_OK;
00761 }
00762 
00763 
00764 void nsPrefBranch::freeObserverList(void)
00765 {
00766   const char *pref;
00767   PrefCallbackData *pCallback;
00768 
00769   if (mObservers) {
00770     // unregister the observers
00771     PRInt32 count;
00772 
00773     count = mObservers->Count();
00774     if (count > 0) {
00775       PRInt32 i;
00776       nsCAutoString domain;
00777       for (i = 0; i < count; ++i) {
00778         pCallback = (PrefCallbackData *)mObservers->ElementAt(i);
00779         if (pCallback) {
00780           mObserverDomains.CStringAt(i, domain);
00781           // We must pass a fully qualified preference name to remove the callback
00782           pref = getPrefName(domain.get()); // can't fail because domain must be valid
00783           // Remove this observer from our array so that nobody else can remove
00784           // what we're trying to remove right now.
00785           mObservers->ReplaceElementAt(nsnull, i);
00786           PREF_UnregisterCallback(pref, NotifyObserver, pCallback);
00787           NS_RELEASE(pCallback->pObserver);
00788           nsMemory::Free(pCallback);
00789         }
00790       }
00791 
00792       // now empty the observer domains array in bulk
00793       mObserverDomains.Clear();
00794     }
00795     delete mObservers;
00796     mObservers = 0;
00797   }
00798 }
00799  
00800 nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char *aPrefName, PRUnichar **return_buf)
00801 {
00802   nsresult rv;
00803 
00804   // the default value contains a URL to a .properties file
00805     
00806   nsXPIDLCString propertyFileURL;
00807   rv = PREF_CopyCharPref(aPrefName, getter_Copies(propertyFileURL), PR_TRUE);
00808   if (NS_FAILED(rv))
00809     return rv;
00810     
00811   nsCOMPtr<nsIStringBundleService> bundleService =
00812       do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
00813   if (NS_FAILED(rv))
00814     return rv;
00815 
00816   nsCOMPtr<nsIStringBundle> bundle;
00817   rv = bundleService->CreateBundle(propertyFileURL,
00818                                    getter_AddRefs(bundle));
00819   if (NS_FAILED(rv))
00820     return rv;
00821 
00822   // string names are in unicode
00823   nsAutoString stringId;
00824   stringId.AssignASCII(aPrefName);
00825 
00826   return bundle->GetStringFromName(stringId.get(), return_buf);
00827 }
00828 
00829 const char *nsPrefBranch::getPrefName(const char *aPrefName)
00830 {
00831   // for speed, avoid strcpy if we can:
00832   if (mPrefRoot.IsEmpty())
00833     return aPrefName;
00834 
00835   // isn't there a better way to do this? this is really kind of gross.
00836   mPrefRoot.Truncate(mPrefRootLength);
00837 
00838   // only append if anything to append
00839   if ((nsnull != aPrefName) && (*aPrefName != '\0'))
00840     mPrefRoot.Append(aPrefName);
00841 
00842   return mPrefRoot.get();
00843 }
00844 
00845 nsresult nsPrefBranch::getValidatedPrefName(const char *aPrefName, const char **_retval)
00846 {
00847   static const char capabilityPrefix[] = "capability.";
00848 
00849   NS_ENSURE_ARG_POINTER(aPrefName);
00850   const char *fullPref = getPrefName(aPrefName);
00851 
00852   // now that we have the pref, check it against the ScriptSecurityManager
00853   if ((fullPref[0] == 'c') &&
00854     PL_strncmp(fullPref, capabilityPrefix, sizeof(capabilityPrefix)-1) == 0)
00855   {
00856     nsresult rv;
00857     nsCOMPtr<nsIPrefSecurityCheck> secCheck = 
00858              do_GetService(NS_GLOBAL_PREF_SECURITY_CHECK, &rv);
00859 
00860     if (NS_FAILED(rv))
00861       return NS_ERROR_FAILURE;
00862 
00863     PRBool enabled;
00864     rv = secCheck->CanAccessSecurityPreferences(&enabled);
00865     if (NS_FAILED(rv) || !enabled)
00866       return NS_ERROR_FAILURE;
00867   }
00868 
00869   *_retval = fullPref;
00870   return NS_OK;
00871 }
00872 
00873 PR_STATIC_CALLBACK(PLDHashOperator)
00874 pref_enumChild(PLDHashTable *table, PLDHashEntryHdr *heh,
00875                PRUint32 i, void *arg)
00876 {
00877   PrefHashEntry *he = NS_STATIC_CAST(PrefHashEntry*, heh);
00878   EnumerateData *d = NS_REINTERPRET_CAST(EnumerateData *, arg);
00879   if (PL_strncmp(he->key, d->parent, PL_strlen(d->parent)) == 0) {
00880     d->pref_list->AppendElement((void*)he->key);
00881   }
00882   return PL_DHASH_NEXT;
00883 }
00884 
00885 
00886 /*
00887  * nsISecurityPref methods
00888  *
00889  * Pref access without security check - these are here
00890  * to support nsScriptSecurityManager.
00891  * These functions are part of nsISecurityPref, not nsIPref.
00892  * **PLEASE** do not call these functions from elsewhere
00893  */
00894 NS_IMETHODIMP nsPrefBranch::SecurityGetBoolPref(const char *pref, PRBool * return_val)
00895 {
00896   return PREF_GetBoolPref(getPrefName(pref), return_val, PR_FALSE);
00897 }
00898 
00899 NS_IMETHODIMP nsPrefBranch::SecuritySetBoolPref(const char *pref, PRBool value)
00900 {
00901   return PREF_SetBoolPref(getPrefName(pref), value);
00902 }
00903 
00904 NS_IMETHODIMP nsPrefBranch::SecurityGetCharPref(const char *pref, char ** return_buf)
00905 {
00906   return PREF_CopyCharPref(getPrefName(pref), return_buf, PR_FALSE);
00907 }
00908 
00909 NS_IMETHODIMP nsPrefBranch::SecuritySetCharPref(const char *pref, const char* value)
00910 {
00911   return PREF_SetCharPref(getPrefName(pref), value);
00912 }
00913 
00914 NS_IMETHODIMP nsPrefBranch::SecurityGetIntPref(const char *pref, PRInt32 * return_val)
00915 {
00916   return PREF_GetIntPref(getPrefName(pref), return_val, PR_FALSE);
00917 }
00918 
00919 NS_IMETHODIMP nsPrefBranch::SecuritySetIntPref(const char *pref, PRInt32 value)
00920 {
00921   return PREF_SetIntPref(getPrefName(pref), value);
00922 }
00923 
00924 NS_IMETHODIMP nsPrefBranch::SecurityClearUserPref(const char *pref_name)
00925 {
00926   return PREF_ClearUserPref(getPrefName(pref_name));
00927 }
00928 
00929 //----------------------------------------------------------------------------
00930 // nsPrefLocalizedString
00931 //----------------------------------------------------------------------------
00932 
00933 nsPrefLocalizedString::nsPrefLocalizedString()
00934 {
00935 }
00936 
00937 nsPrefLocalizedString::~nsPrefLocalizedString()
00938 {
00939 }
00940 
00941 
00942 /*
00943  * nsISupports Implementation
00944  */
00945 
00946 NS_IMPL_THREADSAFE_ADDREF(nsPrefLocalizedString)
00947 NS_IMPL_THREADSAFE_RELEASE(nsPrefLocalizedString)
00948 
00949 NS_INTERFACE_MAP_BEGIN(nsPrefLocalizedString)
00950     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefLocalizedString)
00951     NS_INTERFACE_MAP_ENTRY(nsIPrefLocalizedString)
00952     NS_INTERFACE_MAP_ENTRY(nsISupportsString)
00953 NS_INTERFACE_MAP_END
00954 
00955 nsresult nsPrefLocalizedString::Init()
00956 {
00957   nsresult rv;
00958   mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
00959 
00960   return rv;
00961 }
00962 
00963 NS_IMETHODIMP
00964 nsPrefLocalizedString::GetData(PRUnichar** _retval)
00965 {
00966   nsAutoString data;
00967 
00968   nsresult rv = GetData(data);
00969   if (NS_FAILED(rv))
00970     return rv;
00971   
00972   *_retval = ToNewUnicode(data);
00973   if (!*_retval)
00974     return NS_ERROR_OUT_OF_MEMORY;
00975 
00976   return NS_OK;
00977 }
00978 
00979 NS_IMETHODIMP
00980 nsPrefLocalizedString::SetData(const PRUnichar *aData)
00981 {
00982   if (!aData)
00983     return SetData(EmptyString());
00984   return SetData(nsDependentString(aData));
00985 }
00986 
00987 NS_IMETHODIMP
00988 nsPrefLocalizedString::SetDataWithLength(PRUint32 aLength,
00989                                          const PRUnichar* aData)
00990 {
00991   if (!aData)
00992     return SetData(EmptyString());
00993   return SetData(Substring(aData, aData + aLength));
00994 }
00995 
00996 //----------------------------------------------------------------------------
00997 // nsRelativeFilePref
00998 //----------------------------------------------------------------------------
00999 
01000 NS_IMPL_THREADSAFE_ISUPPORTS1(nsRelativeFilePref, nsIRelativeFilePref)
01001 
01002 nsRelativeFilePref::nsRelativeFilePref()
01003 {
01004 }
01005 
01006 nsRelativeFilePref::~nsRelativeFilePref()
01007 {
01008 }
01009 
01010 NS_IMETHODIMP nsRelativeFilePref::GetFile(nsILocalFile * *aFile)
01011 {
01012     NS_ENSURE_ARG_POINTER(aFile);
01013     *aFile = mFile;
01014     NS_IF_ADDREF(*aFile);
01015     return NS_OK;
01016 }
01017 
01018 NS_IMETHODIMP nsRelativeFilePref::SetFile(nsILocalFile * aFile)
01019 {
01020     mFile = aFile;
01021     return NS_OK;
01022 }
01023 
01024 NS_IMETHODIMP nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey)
01025 {
01026     aRelativeToKey.Assign(mRelativeToKey);
01027     return NS_OK;
01028 }
01029 
01030 NS_IMETHODIMP nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey)
01031 {
01032     mRelativeToKey.Assign(aRelativeToKey);
01033     return NS_OK;
01034 }