1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/modules/libpref/src/nsPrefBranch.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,898 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/dom/ContentChild.h" 1.10 +#include "nsXULAppAPI.h" 1.11 + 1.12 +#include "nsPrefBranch.h" 1.13 +#include "nsILocalFile.h" // nsILocalFile used for backwards compatibility 1.14 +#include "nsIObserverService.h" 1.15 +#include "nsXPCOM.h" 1.16 +#include "nsISupportsPrimitives.h" 1.17 +#include "nsIDirectoryService.h" 1.18 +#include "nsString.h" 1.19 +#include "nsReadableUtils.h" 1.20 +#include "nsXPIDLString.h" 1.21 +#include "nsPrintfCString.h" 1.22 +#include "nsIStringBundle.h" 1.23 +#include "prefapi.h" 1.24 +#include "pldhash.h" 1.25 + 1.26 +#include "nsCRT.h" 1.27 +#include "mozilla/Services.h" 1.28 + 1.29 +#include "prefapi_private_data.h" 1.30 + 1.31 +#ifdef MOZ_CRASHREPORTER 1.32 +#include "nsICrashReporter.h" 1.33 +#endif 1.34 + 1.35 +#include "nsIConsoleService.h" 1.36 + 1.37 +#ifdef DEBUG 1.38 +#define ENSURE_MAIN_PROCESS(message, pref) do { \ 1.39 + if (GetContentChild()) { \ 1.40 + nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref); \ 1.41 + NS_ERROR(msg.get()); \ 1.42 + return NS_ERROR_NOT_AVAILABLE; \ 1.43 + } \ 1.44 +} while (0); 1.45 +#else 1.46 +#define ENSURE_MAIN_PROCESS(message, pref) \ 1.47 + if (GetContentChild()) { \ 1.48 + return NS_ERROR_NOT_AVAILABLE; \ 1.49 + } 1.50 +#endif 1.51 + 1.52 +// Definitions 1.53 +struct EnumerateData { 1.54 + const char *parent; 1.55 + nsTArray<nsCString> *pref_list; 1.56 +}; 1.57 + 1.58 +// Prototypes 1.59 +static PLDHashOperator 1.60 + pref_enumChild(PLDHashTable *table, PLDHashEntryHdr *heh, 1.61 + uint32_t i, void *arg); 1.62 + 1.63 +using mozilla::dom::ContentChild; 1.64 + 1.65 +static ContentChild* 1.66 +GetContentChild() 1.67 +{ 1.68 + if (XRE_GetProcessType() == GeckoProcessType_Content) { 1.69 + ContentChild* cpc = ContentChild::GetSingleton(); 1.70 + if (!cpc) { 1.71 + NS_RUNTIMEABORT("Content Protocol is NULL! We're going to crash!"); 1.72 + } 1.73 + return cpc; 1.74 + } 1.75 + return nullptr; 1.76 +} 1.77 + 1.78 +/* 1.79 + * Constructor/Destructor 1.80 + */ 1.81 + 1.82 +nsPrefBranch::nsPrefBranch(const char *aPrefRoot, bool aDefaultBranch) 1.83 +{ 1.84 + mPrefRoot = aPrefRoot; 1.85 + mPrefRootLength = mPrefRoot.Length(); 1.86 + mIsDefault = aDefaultBranch; 1.87 + mFreeingObserverList = false; 1.88 + 1.89 + nsCOMPtr<nsIObserverService> observerService = 1.90 + mozilla::services::GetObserverService(); 1.91 + if (observerService) { 1.92 + ++mRefCnt; // Our refcnt must be > 0 when we call this, or we'll get deleted! 1.93 + // add weak so we don't have to clean up at shutdown 1.94 + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true); 1.95 + --mRefCnt; 1.96 + } 1.97 +} 1.98 + 1.99 +nsPrefBranch::~nsPrefBranch() 1.100 +{ 1.101 + freeObserverList(); 1.102 + 1.103 + nsCOMPtr<nsIObserverService> observerService = 1.104 + mozilla::services::GetObserverService(); 1.105 + if (observerService) 1.106 + observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); 1.107 +} 1.108 + 1.109 + 1.110 +/* 1.111 + * nsISupports Implementation 1.112 + */ 1.113 + 1.114 +NS_IMPL_ADDREF(nsPrefBranch) 1.115 +NS_IMPL_RELEASE(nsPrefBranch) 1.116 + 1.117 +NS_INTERFACE_MAP_BEGIN(nsPrefBranch) 1.118 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefBranch) 1.119 + NS_INTERFACE_MAP_ENTRY(nsIPrefBranch) 1.120 + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranch2, !mIsDefault) 1.121 + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranchInternal, !mIsDefault) 1.122 + NS_INTERFACE_MAP_ENTRY(nsIObserver) 1.123 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.124 +NS_INTERFACE_MAP_END 1.125 + 1.126 + 1.127 +/* 1.128 + * nsIPrefBranch Implementation 1.129 + */ 1.130 + 1.131 +NS_IMETHODIMP nsPrefBranch::GetRoot(char **aRoot) 1.132 +{ 1.133 + NS_ENSURE_ARG_POINTER(aRoot); 1.134 + mPrefRoot.Truncate(mPrefRootLength); 1.135 + *aRoot = ToNewCString(mPrefRoot); 1.136 + return NS_OK; 1.137 +} 1.138 + 1.139 +NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, int32_t *_retval) 1.140 +{ 1.141 + NS_ENSURE_ARG(aPrefName); 1.142 + const char *pref = getPrefName(aPrefName); 1.143 + *_retval = PREF_GetPrefType(pref); 1.144 + return NS_OK; 1.145 +} 1.146 + 1.147 +NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, bool *_retval) 1.148 +{ 1.149 + NS_ENSURE_ARG(aPrefName); 1.150 + const char *pref = getPrefName(aPrefName); 1.151 + return PREF_GetBoolPref(pref, _retval, mIsDefault); 1.152 +} 1.153 + 1.154 +NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, bool aValue) 1.155 +{ 1.156 + ENSURE_MAIN_PROCESS("Cannot SetBoolPref from content process:", aPrefName); 1.157 + NS_ENSURE_ARG(aPrefName); 1.158 + const char *pref = getPrefName(aPrefName); 1.159 + return PREF_SetBoolPref(pref, aValue, mIsDefault); 1.160 +} 1.161 + 1.162 +NS_IMETHODIMP nsPrefBranch::GetFloatPref(const char *aPrefName, float *_retval) 1.163 +{ 1.164 + NS_ENSURE_ARG(aPrefName); 1.165 + const char *pref = getPrefName(aPrefName); 1.166 + nsAutoCString stringVal; 1.167 + nsresult rv = GetCharPref(pref, getter_Copies(stringVal)); 1.168 + if (NS_SUCCEEDED(rv)) { 1.169 + *_retval = stringVal.ToFloat(&rv); 1.170 + } 1.171 + 1.172 + return rv; 1.173 +} 1.174 + 1.175 +NS_IMETHODIMP nsPrefBranch::GetCharPref(const char *aPrefName, char **_retval) 1.176 +{ 1.177 + NS_ENSURE_ARG(aPrefName); 1.178 + const char *pref = getPrefName(aPrefName); 1.179 + return PREF_CopyCharPref(pref, _retval, mIsDefault); 1.180 +} 1.181 + 1.182 +NS_IMETHODIMP nsPrefBranch::SetCharPref(const char *aPrefName, const char *aValue) 1.183 +{ 1.184 + nsresult rv = CheckSanityOfStringLength(aPrefName, aValue); 1.185 + if (NS_FAILED(rv)) { 1.186 + return rv; 1.187 + } 1.188 + return SetCharPrefInternal(aPrefName, aValue); 1.189 +} 1.190 + 1.191 +nsresult nsPrefBranch::SetCharPrefInternal(const char *aPrefName, const char *aValue) 1.192 + 1.193 +{ 1.194 + ENSURE_MAIN_PROCESS("Cannot SetCharPref from content process:", aPrefName); 1.195 + NS_ENSURE_ARG(aPrefName); 1.196 + NS_ENSURE_ARG(aValue); 1.197 + const char *pref = getPrefName(aPrefName); 1.198 + return PREF_SetCharPref(pref, aValue, mIsDefault); 1.199 +} 1.200 + 1.201 +NS_IMETHODIMP nsPrefBranch::GetIntPref(const char *aPrefName, int32_t *_retval) 1.202 +{ 1.203 + NS_ENSURE_ARG(aPrefName); 1.204 + const char *pref = getPrefName(aPrefName); 1.205 + return PREF_GetIntPref(pref, _retval, mIsDefault); 1.206 +} 1.207 + 1.208 +NS_IMETHODIMP nsPrefBranch::SetIntPref(const char *aPrefName, int32_t aValue) 1.209 +{ 1.210 + ENSURE_MAIN_PROCESS("Cannot SetIntPref from content process:", aPrefName); 1.211 + NS_ENSURE_ARG(aPrefName); 1.212 + const char *pref = getPrefName(aPrefName); 1.213 + return PREF_SetIntPref(pref, aValue, mIsDefault); 1.214 +} 1.215 + 1.216 +NS_IMETHODIMP nsPrefBranch::GetComplexValue(const char *aPrefName, const nsIID & aType, void **_retval) 1.217 +{ 1.218 + NS_ENSURE_ARG(aPrefName); 1.219 + 1.220 + nsresult rv; 1.221 + nsXPIDLCString utf8String; 1.222 + 1.223 + // we have to do this one first because it's different than all the rest 1.224 + if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) { 1.225 + nsCOMPtr<nsIPrefLocalizedString> theString(do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv)); 1.226 + if (NS_FAILED(rv)) return rv; 1.227 + 1.228 + const char *pref = getPrefName(aPrefName); 1.229 + bool bNeedDefault = false; 1.230 + 1.231 + if (mIsDefault) { 1.232 + bNeedDefault = true; 1.233 + } else { 1.234 + // if there is no user (or locked) value 1.235 + if (!PREF_HasUserPref(pref) && !PREF_PrefIsLocked(pref)) { 1.236 + bNeedDefault = true; 1.237 + } 1.238 + } 1.239 + 1.240 + // if we need to fetch the default value, do that instead, otherwise use the 1.241 + // value we pulled in at the top of this function 1.242 + if (bNeedDefault) { 1.243 + nsXPIDLString utf16String; 1.244 + rv = GetDefaultFromPropertiesFile(pref, getter_Copies(utf16String)); 1.245 + if (NS_SUCCEEDED(rv)) { 1.246 + theString->SetData(utf16String.get()); 1.247 + } 1.248 + } else { 1.249 + rv = GetCharPref(aPrefName, getter_Copies(utf8String)); 1.250 + if (NS_SUCCEEDED(rv)) { 1.251 + theString->SetData(NS_ConvertUTF8toUTF16(utf8String).get()); 1.252 + } 1.253 + } 1.254 + 1.255 + if (NS_SUCCEEDED(rv)) { 1.256 + theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(_retval)); 1.257 + } 1.258 + 1.259 + return rv; 1.260 + } 1.261 + 1.262 + // if we can't get the pref, there's no point in being here 1.263 + rv = GetCharPref(aPrefName, getter_Copies(utf8String)); 1.264 + if (NS_FAILED(rv)) { 1.265 + return rv; 1.266 + } 1.267 + 1.268 + // also check nsILocalFile, for backwards compatibility 1.269 + if (aType.Equals(NS_GET_IID(nsIFile)) || aType.Equals(NS_GET_IID(nsILocalFile))) { 1.270 + if (GetContentChild()) { 1.271 + NS_ERROR("cannot get nsIFile pref from content process"); 1.272 + return NS_ERROR_NOT_AVAILABLE; 1.273 + } 1.274 + 1.275 + nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); 1.276 + 1.277 + if (NS_SUCCEEDED(rv)) { 1.278 + rv = file->SetPersistentDescriptor(utf8String); 1.279 + if (NS_SUCCEEDED(rv)) { 1.280 + file.forget(reinterpret_cast<nsIFile**>(_retval)); 1.281 + return NS_OK; 1.282 + } 1.283 + } 1.284 + return rv; 1.285 + } 1.286 + 1.287 + if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) { 1.288 + if (GetContentChild()) { 1.289 + NS_ERROR("cannot get nsIRelativeFilePref from content process"); 1.290 + return NS_ERROR_NOT_AVAILABLE; 1.291 + } 1.292 + 1.293 + nsACString::const_iterator keyBegin, strEnd; 1.294 + utf8String.BeginReading(keyBegin); 1.295 + utf8String.EndReading(strEnd); 1.296 + 1.297 + // The pref has the format: [fromKey]a/b/c 1.298 + if (*keyBegin++ != '[') 1.299 + return NS_ERROR_FAILURE; 1.300 + nsACString::const_iterator keyEnd(keyBegin); 1.301 + if (!FindCharInReadable(']', keyEnd, strEnd)) 1.302 + return NS_ERROR_FAILURE; 1.303 + nsAutoCString key(Substring(keyBegin, keyEnd)); 1.304 + 1.305 + nsCOMPtr<nsIFile> fromFile; 1.306 + nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv)); 1.307 + if (NS_FAILED(rv)) 1.308 + return rv; 1.309 + rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile), getter_AddRefs(fromFile)); 1.310 + if (NS_FAILED(rv)) 1.311 + return rv; 1.312 + 1.313 + nsCOMPtr<nsIFile> theFile; 1.314 + rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(theFile)); 1.315 + if (NS_FAILED(rv)) 1.316 + return rv; 1.317 + rv = theFile->SetRelativeDescriptor(fromFile, Substring(++keyEnd, strEnd)); 1.318 + if (NS_FAILED(rv)) 1.319 + return rv; 1.320 + nsCOMPtr<nsIRelativeFilePref> relativePref; 1.321 + rv = NS_NewRelativeFilePref(theFile, key, getter_AddRefs(relativePref)); 1.322 + if (NS_FAILED(rv)) 1.323 + return rv; 1.324 + 1.325 + relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(_retval)); 1.326 + return NS_OK; 1.327 + } 1.328 + 1.329 + if (aType.Equals(NS_GET_IID(nsISupportsString))) { 1.330 + nsCOMPtr<nsISupportsString> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv)); 1.331 + 1.332 + if (NS_SUCCEEDED(rv)) { 1.333 + // Debugging to see why we end up with very long strings here with 1.334 + // some addons, see bug 836263. 1.335 + nsAutoString wdata; 1.336 + if (!AppendUTF8toUTF16(utf8String, wdata, mozilla::fallible_t())) { 1.337 +#ifdef MOZ_CRASHREPORTER 1.338 + nsCOMPtr<nsICrashReporter> cr = 1.339 + do_GetService("@mozilla.org/toolkit/crash-reporter;1"); 1.340 + if (cr) { 1.341 + cr->AnnotateCrashReport(NS_LITERAL_CSTRING("bug836263-size"), 1.342 + nsPrintfCString("%x", utf8String.Length())); 1.343 + cr->RegisterAppMemory(uint64_t(utf8String.BeginReading()), 1.344 + std::min(0x1000U, utf8String.Length())); 1.345 + } 1.346 +#endif 1.347 + NS_RUNTIMEABORT("bug836263"); 1.348 + } 1.349 + theString->SetData(wdata); 1.350 + theString.forget(reinterpret_cast<nsISupportsString**>(_retval)); 1.351 + } 1.352 + return rv; 1.353 + } 1.354 + 1.355 + NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type"); 1.356 + return NS_NOINTERFACE; 1.357 +} 1.358 + 1.359 +nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const char* aValue) { 1.360 + if (!aValue) { 1.361 + return NS_OK; 1.362 + } 1.363 + return CheckSanityOfStringLength(aPrefName, strlen(aValue)); 1.364 +} 1.365 + 1.366 +nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const nsAString& aValue) { 1.367 + return CheckSanityOfStringLength(aPrefName, aValue.Length()); 1.368 +} 1.369 + 1.370 +nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const uint32_t aLength) { 1.371 + if (aLength > MAX_PREF_LENGTH) { 1.372 + return NS_ERROR_ILLEGAL_VALUE; 1.373 + } 1.374 + if (aLength <= MAX_ADVISABLE_PREF_LENGTH) { 1.375 + return NS_OK; 1.376 + } 1.377 + nsresult rv; 1.378 + nsCOMPtr<nsIConsoleService> console = do_GetService("@mozilla.org/consoleservice;1", &rv); 1.379 + if (NS_FAILED(rv)) { 1.380 + return rv; 1.381 + } 1.382 + nsAutoCString message(nsPrintfCString("Warning: attempting to write %d bytes to preference %s. This is bad for general performance and memory usage. Such an amount of data should rather be written to an external file.", 1.383 + aLength, 1.384 + aPrefName)); 1.385 + rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get()); 1.386 + if (NS_FAILED(rv)) { 1.387 + return rv; 1.388 + } 1.389 + return NS_OK; 1.390 +} 1.391 + 1.392 + 1.393 +NS_IMETHODIMP nsPrefBranch::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue) 1.394 +{ 1.395 + ENSURE_MAIN_PROCESS("Cannot SetComplexValue from content process:", aPrefName); 1.396 + NS_ENSURE_ARG(aPrefName); 1.397 + 1.398 + nsresult rv = NS_NOINTERFACE; 1.399 + 1.400 + // also check nsILocalFile, for backwards compatibility 1.401 + if (aType.Equals(NS_GET_IID(nsIFile)) || aType.Equals(NS_GET_IID(nsILocalFile))) { 1.402 + nsCOMPtr<nsIFile> file = do_QueryInterface(aValue); 1.403 + if (!file) 1.404 + return NS_NOINTERFACE; 1.405 + nsAutoCString descriptorString; 1.406 + 1.407 + rv = file->GetPersistentDescriptor(descriptorString); 1.408 + if (NS_SUCCEEDED(rv)) { 1.409 + rv = SetCharPrefInternal(aPrefName, descriptorString.get()); 1.410 + } 1.411 + return rv; 1.412 + } 1.413 + 1.414 + if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) { 1.415 + nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue); 1.416 + if (!relFilePref) 1.417 + return NS_NOINTERFACE; 1.418 + 1.419 + nsCOMPtr<nsIFile> file; 1.420 + relFilePref->GetFile(getter_AddRefs(file)); 1.421 + if (!file) 1.422 + return NS_NOINTERFACE; 1.423 + nsAutoCString relativeToKey; 1.424 + (void) relFilePref->GetRelativeToKey(relativeToKey); 1.425 + 1.426 + nsCOMPtr<nsIFile> relativeToFile; 1.427 + nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv)); 1.428 + if (NS_FAILED(rv)) 1.429 + return rv; 1.430 + rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile), getter_AddRefs(relativeToFile)); 1.431 + if (NS_FAILED(rv)) 1.432 + return rv; 1.433 + 1.434 + nsAutoCString relDescriptor; 1.435 + rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor); 1.436 + if (NS_FAILED(rv)) 1.437 + return rv; 1.438 + 1.439 + nsAutoCString descriptorString; 1.440 + descriptorString.Append('['); 1.441 + descriptorString.Append(relativeToKey); 1.442 + descriptorString.Append(']'); 1.443 + descriptorString.Append(relDescriptor); 1.444 + return SetCharPrefInternal(aPrefName, descriptorString.get()); 1.445 + } 1.446 + 1.447 + if (aType.Equals(NS_GET_IID(nsISupportsString))) { 1.448 + nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue); 1.449 + 1.450 + if (theString) { 1.451 + nsString wideString; 1.452 + 1.453 + rv = theString->GetData(wideString); 1.454 + if (NS_SUCCEEDED(rv)) { 1.455 + // Check sanity of string length before any lengthy conversion 1.456 + rv = CheckSanityOfStringLength(aPrefName, wideString); 1.457 + if (NS_FAILED(rv)) { 1.458 + return rv; 1.459 + } 1.460 + rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get()); 1.461 + } 1.462 + } 1.463 + return rv; 1.464 + } 1.465 + 1.466 + if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) { 1.467 + nsCOMPtr<nsIPrefLocalizedString> theString = do_QueryInterface(aValue); 1.468 + 1.469 + if (theString) { 1.470 + nsXPIDLString wideString; 1.471 + 1.472 + rv = theString->GetData(getter_Copies(wideString)); 1.473 + if (NS_SUCCEEDED(rv)) { 1.474 + // Check sanity of string length before any lengthy conversion 1.475 + rv = CheckSanityOfStringLength(aPrefName, wideString); 1.476 + if (NS_FAILED(rv)) { 1.477 + return rv; 1.478 + } 1.479 + rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get()); 1.480 + } 1.481 + } 1.482 + return rv; 1.483 + } 1.484 + 1.485 + NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type"); 1.486 + return NS_NOINTERFACE; 1.487 +} 1.488 + 1.489 +NS_IMETHODIMP nsPrefBranch::ClearUserPref(const char *aPrefName) 1.490 +{ 1.491 + ENSURE_MAIN_PROCESS("Cannot ClearUserPref from content process:", aPrefName); 1.492 + NS_ENSURE_ARG(aPrefName); 1.493 + const char *pref = getPrefName(aPrefName); 1.494 + return PREF_ClearUserPref(pref); 1.495 +} 1.496 + 1.497 +NS_IMETHODIMP nsPrefBranch::PrefHasUserValue(const char *aPrefName, bool *_retval) 1.498 +{ 1.499 + NS_ENSURE_ARG_POINTER(_retval); 1.500 + NS_ENSURE_ARG(aPrefName); 1.501 + const char *pref = getPrefName(aPrefName); 1.502 + *_retval = PREF_HasUserPref(pref); 1.503 + return NS_OK; 1.504 +} 1.505 + 1.506 +NS_IMETHODIMP nsPrefBranch::LockPref(const char *aPrefName) 1.507 +{ 1.508 + ENSURE_MAIN_PROCESS("Cannot LockPref from content process:", aPrefName); 1.509 + NS_ENSURE_ARG(aPrefName); 1.510 + const char *pref = getPrefName(aPrefName); 1.511 + return PREF_LockPref(pref, true); 1.512 +} 1.513 + 1.514 +NS_IMETHODIMP nsPrefBranch::PrefIsLocked(const char *aPrefName, bool *_retval) 1.515 +{ 1.516 + ENSURE_MAIN_PROCESS("Cannot check PrefIsLocked from content process:", aPrefName); 1.517 + NS_ENSURE_ARG_POINTER(_retval); 1.518 + NS_ENSURE_ARG(aPrefName); 1.519 + const char *pref = getPrefName(aPrefName); 1.520 + *_retval = PREF_PrefIsLocked(pref); 1.521 + return NS_OK; 1.522 +} 1.523 + 1.524 +NS_IMETHODIMP nsPrefBranch::UnlockPref(const char *aPrefName) 1.525 +{ 1.526 + ENSURE_MAIN_PROCESS("Cannot UnlockPref from content process:", aPrefName); 1.527 + NS_ENSURE_ARG(aPrefName); 1.528 + const char *pref = getPrefName(aPrefName); 1.529 + return PREF_LockPref(pref, false); 1.530 +} 1.531 + 1.532 +/* void resetBranch (in string startingAt); */ 1.533 +NS_IMETHODIMP nsPrefBranch::ResetBranch(const char *aStartingAt) 1.534 +{ 1.535 + return NS_ERROR_NOT_IMPLEMENTED; 1.536 +} 1.537 + 1.538 +NS_IMETHODIMP nsPrefBranch::DeleteBranch(const char *aStartingAt) 1.539 +{ 1.540 + ENSURE_MAIN_PROCESS("Cannot DeleteBranch from content process:", aStartingAt); 1.541 + NS_ENSURE_ARG(aStartingAt); 1.542 + const char *pref = getPrefName(aStartingAt); 1.543 + return PREF_DeleteBranch(pref); 1.544 +} 1.545 + 1.546 +NS_IMETHODIMP nsPrefBranch::GetChildList(const char *aStartingAt, uint32_t *aCount, char ***aChildArray) 1.547 +{ 1.548 + char **outArray; 1.549 + int32_t numPrefs; 1.550 + int32_t dwIndex; 1.551 + EnumerateData ed; 1.552 + nsAutoTArray<nsCString, 32> prefArray; 1.553 + 1.554 + NS_ENSURE_ARG(aStartingAt); 1.555 + NS_ENSURE_ARG_POINTER(aCount); 1.556 + NS_ENSURE_ARG_POINTER(aChildArray); 1.557 + 1.558 + *aChildArray = nullptr; 1.559 + *aCount = 0; 1.560 + 1.561 + if (!gHashTable.ops) 1.562 + return NS_ERROR_NOT_INITIALIZED; 1.563 + 1.564 + // this will contain a list of all the pref name strings 1.565 + // allocate on the stack for speed 1.566 + 1.567 + ed.parent = getPrefName(aStartingAt); 1.568 + ed.pref_list = &prefArray; 1.569 + PL_DHashTableEnumerate(&gHashTable, pref_enumChild, &ed); 1.570 + 1.571 + // now that we've built up the list, run the callback on 1.572 + // all the matching elements 1.573 + numPrefs = prefArray.Length(); 1.574 + 1.575 + if (numPrefs) { 1.576 + outArray = (char **)nsMemory::Alloc(numPrefs * sizeof(char *)); 1.577 + if (!outArray) 1.578 + return NS_ERROR_OUT_OF_MEMORY; 1.579 + 1.580 + for (dwIndex = 0; dwIndex < numPrefs; ++dwIndex) { 1.581 + // we need to lop off mPrefRoot in case the user is planning to pass this 1.582 + // back to us because if they do we are going to add mPrefRoot again. 1.583 + const nsCString& element = prefArray[dwIndex]; 1.584 + outArray[dwIndex] = (char *)nsMemory::Clone( 1.585 + element.get() + mPrefRootLength, element.Length() - mPrefRootLength + 1); 1.586 + 1.587 + if (!outArray[dwIndex]) { 1.588 + // we ran out of memory... this is annoying 1.589 + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(dwIndex, outArray); 1.590 + return NS_ERROR_OUT_OF_MEMORY; 1.591 + } 1.592 + } 1.593 + *aChildArray = outArray; 1.594 + } 1.595 + *aCount = numPrefs; 1.596 + 1.597 + return NS_OK; 1.598 +} 1.599 + 1.600 +NS_IMETHODIMP nsPrefBranch::AddObserver(const char *aDomain, nsIObserver *aObserver, bool aHoldWeak) 1.601 +{ 1.602 + PrefCallback *pCallback; 1.603 + const char *pref; 1.604 + 1.605 + NS_ENSURE_ARG(aDomain); 1.606 + NS_ENSURE_ARG(aObserver); 1.607 + 1.608 + // hold a weak reference to the observer if so requested 1.609 + if (aHoldWeak) { 1.610 + nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver); 1.611 + if (!weakRefFactory) { 1.612 + // the caller didn't give us a object that supports weak reference... tell them 1.613 + return NS_ERROR_INVALID_ARG; 1.614 + } 1.615 + 1.616 + // Construct a PrefCallback with a weak reference to the observer. 1.617 + pCallback = new PrefCallback(aDomain, weakRefFactory, this); 1.618 + 1.619 + } else { 1.620 + // Construct a PrefCallback with a strong reference to the observer. 1.621 + pCallback = new PrefCallback(aDomain, aObserver, this); 1.622 + } 1.623 + 1.624 + if (mObservers.Get(pCallback)) { 1.625 + NS_WARNING("Ignoring duplicate observer."); 1.626 + delete pCallback; 1.627 + return NS_OK; 1.628 + } 1.629 + 1.630 + mObservers.Put(pCallback, pCallback); 1.631 + 1.632 + // We must pass a fully qualified preference name to the callback 1.633 + // aDomain == nullptr is the only possible failure, and we trapped it with 1.634 + // NS_ENSURE_ARG above. 1.635 + pref = getPrefName(aDomain); 1.636 + PREF_RegisterCallback(pref, NotifyObserver, pCallback); 1.637 + return NS_OK; 1.638 +} 1.639 + 1.640 +NS_IMETHODIMP nsPrefBranch::RemoveObserver(const char *aDomain, nsIObserver *aObserver) 1.641 +{ 1.642 + NS_ENSURE_ARG(aDomain); 1.643 + NS_ENSURE_ARG(aObserver); 1.644 + 1.645 + nsresult rv = NS_OK; 1.646 + 1.647 + // If we're in the middle of a call to freeObserverList, don't process this 1.648 + // RemoveObserver call -- the observer in question will be removed soon, if 1.649 + // it hasn't been already. 1.650 + // 1.651 + // It's important that we don't touch mObservers in any way -- even a Get() 1.652 + // which retuns null might cause the hashtable to resize itself, which will 1.653 + // break the Enumerator in freeObserverList. 1.654 + if (mFreeingObserverList) 1.655 + return NS_OK; 1.656 + 1.657 + // Remove the relevant PrefCallback from mObservers and get an owning 1.658 + // pointer to it. Unregister the callback first, and then let the owning 1.659 + // pointer go out of scope and destroy the callback. 1.660 + PrefCallback key(aDomain, aObserver, this); 1.661 + nsAutoPtr<PrefCallback> pCallback; 1.662 + mObservers.RemoveAndForget(&key, pCallback); 1.663 + if (pCallback) { 1.664 + // aDomain == nullptr is the only possible failure, trapped above 1.665 + const char *pref = getPrefName(aDomain); 1.666 + rv = PREF_UnregisterCallback(pref, NotifyObserver, pCallback); 1.667 + } 1.668 + 1.669 + return rv; 1.670 +} 1.671 + 1.672 +NS_IMETHODIMP nsPrefBranch::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) 1.673 +{ 1.674 + // watch for xpcom shutdown and free our observers to eliminate any cyclic references 1.675 + if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { 1.676 + freeObserverList(); 1.677 + } 1.678 + return NS_OK; 1.679 +} 1.680 + 1.681 +/* static */ 1.682 +void nsPrefBranch::NotifyObserver(const char *newpref, void *data) 1.683 +{ 1.684 + PrefCallback *pCallback = (PrefCallback *)data; 1.685 + 1.686 + nsCOMPtr<nsIObserver> observer = pCallback->GetObserver(); 1.687 + if (!observer) { 1.688 + // The observer has expired. Let's remove this callback. 1.689 + pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback); 1.690 + return; 1.691 + } 1.692 + 1.693 + // remove any root this string may contain so as to not confuse the observer 1.694 + // by passing them something other than what they passed us as a topic 1.695 + uint32_t len = pCallback->GetPrefBranch()->GetRootLength(); 1.696 + nsAutoCString suffix(newpref + len); 1.697 + 1.698 + observer->Observe(static_cast<nsIPrefBranch *>(pCallback->GetPrefBranch()), 1.699 + NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, 1.700 + NS_ConvertASCIItoUTF16(suffix).get()); 1.701 +} 1.702 + 1.703 +PLDHashOperator 1.704 +FreeObserverFunc(PrefCallback *aKey, 1.705 + nsAutoPtr<PrefCallback> &aCallback, 1.706 + void *aArgs) 1.707 +{ 1.708 + // Calling NS_RELEASE below might trigger a call to 1.709 + // nsPrefBranch::RemoveObserver, since some classes remove themselves from 1.710 + // the pref branch on destruction. We don't need to worry about this causing 1.711 + // double-frees, however, because freeObserverList sets mFreeingObserverList 1.712 + // to true, which prevents RemoveObserver calls from doing anything. 1.713 + 1.714 + nsPrefBranch *prefBranch = aCallback->GetPrefBranch(); 1.715 + const char *pref = prefBranch->getPrefName(aCallback->GetDomain().get()); 1.716 + PREF_UnregisterCallback(pref, nsPrefBranch::NotifyObserver, aCallback); 1.717 + 1.718 + return PL_DHASH_REMOVE; 1.719 +} 1.720 + 1.721 +void nsPrefBranch::freeObserverList(void) 1.722 +{ 1.723 + // We need to prevent anyone from modifying mObservers while we're 1.724 + // enumerating over it. In particular, some clients will call 1.725 + // RemoveObserver() when they're destructed; we need to keep those calls from 1.726 + // touching mObservers. 1.727 + mFreeingObserverList = true; 1.728 + mObservers.Enumerate(&FreeObserverFunc, nullptr); 1.729 + mFreeingObserverList = false; 1.730 +} 1.731 + 1.732 +void 1.733 +nsPrefBranch::RemoveExpiredCallback(PrefCallback *aCallback) 1.734 +{ 1.735 + NS_PRECONDITION(aCallback->IsExpired(), "Callback should be expired."); 1.736 + mObservers.Remove(aCallback); 1.737 +} 1.738 + 1.739 +nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char *aPrefName, char16_t **return_buf) 1.740 +{ 1.741 + nsresult rv; 1.742 + 1.743 + // the default value contains a URL to a .properties file 1.744 + 1.745 + nsXPIDLCString propertyFileURL; 1.746 + rv = PREF_CopyCharPref(aPrefName, getter_Copies(propertyFileURL), true); 1.747 + if (NS_FAILED(rv)) 1.748 + return rv; 1.749 + 1.750 + nsCOMPtr<nsIStringBundleService> bundleService = 1.751 + mozilla::services::GetStringBundleService(); 1.752 + if (!bundleService) 1.753 + return NS_ERROR_FAILURE; 1.754 + 1.755 + nsCOMPtr<nsIStringBundle> bundle; 1.756 + rv = bundleService->CreateBundle(propertyFileURL, 1.757 + getter_AddRefs(bundle)); 1.758 + if (NS_FAILED(rv)) 1.759 + return rv; 1.760 + 1.761 + // string names are in unicode 1.762 + nsAutoString stringId; 1.763 + stringId.AssignASCII(aPrefName); 1.764 + 1.765 + return bundle->GetStringFromName(stringId.get(), return_buf); 1.766 +} 1.767 + 1.768 +const char *nsPrefBranch::getPrefName(const char *aPrefName) 1.769 +{ 1.770 + NS_ASSERTION(aPrefName, "null pref name!"); 1.771 + 1.772 + // for speed, avoid strcpy if we can: 1.773 + if (mPrefRoot.IsEmpty()) 1.774 + return aPrefName; 1.775 + 1.776 + // isn't there a better way to do this? this is really kind of gross. 1.777 + mPrefRoot.Truncate(mPrefRootLength); 1.778 + mPrefRoot.Append(aPrefName); 1.779 + return mPrefRoot.get(); 1.780 +} 1.781 + 1.782 +static PLDHashOperator 1.783 +pref_enumChild(PLDHashTable *table, PLDHashEntryHdr *heh, 1.784 + uint32_t i, void *arg) 1.785 +{ 1.786 + PrefHashEntry *he = static_cast<PrefHashEntry*>(heh); 1.787 + EnumerateData *d = reinterpret_cast<EnumerateData *>(arg); 1.788 + if (strncmp(he->key, d->parent, strlen(d->parent)) == 0) { 1.789 + d->pref_list->AppendElement(he->key); 1.790 + } 1.791 + return PL_DHASH_NEXT; 1.792 +} 1.793 + 1.794 +//---------------------------------------------------------------------------- 1.795 +// nsPrefLocalizedString 1.796 +//---------------------------------------------------------------------------- 1.797 + 1.798 +nsPrefLocalizedString::nsPrefLocalizedString() 1.799 +{ 1.800 +} 1.801 + 1.802 +nsPrefLocalizedString::~nsPrefLocalizedString() 1.803 +{ 1.804 +} 1.805 + 1.806 + 1.807 +/* 1.808 + * nsISupports Implementation 1.809 + */ 1.810 + 1.811 +NS_IMPL_ADDREF(nsPrefLocalizedString) 1.812 +NS_IMPL_RELEASE(nsPrefLocalizedString) 1.813 + 1.814 +NS_INTERFACE_MAP_BEGIN(nsPrefLocalizedString) 1.815 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefLocalizedString) 1.816 + NS_INTERFACE_MAP_ENTRY(nsIPrefLocalizedString) 1.817 + NS_INTERFACE_MAP_ENTRY(nsISupportsString) 1.818 +NS_INTERFACE_MAP_END 1.819 + 1.820 +nsresult nsPrefLocalizedString::Init() 1.821 +{ 1.822 + nsresult rv; 1.823 + mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); 1.824 + 1.825 + return rv; 1.826 +} 1.827 + 1.828 +NS_IMETHODIMP 1.829 +nsPrefLocalizedString::GetData(char16_t **_retval) 1.830 +{ 1.831 + nsAutoString data; 1.832 + 1.833 + nsresult rv = GetData(data); 1.834 + if (NS_FAILED(rv)) 1.835 + return rv; 1.836 + 1.837 + *_retval = ToNewUnicode(data); 1.838 + if (!*_retval) 1.839 + return NS_ERROR_OUT_OF_MEMORY; 1.840 + 1.841 + return NS_OK; 1.842 +} 1.843 + 1.844 +NS_IMETHODIMP 1.845 +nsPrefLocalizedString::SetData(const char16_t *aData) 1.846 +{ 1.847 + if (!aData) 1.848 + return SetData(EmptyString()); 1.849 + return SetData(nsDependentString(aData)); 1.850 +} 1.851 + 1.852 +NS_IMETHODIMP 1.853 +nsPrefLocalizedString::SetDataWithLength(uint32_t aLength, 1.854 + const char16_t *aData) 1.855 +{ 1.856 + if (!aData) 1.857 + return SetData(EmptyString()); 1.858 + return SetData(Substring(aData, aLength)); 1.859 +} 1.860 + 1.861 +//---------------------------------------------------------------------------- 1.862 +// nsRelativeFilePref 1.863 +//---------------------------------------------------------------------------- 1.864 + 1.865 +NS_IMPL_ISUPPORTS(nsRelativeFilePref, nsIRelativeFilePref) 1.866 + 1.867 +nsRelativeFilePref::nsRelativeFilePref() 1.868 +{ 1.869 +} 1.870 + 1.871 +nsRelativeFilePref::~nsRelativeFilePref() 1.872 +{ 1.873 +} 1.874 + 1.875 +NS_IMETHODIMP nsRelativeFilePref::GetFile(nsIFile **aFile) 1.876 +{ 1.877 + NS_ENSURE_ARG_POINTER(aFile); 1.878 + *aFile = mFile; 1.879 + NS_IF_ADDREF(*aFile); 1.880 + return NS_OK; 1.881 +} 1.882 + 1.883 +NS_IMETHODIMP nsRelativeFilePref::SetFile(nsIFile *aFile) 1.884 +{ 1.885 + mFile = aFile; 1.886 + return NS_OK; 1.887 +} 1.888 + 1.889 +NS_IMETHODIMP nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey) 1.890 +{ 1.891 + aRelativeToKey.Assign(mRelativeToKey); 1.892 + return NS_OK; 1.893 +} 1.894 + 1.895 +NS_IMETHODIMP nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey) 1.896 +{ 1.897 + mRelativeToKey.Assign(aRelativeToKey); 1.898 + return NS_OK; 1.899 +} 1.900 + 1.901 +#undef ENSURE_MAIN_PROCESS 1.902 \ No newline at end of file