Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/dom/ContentChild.h"
8 : #include "nsXULAppAPI.h"
9 :
10 : #include "nsPrefBranch.h"
11 : #include "nsILocalFile.h" // nsILocalFile used for backwards compatibility
12 : #include "nsIObserverService.h"
13 : #include "nsXPCOM.h"
14 : #include "nsISupportsPrimitives.h"
15 : #include "nsIDirectoryService.h"
16 : #include "nsString.h"
17 : #include "nsReadableUtils.h"
18 : #include "nsXPIDLString.h"
19 : #include "nsPrintfCString.h"
20 : #include "nsIStringBundle.h"
21 : #include "prefapi.h"
22 : #include "PLDHashTable.h"
23 :
24 : #include "nsCRT.h"
25 : #include "mozilla/Services.h"
26 :
27 : #include "prefapi_private_data.h"
28 :
29 : #ifdef MOZ_CRASHREPORTER
30 : #include "nsICrashReporter.h"
31 : #endif
32 :
33 : #include "nsIConsoleService.h"
34 :
35 : #ifdef DEBUG
36 : #define ENSURE_MAIN_PROCESS(message, pref) do { \
37 : if (GetContentChild()) { \
38 : nsPrintfCString msg("ENSURE_MAIN_PROCESS failed. %s %s", message, pref); \
39 : NS_ERROR(msg.get()); \
40 : return NS_ERROR_NOT_AVAILABLE; \
41 : } \
42 : } while (0);
43 : #else
44 : #define ENSURE_MAIN_PROCESS(message, pref) \
45 : if (GetContentChild()) { \
46 : return NS_ERROR_NOT_AVAILABLE; \
47 : }
48 : #endif
49 :
50 : using mozilla::dom::ContentChild;
51 :
52 : static ContentChild*
53 42 : GetContentChild()
54 : {
55 42 : if (XRE_IsContentProcess()) {
56 0 : ContentChild* cpc = ContentChild::GetSingleton();
57 0 : if (!cpc) {
58 0 : MOZ_CRASH("Content Protocol is NULL! We're going to crash!");
59 : }
60 0 : return cpc;
61 : }
62 42 : return nullptr;
63 : }
64 :
65 : /*
66 : * Constructor/Destructor
67 : */
68 :
69 41 : nsPrefBranch::nsPrefBranch(const char *aPrefRoot, bool aDefaultBranch)
70 : : mPrefRoot(aPrefRoot)
71 : , mIsDefault(aDefaultBranch)
72 : , mFreeingObserverList(false)
73 41 : , mObservers()
74 : {
75 : nsCOMPtr<nsIObserverService> observerService =
76 82 : mozilla::services::GetObserverService();
77 41 : if (observerService) {
78 41 : ++mRefCnt; // Our refcnt must be > 0 when we call this, or we'll get deleted!
79 : // add weak so we don't have to clean up at shutdown
80 41 : observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
81 41 : --mRefCnt;
82 : }
83 41 : }
84 :
85 6 : nsPrefBranch::~nsPrefBranch()
86 : {
87 2 : freeObserverList();
88 :
89 : nsCOMPtr<nsIObserverService> observerService =
90 4 : mozilla::services::GetObserverService();
91 2 : if (observerService)
92 2 : observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
93 6 : }
94 :
95 :
96 : /*
97 : * nsISupports Implementation
98 : */
99 :
100 230 : NS_IMPL_ADDREF(nsPrefBranch)
101 148 : NS_IMPL_RELEASE(nsPrefBranch)
102 :
103 365 : NS_INTERFACE_MAP_BEGIN(nsPrefBranch)
104 365 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefBranch)
105 323 : NS_INTERFACE_MAP_ENTRY(nsIPrefBranch)
106 269 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranch2, !mIsDefault)
107 269 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIPrefBranchInternal, !mIsDefault)
108 269 : NS_INTERFACE_MAP_ENTRY(nsIObserver)
109 267 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
110 224 : NS_INTERFACE_MAP_END
111 :
112 :
113 : /*
114 : * nsIPrefBranch Implementation
115 : */
116 :
117 0 : NS_IMETHODIMP nsPrefBranch::GetRoot(char **aRoot)
118 : {
119 0 : NS_ENSURE_ARG_POINTER(aRoot);
120 0 : *aRoot = ToNewCString(mPrefRoot);
121 0 : return NS_OK;
122 : }
123 :
124 710 : NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, int32_t *_retval)
125 : {
126 710 : NS_ENSURE_ARG(aPrefName);
127 1420 : const PrefName& pref = getPrefName(aPrefName);
128 710 : switch (PREF_GetPrefType(pref.get())) {
129 : case PrefType::String:
130 42 : *_retval = PREF_STRING;
131 42 : break;
132 : case PrefType::Int:
133 106 : *_retval = PREF_INT;
134 106 : break;
135 : case PrefType::Bool:
136 295 : *_retval = PREF_BOOL;
137 295 : break;
138 : case PrefType::Invalid:
139 : default:
140 267 : *_retval = PREF_INVALID;
141 267 : break;
142 : }
143 710 : return NS_OK;
144 : }
145 :
146 304 : NS_IMETHODIMP nsPrefBranch::GetBoolPrefWithDefault(const char *aPrefName,
147 : bool aDefaultValue,
148 : uint8_t _argc, bool *_retval)
149 : {
150 304 : nsresult rv = GetBoolPref(aPrefName, _retval);
151 :
152 304 : if (NS_FAILED(rv) && _argc == 1) {
153 16 : *_retval = aDefaultValue;
154 16 : return NS_OK;
155 : }
156 :
157 288 : return rv;
158 : }
159 :
160 432 : NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, bool *_retval)
161 : {
162 432 : NS_ENSURE_ARG(aPrefName);
163 864 : const PrefName& pref = getPrefName(aPrefName);
164 432 : return PREF_GetBoolPref(pref.get(), _retval, mIsDefault);
165 : }
166 :
167 15 : NS_IMETHODIMP nsPrefBranch::SetBoolPref(const char *aPrefName, bool aValue)
168 : {
169 15 : ENSURE_MAIN_PROCESS("Cannot SetBoolPref from content process:", aPrefName);
170 15 : NS_ENSURE_ARG(aPrefName);
171 30 : const PrefName& pref = getPrefName(aPrefName);
172 15 : return PREF_SetBoolPref(pref.get(), aValue, mIsDefault);
173 : }
174 :
175 0 : NS_IMETHODIMP nsPrefBranch::GetFloatPrefWithDefault(const char *aPrefName,
176 : float aDefaultValue,
177 : uint8_t _argc, float *_retval)
178 : {
179 0 : nsresult rv = GetFloatPref(aPrefName, _retval);
180 :
181 0 : if (NS_FAILED(rv) && _argc == 1) {
182 0 : *_retval = aDefaultValue;
183 0 : return NS_OK;
184 : }
185 :
186 0 : return rv;
187 : }
188 :
189 2 : NS_IMETHODIMP nsPrefBranch::GetFloatPref(const char *aPrefName, float *_retval)
190 : {
191 2 : NS_ENSURE_ARG(aPrefName);
192 4 : nsAutoCString stringVal;
193 2 : nsresult rv = GetCharPref(aPrefName, getter_Copies(stringVal));
194 2 : if (NS_SUCCEEDED(rv)) {
195 2 : *_retval = stringVal.ToFloat(&rv);
196 : }
197 :
198 2 : return rv;
199 : }
200 :
201 59 : NS_IMETHODIMP nsPrefBranch::GetCharPrefWithDefault(const char *aPrefName,
202 : const char *aDefaultValue,
203 : uint8_t _argc, char **_retval)
204 : {
205 59 : nsresult rv = GetCharPref(aPrefName, _retval);
206 :
207 59 : if (NS_FAILED(rv) && _argc == 1) {
208 1 : NS_ENSURE_ARG(aDefaultValue);
209 1 : *_retval = NS_strdup(aDefaultValue);
210 1 : return NS_OK;
211 : }
212 :
213 58 : return rv;
214 : }
215 :
216 145 : NS_IMETHODIMP nsPrefBranch::GetCharPref(const char *aPrefName, char **_retval)
217 : {
218 145 : NS_ENSURE_ARG(aPrefName);
219 290 : const PrefName& pref = getPrefName(aPrefName);
220 145 : return PREF_CopyCharPref(pref.get(), _retval, mIsDefault);
221 : }
222 :
223 8 : NS_IMETHODIMP nsPrefBranch::SetCharPref(const char *aPrefName, const char *aValue)
224 : {
225 8 : nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
226 8 : if (NS_FAILED(rv)) {
227 0 : return rv;
228 : }
229 8 : return SetCharPrefInternal(aPrefName, aValue);
230 : }
231 :
232 9 : nsresult nsPrefBranch::SetCharPrefInternal(const char *aPrefName, const char *aValue)
233 :
234 : {
235 9 : ENSURE_MAIN_PROCESS("Cannot SetCharPref from content process:", aPrefName);
236 9 : NS_ENSURE_ARG(aPrefName);
237 9 : NS_ENSURE_ARG(aValue);
238 18 : const PrefName& pref = getPrefName(aPrefName);
239 9 : return PREF_SetCharPref(pref.get(), aValue, mIsDefault);
240 : }
241 :
242 15 : NS_IMETHODIMP nsPrefBranch::GetStringPref(const char *aPrefName,
243 : const nsACString& aDefaultValue,
244 : uint8_t _argc,
245 : nsACString& _retval)
246 : {
247 30 : nsXPIDLCString utf8String;
248 15 : nsresult rv = GetCharPref(aPrefName, getter_Copies(utf8String));
249 15 : if (NS_SUCCEEDED(rv)) {
250 7 : _retval = utf8String;
251 7 : return rv;
252 : }
253 :
254 8 : if (_argc == 1) {
255 4 : _retval = aDefaultValue;
256 4 : return NS_OK;
257 : }
258 :
259 4 : return rv;
260 : }
261 :
262 1 : NS_IMETHODIMP nsPrefBranch::SetStringPref(const char *aPrefName, const nsACString& aValue)
263 : {
264 1 : nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
265 1 : if (NS_FAILED(rv)) {
266 0 : return rv;
267 : }
268 :
269 1 : return SetCharPrefInternal(aPrefName, PromiseFlatCString(aValue).get());
270 : }
271 :
272 51 : NS_IMETHODIMP nsPrefBranch::GetIntPrefWithDefault(const char *aPrefName,
273 : int32_t aDefaultValue,
274 : uint8_t _argc, int32_t *_retval)
275 : {
276 51 : nsresult rv = GetIntPref(aPrefName, _retval);
277 :
278 51 : if (NS_FAILED(rv) && _argc == 1) {
279 3 : *_retval = aDefaultValue;
280 3 : return NS_OK;
281 : }
282 :
283 48 : return rv;
284 : }
285 :
286 232 : NS_IMETHODIMP nsPrefBranch::GetIntPref(const char *aPrefName, int32_t *_retval)
287 : {
288 232 : NS_ENSURE_ARG(aPrefName);
289 464 : const PrefName& pref = getPrefName(aPrefName);
290 232 : return PREF_GetIntPref(pref.get(), _retval, mIsDefault);
291 : }
292 :
293 12 : NS_IMETHODIMP nsPrefBranch::SetIntPref(const char *aPrefName, int32_t aValue)
294 : {
295 12 : ENSURE_MAIN_PROCESS("Cannot SetIntPref from content process:", aPrefName);
296 12 : NS_ENSURE_ARG(aPrefName);
297 24 : const PrefName& pref = getPrefName(aPrefName);
298 12 : return PREF_SetIntPref(pref.get(), aValue, mIsDefault);
299 : }
300 :
301 47 : NS_IMETHODIMP nsPrefBranch::GetComplexValue(const char *aPrefName, const nsIID & aType, void **_retval)
302 : {
303 47 : NS_ENSURE_ARG(aPrefName);
304 :
305 : nsresult rv;
306 94 : nsXPIDLCString utf8String;
307 :
308 : // we have to do this one first because it's different than all the rest
309 47 : if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
310 50 : nsCOMPtr<nsIPrefLocalizedString> theString(do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv));
311 25 : if (NS_FAILED(rv)) return rv;
312 :
313 50 : const PrefName& pref = getPrefName(aPrefName);
314 25 : bool bNeedDefault = false;
315 :
316 25 : if (mIsDefault) {
317 0 : bNeedDefault = true;
318 : } else {
319 : // if there is no user (or locked) value
320 25 : if (!PREF_HasUserPref(pref.get()) && !PREF_PrefIsLocked(pref.get())) {
321 19 : bNeedDefault = true;
322 : }
323 : }
324 :
325 : // if we need to fetch the default value, do that instead, otherwise use the
326 : // value we pulled in at the top of this function
327 25 : if (bNeedDefault) {
328 38 : nsXPIDLString utf16String;
329 19 : rv = GetDefaultFromPropertiesFile(pref.get(), getter_Copies(utf16String));
330 19 : if (NS_SUCCEEDED(rv)) {
331 14 : theString->SetData(utf16String.get());
332 : }
333 : } else {
334 6 : rv = GetCharPref(aPrefName, getter_Copies(utf8String));
335 6 : if (NS_SUCCEEDED(rv)) {
336 6 : theString->SetData(NS_ConvertUTF8toUTF16(utf8String).get());
337 : }
338 : }
339 :
340 25 : if (NS_SUCCEEDED(rv)) {
341 20 : theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(_retval));
342 : }
343 :
344 25 : return rv;
345 : }
346 :
347 : // if we can't get the pref, there's no point in being here
348 22 : rv = GetCharPref(aPrefName, getter_Copies(utf8String));
349 22 : if (NS_FAILED(rv)) {
350 3 : return rv;
351 : }
352 :
353 : // also check nsILocalFile, for backwards compatibility
354 19 : if (aType.Equals(NS_GET_IID(nsIFile)) || aType.Equals(NS_GET_IID(nsILocalFile))) {
355 0 : if (GetContentChild()) {
356 0 : NS_ERROR("cannot get nsIFile pref from content process");
357 0 : return NS_ERROR_NOT_AVAILABLE;
358 : }
359 :
360 0 : nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
361 :
362 0 : if (NS_SUCCEEDED(rv)) {
363 0 : rv = file->SetPersistentDescriptor(utf8String);
364 0 : if (NS_SUCCEEDED(rv)) {
365 0 : file.forget(reinterpret_cast<nsIFile**>(_retval));
366 0 : return NS_OK;
367 : }
368 : }
369 0 : return rv;
370 : }
371 :
372 19 : if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
373 0 : if (GetContentChild()) {
374 0 : NS_ERROR("cannot get nsIRelativeFilePref from content process");
375 0 : return NS_ERROR_NOT_AVAILABLE;
376 : }
377 :
378 0 : nsACString::const_iterator keyBegin, strEnd;
379 0 : utf8String.BeginReading(keyBegin);
380 0 : utf8String.EndReading(strEnd);
381 :
382 : // The pref has the format: [fromKey]a/b/c
383 0 : if (*keyBegin++ != '[')
384 0 : return NS_ERROR_FAILURE;
385 0 : nsACString::const_iterator keyEnd(keyBegin);
386 0 : if (!FindCharInReadable(']', keyEnd, strEnd))
387 0 : return NS_ERROR_FAILURE;
388 0 : nsAutoCString key(Substring(keyBegin, keyEnd));
389 :
390 0 : nsCOMPtr<nsIFile> fromFile;
391 0 : nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
392 0 : if (NS_FAILED(rv))
393 0 : return rv;
394 0 : rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile), getter_AddRefs(fromFile));
395 0 : if (NS_FAILED(rv))
396 0 : return rv;
397 :
398 0 : nsCOMPtr<nsIFile> theFile;
399 0 : rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(theFile));
400 0 : if (NS_FAILED(rv))
401 0 : return rv;
402 0 : rv = theFile->SetRelativeDescriptor(fromFile, Substring(++keyEnd, strEnd));
403 0 : if (NS_FAILED(rv))
404 0 : return rv;
405 0 : nsCOMPtr<nsIRelativeFilePref> relativePref;
406 0 : rv = NS_NewRelativeFilePref(theFile, key, getter_AddRefs(relativePref));
407 0 : if (NS_FAILED(rv))
408 0 : return rv;
409 :
410 0 : relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(_retval));
411 0 : return NS_OK;
412 : }
413 :
414 19 : if (aType.Equals(NS_GET_IID(nsISupportsString))) {
415 38 : nsCOMPtr<nsISupportsString> theString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
416 :
417 19 : if (NS_SUCCEEDED(rv)) {
418 : // Debugging to see why we end up with very long strings here with
419 : // some addons, see bug 836263.
420 38 : nsAutoString wdata;
421 19 : if (!AppendUTF8toUTF16(utf8String, wdata, mozilla::fallible)) {
422 : #ifdef MOZ_CRASHREPORTER
423 : nsCOMPtr<nsICrashReporter> cr =
424 0 : do_GetService("@mozilla.org/toolkit/crash-reporter;1");
425 0 : if (cr) {
426 0 : cr->AnnotateCrashReport(NS_LITERAL_CSTRING("bug836263-size"),
427 0 : nsPrintfCString("%x", utf8String.Length()));
428 0 : cr->RegisterAppMemory(uint64_t(utf8String.BeginReading()),
429 0 : std::min(0x1000U, utf8String.Length()));
430 : }
431 : #endif
432 0 : MOZ_CRASH("bug836263");
433 : }
434 19 : theString->SetData(wdata);
435 19 : theString.forget(reinterpret_cast<nsISupportsString**>(_retval));
436 : }
437 19 : return rv;
438 : }
439 :
440 0 : NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type");
441 0 : return NS_NOINTERFACE;
442 : }
443 :
444 8 : nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const char* aValue) {
445 8 : if (!aValue) {
446 0 : return NS_OK;
447 : }
448 8 : return CheckSanityOfStringLength(aPrefName, strlen(aValue));
449 : }
450 :
451 0 : nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const nsAString& aValue) {
452 0 : return CheckSanityOfStringLength(aPrefName, aValue.Length());
453 : }
454 :
455 1 : nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const nsACString& aValue) {
456 1 : return CheckSanityOfStringLength(aPrefName, aValue.Length());
457 : }
458 :
459 9 : nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, const uint32_t aLength) {
460 9 : if (aLength > MAX_PREF_LENGTH) {
461 0 : return NS_ERROR_ILLEGAL_VALUE;
462 : }
463 9 : if (aLength <= MAX_ADVISABLE_PREF_LENGTH) {
464 9 : return NS_OK;
465 : }
466 : nsresult rv;
467 0 : nsCOMPtr<nsIConsoleService> console = do_GetService("@mozilla.org/consoleservice;1", &rv);
468 0 : if (NS_FAILED(rv)) {
469 0 : return rv;
470 : }
471 0 : nsAutoCString message(nsPrintfCString("Warning: attempting to write %d bytes to preference %s. This is bad "
472 : "for general performance and memory usage. Such an amount of data "
473 : "should rather be written to an external file. This preference will "
474 : "not be sent to any content processes.",
475 : aLength,
476 0 : getPrefName(aPrefName).get()));
477 0 : rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get());
478 0 : if (NS_FAILED(rv)) {
479 0 : return rv;
480 : }
481 0 : return NS_OK;
482 : }
483 :
484 : /*static*/
485 0 : void nsPrefBranch::ReportToConsole(const nsAString& aMessage)
486 : {
487 : nsresult rv;
488 0 : nsCOMPtr<nsIConsoleService> console = do_GetService("@mozilla.org/consoleservice;1", &rv);
489 0 : if (NS_FAILED(rv)) {
490 0 : return;
491 : }
492 0 : nsAutoString message(aMessage);
493 0 : console->LogStringMessage(message.get());
494 : }
495 :
496 0 : NS_IMETHODIMP nsPrefBranch::SetComplexValue(const char *aPrefName, const nsIID & aType, nsISupports *aValue)
497 : {
498 0 : ENSURE_MAIN_PROCESS("Cannot SetComplexValue from content process:", aPrefName);
499 0 : NS_ENSURE_ARG(aPrefName);
500 :
501 0 : nsresult rv = NS_NOINTERFACE;
502 :
503 : // also check nsILocalFile, for backwards compatibility
504 0 : if (aType.Equals(NS_GET_IID(nsIFile)) || aType.Equals(NS_GET_IID(nsILocalFile))) {
505 0 : nsCOMPtr<nsIFile> file = do_QueryInterface(aValue);
506 0 : if (!file)
507 0 : return NS_NOINTERFACE;
508 0 : nsAutoCString descriptorString;
509 :
510 0 : rv = file->GetPersistentDescriptor(descriptorString);
511 0 : if (NS_SUCCEEDED(rv)) {
512 0 : rv = SetCharPrefInternal(aPrefName, descriptorString.get());
513 : }
514 0 : return rv;
515 : }
516 :
517 0 : if (aType.Equals(NS_GET_IID(nsIRelativeFilePref))) {
518 0 : nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue);
519 0 : if (!relFilePref)
520 0 : return NS_NOINTERFACE;
521 :
522 0 : nsCOMPtr<nsIFile> file;
523 0 : relFilePref->GetFile(getter_AddRefs(file));
524 0 : if (!file)
525 0 : return NS_NOINTERFACE;
526 0 : nsAutoCString relativeToKey;
527 0 : (void) relFilePref->GetRelativeToKey(relativeToKey);
528 :
529 0 : nsCOMPtr<nsIFile> relativeToFile;
530 0 : nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
531 0 : if (NS_FAILED(rv))
532 0 : return rv;
533 0 : rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile), getter_AddRefs(relativeToFile));
534 0 : if (NS_FAILED(rv))
535 0 : return rv;
536 :
537 0 : nsAutoCString relDescriptor;
538 0 : rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor);
539 0 : if (NS_FAILED(rv))
540 0 : return rv;
541 :
542 0 : nsAutoCString descriptorString;
543 0 : descriptorString.Append('[');
544 0 : descriptorString.Append(relativeToKey);
545 0 : descriptorString.Append(']');
546 0 : descriptorString.Append(relDescriptor);
547 0 : return SetCharPrefInternal(aPrefName, descriptorString.get());
548 : }
549 :
550 0 : if (aType.Equals(NS_GET_IID(nsISupportsString))) {
551 0 : nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
552 :
553 0 : if (theString) {
554 0 : nsString wideString;
555 :
556 0 : rv = theString->GetData(wideString);
557 0 : if (NS_SUCCEEDED(rv)) {
558 : // Check sanity of string length before any lengthy conversion
559 0 : rv = CheckSanityOfStringLength(aPrefName, wideString);
560 0 : if (NS_FAILED(rv)) {
561 0 : return rv;
562 : }
563 0 : rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
564 : }
565 : }
566 0 : return rv;
567 : }
568 :
569 0 : if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString))) {
570 0 : nsCOMPtr<nsIPrefLocalizedString> theString = do_QueryInterface(aValue);
571 :
572 0 : if (theString) {
573 0 : nsXPIDLString wideString;
574 :
575 0 : rv = theString->GetData(getter_Copies(wideString));
576 0 : if (NS_SUCCEEDED(rv)) {
577 : // Check sanity of string length before any lengthy conversion
578 0 : rv = CheckSanityOfStringLength(aPrefName, wideString);
579 0 : if (NS_FAILED(rv)) {
580 0 : return rv;
581 : }
582 0 : rv = SetCharPrefInternal(aPrefName, NS_ConvertUTF16toUTF8(wideString).get());
583 : }
584 : }
585 0 : return rv;
586 : }
587 :
588 0 : NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type");
589 0 : return NS_NOINTERFACE;
590 : }
591 :
592 5 : NS_IMETHODIMP nsPrefBranch::ClearUserPref(const char *aPrefName)
593 : {
594 5 : ENSURE_MAIN_PROCESS("Cannot ClearUserPref from content process:", aPrefName);
595 5 : NS_ENSURE_ARG(aPrefName);
596 10 : const PrefName& pref = getPrefName(aPrefName);
597 5 : return PREF_ClearUserPref(pref.get());
598 : }
599 :
600 87 : NS_IMETHODIMP nsPrefBranch::PrefHasUserValue(const char *aPrefName, bool *_retval)
601 : {
602 87 : NS_ENSURE_ARG_POINTER(_retval);
603 87 : NS_ENSURE_ARG(aPrefName);
604 174 : const PrefName& pref = getPrefName(aPrefName);
605 87 : *_retval = PREF_HasUserPref(pref.get());
606 87 : return NS_OK;
607 : }
608 :
609 0 : NS_IMETHODIMP nsPrefBranch::LockPref(const char *aPrefName)
610 : {
611 0 : ENSURE_MAIN_PROCESS("Cannot LockPref from content process:", aPrefName);
612 0 : NS_ENSURE_ARG(aPrefName);
613 0 : const PrefName& pref = getPrefName(aPrefName);
614 0 : return PREF_LockPref(pref.get(), true);
615 : }
616 :
617 1 : NS_IMETHODIMP nsPrefBranch::PrefIsLocked(const char *aPrefName, bool *_retval)
618 : {
619 1 : ENSURE_MAIN_PROCESS("Cannot check PrefIsLocked from content process:", aPrefName);
620 1 : NS_ENSURE_ARG_POINTER(_retval);
621 1 : NS_ENSURE_ARG(aPrefName);
622 2 : const PrefName& pref = getPrefName(aPrefName);
623 1 : *_retval = PREF_PrefIsLocked(pref.get());
624 1 : return NS_OK;
625 : }
626 :
627 0 : NS_IMETHODIMP nsPrefBranch::UnlockPref(const char *aPrefName)
628 : {
629 0 : ENSURE_MAIN_PROCESS("Cannot UnlockPref from content process:", aPrefName);
630 0 : NS_ENSURE_ARG(aPrefName);
631 0 : const PrefName& pref = getPrefName(aPrefName);
632 0 : return PREF_LockPref(pref.get(), false);
633 : }
634 :
635 0 : NS_IMETHODIMP nsPrefBranch::ResetBranch(const char *aStartingAt)
636 : {
637 0 : return NS_ERROR_NOT_IMPLEMENTED;
638 : }
639 :
640 0 : NS_IMETHODIMP nsPrefBranch::DeleteBranch(const char *aStartingAt)
641 : {
642 0 : ENSURE_MAIN_PROCESS("Cannot DeleteBranch from content process:", aStartingAt);
643 0 : NS_ENSURE_ARG(aStartingAt);
644 0 : const PrefName& pref = getPrefName(aStartingAt);
645 0 : return PREF_DeleteBranch(pref.get());
646 : }
647 :
648 28 : NS_IMETHODIMP nsPrefBranch::GetChildList(const char *aStartingAt, uint32_t *aCount, char ***aChildArray)
649 : {
650 : char **outArray;
651 : int32_t numPrefs;
652 : int32_t dwIndex;
653 56 : AutoTArray<nsCString, 32> prefArray;
654 :
655 28 : NS_ENSURE_ARG(aStartingAt);
656 28 : NS_ENSURE_ARG_POINTER(aCount);
657 28 : NS_ENSURE_ARG_POINTER(aChildArray);
658 :
659 28 : *aChildArray = nullptr;
660 28 : *aCount = 0;
661 :
662 : // this will contain a list of all the pref name strings
663 : // allocate on the stack for speed
664 :
665 56 : const PrefName& parent = getPrefName(aStartingAt);
666 28 : size_t parentLen = parent.Length();
667 84528 : for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
668 84500 : auto entry = static_cast<PrefHashEntry*>(iter.Get());
669 84500 : if (strncmp(entry->key, parent.get(), parentLen) == 0) {
670 818 : prefArray.AppendElement(entry->key);
671 : }
672 : }
673 :
674 : // now that we've built up the list, run the callback on
675 : // all the matching elements
676 28 : numPrefs = prefArray.Length();
677 :
678 28 : if (numPrefs) {
679 23 : outArray = (char **)moz_xmalloc(numPrefs * sizeof(char *));
680 23 : if (!outArray)
681 0 : return NS_ERROR_OUT_OF_MEMORY;
682 :
683 841 : for (dwIndex = 0; dwIndex < numPrefs; ++dwIndex) {
684 : // we need to lop off mPrefRoot in case the user is planning to pass this
685 : // back to us because if they do we are going to add mPrefRoot again.
686 818 : const nsCString& element = prefArray[dwIndex];
687 2454 : outArray[dwIndex] = (char *)nsMemory::Clone(
688 1636 : element.get() + mPrefRoot.Length(), element.Length() - mPrefRoot.Length() + 1);
689 :
690 818 : if (!outArray[dwIndex]) {
691 : // we ran out of memory... this is annoying
692 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(dwIndex, outArray);
693 0 : return NS_ERROR_OUT_OF_MEMORY;
694 : }
695 : }
696 23 : *aChildArray = outArray;
697 : }
698 28 : *aCount = numPrefs;
699 :
700 28 : return NS_OK;
701 : }
702 :
703 925 : NS_IMETHODIMP nsPrefBranch::AddObserver(const char *aDomain, nsIObserver *aObserver, bool aHoldWeak)
704 : {
705 : PrefCallback *pCallback;
706 :
707 925 : NS_ENSURE_ARG(aDomain);
708 925 : NS_ENSURE_ARG(aObserver);
709 :
710 : // hold a weak reference to the observer if so requested
711 925 : if (aHoldWeak) {
712 288 : nsCOMPtr<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(aObserver);
713 144 : if (!weakRefFactory) {
714 : // the caller didn't give us a object that supports weak reference... tell them
715 0 : return NS_ERROR_INVALID_ARG;
716 : }
717 :
718 : // Construct a PrefCallback with a weak reference to the observer.
719 288 : pCallback = new PrefCallback(aDomain, weakRefFactory, this);
720 :
721 : } else {
722 : // Construct a PrefCallback with a strong reference to the observer.
723 781 : pCallback = new PrefCallback(aDomain, aObserver, this);
724 : }
725 :
726 1850 : auto p = mObservers.LookupForAdd(pCallback);
727 925 : if (p) {
728 0 : NS_WARNING("Ignoring duplicate observer.");
729 0 : delete pCallback;
730 0 : return NS_OK;
731 : }
732 :
733 925 : p.OrInsert([&pCallback]() {
734 : return pCallback;
735 1850 : });
736 :
737 : // We must pass a fully qualified preference name to the callback
738 : // aDomain == nullptr is the only possible failure, and we trapped it with
739 : // NS_ENSURE_ARG above.
740 1850 : const PrefName& pref = getPrefName(aDomain);
741 925 : PREF_RegisterCallback(pref.get(), NotifyObserver, pCallback);
742 925 : return NS_OK;
743 : }
744 :
745 3 : NS_IMETHODIMP nsPrefBranch::RemoveObserver(const char *aDomain, nsIObserver *aObserver)
746 : {
747 3 : NS_ENSURE_ARG(aDomain);
748 3 : NS_ENSURE_ARG(aObserver);
749 :
750 3 : nsresult rv = NS_OK;
751 :
752 : // If we're in the middle of a call to freeObserverList, don't process this
753 : // RemoveObserver call -- the observer in question will be removed soon, if
754 : // it hasn't been already.
755 : //
756 : // It's important that we don't touch mObservers in any way -- even a Get()
757 : // which returns null might cause the hashtable to resize itself, which will
758 : // break the iteration in freeObserverList.
759 3 : if (mFreeingObserverList)
760 0 : return NS_OK;
761 :
762 : // Remove the relevant PrefCallback from mObservers and get an owning
763 : // pointer to it. Unregister the callback first, and then let the owning
764 : // pointer go out of scope and destroy the callback.
765 6 : PrefCallback key(aDomain, aObserver, this);
766 6 : nsAutoPtr<PrefCallback> pCallback;
767 3 : mObservers.Remove(&key, &pCallback);
768 3 : if (pCallback) {
769 : // aDomain == nullptr is the only possible failure, trapped above
770 6 : const PrefName& pref = getPrefName(aDomain);
771 3 : rv = PREF_UnregisterCallback(pref.get(), NotifyObserver, pCallback);
772 : }
773 :
774 3 : return rv;
775 : }
776 :
777 0 : NS_IMETHODIMP nsPrefBranch::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
778 : {
779 : // watch for xpcom shutdown and free our observers to eliminate any cyclic references
780 0 : if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
781 0 : freeObserverList();
782 : }
783 0 : return NS_OK;
784 : }
785 :
786 : /* static */
787 49 : void nsPrefBranch::NotifyObserver(const char *newpref, void *data)
788 : {
789 49 : PrefCallback *pCallback = (PrefCallback *)data;
790 :
791 98 : nsCOMPtr<nsIObserver> observer = pCallback->GetObserver();
792 49 : if (!observer) {
793 : // The observer has expired. Let's remove this callback.
794 0 : pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback);
795 0 : return;
796 : }
797 :
798 : // remove any root this string may contain so as to not confuse the observer
799 : // by passing them something other than what they passed us as a topic
800 49 : uint32_t len = pCallback->GetPrefBranch()->GetRootLength();
801 98 : nsAutoCString suffix(newpref + len);
802 :
803 98 : observer->Observe(static_cast<nsIPrefBranch *>(pCallback->GetPrefBranch()),
804 : NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
805 98 : NS_ConvertASCIItoUTF16(suffix).get());
806 : }
807 :
808 : size_t
809 0 : nsPrefBranch::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
810 : {
811 0 : size_t n = aMallocSizeOf(this);
812 0 : n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
813 0 : n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
814 0 : return n;
815 : }
816 :
817 2 : void nsPrefBranch::freeObserverList(void)
818 : {
819 : // We need to prevent anyone from modifying mObservers while we're iterating
820 : // over it. In particular, some clients will call RemoveObserver() when
821 : // they're removed and destructed via the iterator; we set
822 : // mFreeingObserverList to keep those calls from touching mObservers.
823 2 : mFreeingObserverList = true;
824 2 : for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) {
825 0 : nsAutoPtr<PrefCallback>& callback = iter.Data();
826 0 : nsPrefBranch *prefBranch = callback->GetPrefBranch();
827 0 : const PrefName& pref = prefBranch->getPrefName(callback->GetDomain().get());
828 0 : PREF_UnregisterCallback(pref.get(), nsPrefBranch::NotifyObserver, callback);
829 0 : iter.Remove();
830 : }
831 2 : mFreeingObserverList = false;
832 2 : }
833 :
834 : void
835 0 : nsPrefBranch::RemoveExpiredCallback(PrefCallback *aCallback)
836 : {
837 0 : NS_PRECONDITION(aCallback->IsExpired(), "Callback should be expired.");
838 0 : mObservers.Remove(aCallback);
839 0 : }
840 :
841 19 : nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char *aPrefName, char16_t **return_buf)
842 : {
843 : nsresult rv;
844 :
845 : // the default value contains a URL to a .properties file
846 :
847 38 : nsXPIDLCString propertyFileURL;
848 19 : rv = PREF_CopyCharPref(aPrefName, getter_Copies(propertyFileURL), true);
849 19 : if (NS_FAILED(rv))
850 0 : return rv;
851 :
852 : nsCOMPtr<nsIStringBundleService> bundleService =
853 38 : mozilla::services::GetStringBundleService();
854 19 : if (!bundleService)
855 0 : return NS_ERROR_FAILURE;
856 :
857 38 : nsCOMPtr<nsIStringBundle> bundle;
858 38 : rv = bundleService->CreateBundle(propertyFileURL,
859 38 : getter_AddRefs(bundle));
860 19 : if (NS_FAILED(rv))
861 0 : return rv;
862 :
863 : // string names are in unicode
864 38 : nsAutoString stringId;
865 19 : stringId.AssignASCII(aPrefName);
866 :
867 19 : return bundle->GetStringFromName(stringId.get(), return_buf);
868 : }
869 :
870 : nsPrefBranch::PrefName
871 2629 : nsPrefBranch::getPrefName(const char *aPrefName) const
872 : {
873 2629 : NS_ASSERTION(aPrefName, "null pref name!");
874 :
875 : // for speed, avoid strcpy if we can:
876 2629 : if (mPrefRoot.IsEmpty())
877 2415 : return PrefName(aPrefName);
878 :
879 214 : return PrefName(mPrefRoot + nsDependentCString(aPrefName));
880 : }
881 :
882 : //----------------------------------------------------------------------------
883 : // nsPrefLocalizedString
884 : //----------------------------------------------------------------------------
885 :
886 25 : nsPrefLocalizedString::nsPrefLocalizedString()
887 : {
888 25 : }
889 :
890 28 : nsPrefLocalizedString::~nsPrefLocalizedString()
891 : {
892 42 : }
893 :
894 :
895 : /*
896 : * nsISupports Implementation
897 : */
898 :
899 117 : NS_IMPL_ADDREF(nsPrefLocalizedString)
900 95 : NS_IMPL_RELEASE(nsPrefLocalizedString)
901 :
902 147 : NS_INTERFACE_MAP_BEGIN(nsPrefLocalizedString)
903 147 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrefLocalizedString)
904 136 : NS_INTERFACE_MAP_ENTRY(nsIPrefLocalizedString)
905 66 : NS_INTERFACE_MAP_ENTRY(nsISupportsString)
906 66 : NS_INTERFACE_MAP_END
907 :
908 25 : nsresult nsPrefLocalizedString::Init()
909 : {
910 : nsresult rv;
911 25 : mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
912 :
913 25 : return rv;
914 : }
915 :
916 : NS_IMETHODIMP
917 20 : nsPrefLocalizedString::GetData(char16_t **_retval)
918 : {
919 40 : nsAutoString data;
920 :
921 20 : nsresult rv = GetData(data);
922 20 : if (NS_FAILED(rv))
923 0 : return rv;
924 :
925 20 : *_retval = ToNewUnicode(data);
926 20 : if (!*_retval)
927 0 : return NS_ERROR_OUT_OF_MEMORY;
928 :
929 20 : return NS_OK;
930 : }
931 :
932 : NS_IMETHODIMP
933 20 : nsPrefLocalizedString::SetData(const char16_t *aData)
934 : {
935 20 : if (!aData)
936 0 : return SetData(EmptyString());
937 20 : return SetData(nsDependentString(aData));
938 : }
939 :
940 : NS_IMETHODIMP
941 0 : nsPrefLocalizedString::SetDataWithLength(uint32_t aLength,
942 : const char16_t *aData)
943 : {
944 0 : if (!aData)
945 0 : return SetData(EmptyString());
946 0 : return SetData(Substring(aData, aLength));
947 : }
948 :
949 : //----------------------------------------------------------------------------
950 : // nsRelativeFilePref
951 : //----------------------------------------------------------------------------
952 :
953 0 : NS_IMPL_ISUPPORTS(nsRelativeFilePref, nsIRelativeFilePref)
954 :
955 0 : nsRelativeFilePref::nsRelativeFilePref()
956 : {
957 0 : }
958 :
959 0 : nsRelativeFilePref::~nsRelativeFilePref()
960 : {
961 0 : }
962 :
963 0 : NS_IMETHODIMP nsRelativeFilePref::GetFile(nsIFile **aFile)
964 : {
965 0 : NS_ENSURE_ARG_POINTER(aFile);
966 0 : *aFile = mFile;
967 0 : NS_IF_ADDREF(*aFile);
968 0 : return NS_OK;
969 : }
970 :
971 0 : NS_IMETHODIMP nsRelativeFilePref::SetFile(nsIFile *aFile)
972 : {
973 0 : mFile = aFile;
974 0 : return NS_OK;
975 : }
976 :
977 0 : NS_IMETHODIMP nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey)
978 : {
979 0 : aRelativeToKey.Assign(mRelativeToKey);
980 0 : return NS_OK;
981 : }
982 :
983 0 : NS_IMETHODIMP nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey)
984 : {
985 0 : mRelativeToKey.Assign(aRelativeToKey);
986 0 : return NS_OK;
987 : }
988 :
989 : #undef ENSURE_MAIN_PROCESS
|