Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef nsPrefBranch_h
7 : #define nsPrefBranch_h
8 :
9 : #include "nsCOMPtr.h"
10 : #include "nsIObserver.h"
11 : #include "nsIPrefBranch.h"
12 : #include "nsIPrefBranchInternal.h"
13 : #include "nsIPrefLocalizedString.h"
14 : #include "nsXPCOM.h"
15 : #include "nsISupportsPrimitives.h"
16 : #include "nsIRelativeFilePref.h"
17 : #include "nsIFile.h"
18 : #include "nsString.h"
19 : #include "nsTArray.h"
20 : #include "nsWeakReference.h"
21 : #include "nsClassHashtable.h"
22 : #include "nsCRT.h"
23 : #include "nsISupportsImpl.h"
24 : #include "mozilla/HashFunctions.h"
25 : #include "mozilla/MemoryReporting.h"
26 : #include "mozilla/Variant.h"
27 :
28 : namespace mozilla {
29 : class PreferenceServiceReporter;
30 : } // namespace mozilla
31 :
32 : class nsPrefBranch;
33 :
34 : class PrefCallback : public PLDHashEntryHdr {
35 : friend class mozilla::PreferenceServiceReporter;
36 :
37 : public:
38 : typedef PrefCallback* KeyType;
39 : typedef const PrefCallback* KeyTypePointer;
40 :
41 928 : static const PrefCallback* KeyToPointer(PrefCallback *aKey)
42 : {
43 928 : return aKey;
44 : }
45 :
46 928 : static PLDHashNumber HashKey(const PrefCallback *aKey)
47 : {
48 928 : uint32_t hash = mozilla::HashString(aKey->mDomain);
49 928 : return mozilla::AddToHash(hash, aKey->mCanonical);
50 : }
51 :
52 :
53 : public:
54 : // Create a PrefCallback with a strong reference to its observer.
55 784 : PrefCallback(const char *aDomain, nsIObserver *aObserver,
56 : nsPrefBranch *aBranch)
57 784 : : mDomain(aDomain),
58 : mBranch(aBranch),
59 : mWeakRef(nullptr),
60 784 : mStrongRef(aObserver)
61 : {
62 784 : MOZ_COUNT_CTOR(PrefCallback);
63 1568 : nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
64 784 : mCanonical = canonical;
65 784 : }
66 :
67 : // Create a PrefCallback with a weak reference to its observer.
68 144 : PrefCallback(const char *aDomain,
69 : nsISupportsWeakReference *aObserver,
70 : nsPrefBranch *aBranch)
71 144 : : mDomain(aDomain),
72 : mBranch(aBranch),
73 288 : mWeakRef(do_GetWeakReference(aObserver)),
74 432 : mStrongRef(nullptr)
75 : {
76 144 : MOZ_COUNT_CTOR(PrefCallback);
77 288 : nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
78 144 : mCanonical = canonical;
79 144 : }
80 :
81 : // Copy constructor needs to be explicit or the linker complains.
82 925 : explicit PrefCallback(const PrefCallback *&aCopy)
83 1850 : : mDomain(aCopy->mDomain),
84 925 : mBranch(aCopy->mBranch),
85 925 : mWeakRef(aCopy->mWeakRef),
86 925 : mStrongRef(aCopy->mStrongRef),
87 4625 : mCanonical(aCopy->mCanonical)
88 : {
89 925 : MOZ_COUNT_CTOR(PrefCallback);
90 925 : }
91 :
92 9 : ~PrefCallback()
93 9 : {
94 9 : MOZ_COUNT_DTOR(PrefCallback);
95 9 : }
96 :
97 3 : bool KeyEquals(const PrefCallback *aKey) const
98 : {
99 : // We want to be able to look up a weakly-referencing PrefCallback after
100 : // its observer has died so we can remove it from the table. Once the
101 : // callback's observer dies, its canonical pointer is stale -- in
102 : // particular, we may have allocated a new observer in the same spot in
103 : // memory! So we can't just compare canonical pointers to determine
104 : // whether aKey refers to the same observer as this.
105 : //
106 : // Our workaround is based on the way we use this hashtable: When we ask
107 : // the hashtable to remove a PrefCallback whose weak reference has
108 : // expired, we use as the key for removal the same object as was inserted
109 : // into the hashtable. Thus we can say that if one of the keys' weak
110 : // references has expired, the two keys are equal iff they're the same
111 : // object.
112 :
113 3 : if (IsExpired() || aKey->IsExpired())
114 0 : return this == aKey;
115 :
116 3 : if (mCanonical != aKey->mCanonical)
117 0 : return false;
118 :
119 3 : return mDomain.Equals(aKey->mDomain);
120 : }
121 :
122 : PrefCallback *GetKey() const
123 : {
124 : return const_cast<PrefCallback*>(this);
125 : }
126 :
127 : // Get a reference to the callback's observer, or null if the observer was
128 : // weakly referenced and has been destroyed.
129 49 : already_AddRefed<nsIObserver> GetObserver() const
130 : {
131 49 : if (!IsWeak()) {
132 88 : nsCOMPtr<nsIObserver> copy = mStrongRef;
133 44 : return copy.forget();
134 : }
135 :
136 10 : nsCOMPtr<nsIObserver> observer = do_QueryReferent(mWeakRef);
137 5 : return observer.forget();
138 : }
139 :
140 0 : const nsCString& GetDomain() const
141 : {
142 0 : return mDomain;
143 : }
144 :
145 98 : nsPrefBranch* GetPrefBranch() const
146 : {
147 98 : return mBranch;
148 : }
149 :
150 : // Has this callback's weak reference died?
151 6 : bool IsExpired() const
152 : {
153 6 : if (!IsWeak())
154 6 : return false;
155 :
156 0 : nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef));
157 0 : return !observer;
158 : }
159 :
160 : enum { ALLOW_MEMMOVE = true };
161 :
162 : private:
163 : nsCString mDomain;
164 : nsPrefBranch *mBranch;
165 :
166 : // Exactly one of mWeakRef and mStrongRef should be non-null.
167 : nsWeakPtr mWeakRef;
168 : nsCOMPtr<nsIObserver> mStrongRef;
169 :
170 : // We need a canonical nsISupports pointer, per bug 578392.
171 : nsISupports *mCanonical;
172 :
173 55 : bool IsWeak() const
174 : {
175 55 : return !!mWeakRef;
176 : }
177 : };
178 :
179 : class nsPrefBranch final : public nsIPrefBranchInternal,
180 : public nsIObserver,
181 : public nsSupportsWeakReference
182 : {
183 : friend class mozilla::PreferenceServiceReporter;
184 : public:
185 : NS_DECL_ISUPPORTS
186 : NS_DECL_NSIPREFBRANCH
187 : NS_DECL_NSIPREFBRANCH2
188 : NS_DECL_NSIOBSERVER
189 :
190 : nsPrefBranch(const char *aPrefRoot, bool aDefaultBranch);
191 : nsPrefBranch() = delete;
192 :
193 49 : int32_t GetRootLength() const { return mPrefRoot.Length(); }
194 :
195 : nsresult RemoveObserverFromMap(const char *aDomain, nsISupports *aObserver);
196 :
197 : static void NotifyObserver(const char *newpref, void *data);
198 :
199 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
200 :
201 : static void ReportToConsole(const nsAString& aMessage);
202 :
203 : protected:
204 : /**
205 : * Helper class for either returning a raw cstring or nsCString.
206 : */
207 : typedef mozilla::Variant<const char*, const nsCString> PrefNameBase;
208 2629 : class PrefName : public PrefNameBase
209 : {
210 : public:
211 2415 : explicit PrefName(const char* aName) : PrefNameBase(aName) {}
212 214 : explicit PrefName(const nsCString& aName) : PrefNameBase(aName) {}
213 :
214 : /**
215 : * Use default move constructors, disallow copy constructors.
216 : */
217 : PrefName(PrefName&& aOther) = default;
218 : PrefName& operator=(PrefName&& aOther) = default;
219 : PrefName(const PrefName&) = delete;
220 : PrefName& operator=(const PrefName&) = delete;
221 :
222 : struct PtrMatcher {
223 47560 : static const char* match(const char* aVal) { return aVal; }
224 39579 : static const char* match(const nsCString& aVal) { return aVal.get(); }
225 : };
226 :
227 : struct LenMatcher {
228 15 : static size_t match(const char* aVal) { return strlen(aVal); }
229 13 : static size_t match(const nsCString& aVal) { return aVal.Length(); }
230 : };
231 :
232 87139 : const char* get() const {
233 : static PtrMatcher m;
234 87139 : return match(m);
235 : }
236 :
237 28 : size_t Length() const {
238 : static LenMatcher m;
239 28 : return match(m);
240 : }
241 : };
242 :
243 : virtual ~nsPrefBranch();
244 :
245 : nsresult GetDefaultFromPropertiesFile(const char *aPrefName, char16_t **return_buf);
246 : // As SetCharPref, but without any check on the length of |aValue|
247 : nsresult SetCharPrefInternal(const char *aPrefName, const char *aValue);
248 : // Reject strings that are more than 1Mb, warn if strings are more than 16kb
249 : nsresult CheckSanityOfStringLength(const char* aPrefName, const nsAString& aValue);
250 : nsresult CheckSanityOfStringLength(const char* aPrefName, const nsACString& aValue);
251 : nsresult CheckSanityOfStringLength(const char* aPrefName, const char* aValue);
252 : nsresult CheckSanityOfStringLength(const char* aPrefName, const uint32_t aLength);
253 : void RemoveExpiredCallback(PrefCallback *aCallback);
254 : PrefName getPrefName(const char *aPrefName) const;
255 : void freeObserverList(void);
256 :
257 : private:
258 : const nsCString mPrefRoot;
259 : bool mIsDefault;
260 :
261 : bool mFreeingObserverList;
262 : nsClassHashtable<PrefCallback, PrefCallback> mObservers;
263 : };
264 :
265 :
266 : class nsPrefLocalizedString final : public nsIPrefLocalizedString,
267 : public nsISupportsString
268 : {
269 : public:
270 : nsPrefLocalizedString();
271 :
272 : NS_DECL_ISUPPORTS
273 40 : NS_FORWARD_NSISUPPORTSSTRING(mUnicodeString->)
274 0 : NS_FORWARD_NSISUPPORTSPRIMITIVE(mUnicodeString->)
275 :
276 : nsresult Init();
277 :
278 : private:
279 : virtual ~nsPrefLocalizedString();
280 :
281 : NS_IMETHOD GetData(char16_t**) override;
282 : NS_IMETHOD SetData(const char16_t* aData) override;
283 : NS_IMETHOD SetDataWithLength(uint32_t aLength, const char16_t *aData) override;
284 :
285 : nsCOMPtr<nsISupportsString> mUnicodeString;
286 : };
287 :
288 :
289 : class nsRelativeFilePref : public nsIRelativeFilePref
290 : {
291 : public:
292 : NS_DECL_ISUPPORTS
293 : NS_DECL_NSIRELATIVEFILEPREF
294 :
295 : nsRelativeFilePref();
296 :
297 : private:
298 : virtual ~nsRelativeFilePref();
299 :
300 : nsCOMPtr<nsIFile> mFile;
301 : nsCString mRelativeToKey;
302 : };
303 :
304 : #endif
|