1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Alec Flett <alecf@netscape.com>
24 : * Brian Nesse <bnesse@netscape.com>
25 : * Benjamin Smedberg <benjamin@smedbergs.us>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "nsCOMPtr.h"
42 : #include "nsIObserver.h"
43 : #include "nsIPrefBranch.h"
44 : #include "nsIPrefBranchInternal.h"
45 : #include "nsIPrefLocalizedString.h"
46 : #include "nsXPCOM.h"
47 : #include "nsISupportsPrimitives.h"
48 : #include "nsIRelativeFilePref.h"
49 : #include "nsILocalFile.h"
50 : #include "nsString.h"
51 : #include "nsVoidArray.h"
52 : #include "nsTArray.h"
53 : #include "nsWeakReference.h"
54 : #include "nsClassHashtable.h"
55 : #include "nsCRT.h"
56 : #include "prbit.h"
57 : #include "nsTraceRefcnt.h"
58 : #include "mozilla/HashFunctions.h"
59 :
60 : class nsPrefBranch;
61 :
62 : class PrefCallback : public PLDHashEntryHdr {
63 :
64 : public:
65 : typedef PrefCallback* KeyType;
66 : typedef const PrefCallback* KeyTypePointer;
67 :
68 319686 : static const PrefCallback* KeyToPointer(PrefCallback *aKey)
69 : {
70 319686 : return aKey;
71 : }
72 :
73 319686 : static PLDHashNumber HashKey(const PrefCallback *aKey)
74 : {
75 319686 : PRUint32 hash = mozilla::HashString(aKey->mDomain);
76 319686 : return mozilla::AddToHash(hash, aKey->mCanonical);
77 : }
78 :
79 :
80 : public:
81 : // Create a PrefCallback with a strong reference to its observer.
82 154350 : PrefCallback(const char *aDomain, nsIObserver *aObserver,
83 : nsPrefBranch *aBranch)
84 : : mDomain(aDomain),
85 : mBranch(aBranch),
86 : mWeakRef(nsnull),
87 154350 : mStrongRef(aObserver)
88 : {
89 154350 : MOZ_COUNT_CTOR(PrefCallback);
90 308700 : nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
91 154350 : mCanonical = canonical;
92 154350 : }
93 :
94 : // Create a PrefCallback with a weak reference to its observer.
95 32031 : PrefCallback(const char *aDomain,
96 : nsISupportsWeakReference *aObserver,
97 : nsPrefBranch *aBranch)
98 : : mDomain(aDomain),
99 : mBranch(aBranch),
100 32031 : mWeakRef(do_GetWeakReference(aObserver)),
101 64062 : mStrongRef(nsnull)
102 : {
103 32031 : MOZ_COUNT_CTOR(PrefCallback);
104 64062 : nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
105 32031 : mCanonical = canonical;
106 32031 : }
107 :
108 : // Copy constructor needs to be explicit or the linker complains.
109 120644 : PrefCallback(const PrefCallback *&aCopy)
110 : : mDomain(aCopy->mDomain),
111 : mBranch(aCopy->mBranch),
112 : mWeakRef(aCopy->mWeakRef),
113 : mStrongRef(aCopy->mStrongRef),
114 120644 : mCanonical(aCopy->mCanonical)
115 : {
116 120644 : MOZ_COUNT_CTOR(PrefCallback);
117 120644 : }
118 :
119 307025 : ~PrefCallback()
120 307025 : {
121 307025 : MOZ_COUNT_DTOR(PrefCallback);
122 307025 : }
123 :
124 25323 : bool KeyEquals(const PrefCallback *aKey) const
125 : {
126 : // We want to be able to look up a weakly-referencing PrefCallback after
127 : // its observer has died so we can remove it from the table. Once the
128 : // callback's observer dies, its canonical pointer is stale -- in
129 : // particular, we may have allocated a new observer in the same spot in
130 : // memory! So we can't just compare canonical pointers to determine
131 : // whether aKey refers to the same observer as this.
132 : //
133 : // Our workaround is based on the way we use this hashtable: When we ask
134 : // the hashtable to remove a PrefCallback whose weak reference has
135 : // expired, we use as the key for removal the same object as was inserted
136 : // into the hashtable. Thus we can say that if one of the keys' weak
137 : // references has expired, the two keys are equal iff they're the same
138 : // object.
139 :
140 25323 : if (IsExpired() || aKey->IsExpired())
141 0 : return this == aKey;
142 :
143 25323 : if (mCanonical != aKey->mCanonical)
144 0 : return false;
145 :
146 25323 : return mDomain.Equals(aKey->mDomain);
147 : }
148 :
149 107983 : PrefCallback *GetKey() const
150 : {
151 107983 : return const_cast<PrefCallback*>(this);
152 : }
153 :
154 : // Get a reference to the callback's observer, or null if the observer was
155 : // weakly referenced and has been destroyed.
156 2512 : already_AddRefed<nsIObserver> GetObserver() const
157 : {
158 2512 : if (!IsWeak()) {
159 4380 : nsCOMPtr<nsIObserver> copy = mStrongRef;
160 2190 : return copy.forget();
161 : }
162 :
163 644 : nsCOMPtr<nsIObserver> observer = do_QueryReferent(mWeakRef);
164 322 : return observer.forget();
165 : }
166 :
167 107983 : const nsCString& GetDomain() const
168 : {
169 107983 : return mDomain;
170 : }
171 :
172 113007 : nsPrefBranch* GetPrefBranch() const
173 : {
174 113007 : return mBranch;
175 : }
176 :
177 : // Has this callback's weak reference died?
178 50646 : bool IsExpired() const
179 : {
180 50646 : if (!IsWeak())
181 50636 : return false;
182 :
183 20 : nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef));
184 10 : return !observer;
185 : }
186 :
187 : enum { ALLOW_MEMMOVE = true };
188 :
189 : private:
190 : nsCString mDomain;
191 : nsPrefBranch *mBranch;
192 :
193 : // Exactly one of mWeakRef and mStrongRef should be non-null.
194 : nsWeakPtr mWeakRef;
195 : nsCOMPtr<nsIObserver> mStrongRef;
196 :
197 : // We need a canonical nsISupports pointer, per bug 578392.
198 : nsISupports *mCanonical;
199 :
200 53158 : bool IsWeak() const
201 : {
202 53158 : return !!mWeakRef;
203 : }
204 : };
205 :
206 : class nsPrefBranch : public nsIPrefBranchInternal,
207 : public nsIObserver,
208 : public nsSupportsWeakReference
209 : {
210 : public:
211 : NS_DECL_ISUPPORTS
212 : NS_DECL_NSIPREFBRANCH
213 : NS_DECL_NSIPREFBRANCH2
214 : NS_DECL_NSIOBSERVER
215 :
216 : nsPrefBranch(const char *aPrefRoot, bool aDefaultBranch);
217 : virtual ~nsPrefBranch();
218 :
219 2512 : PRInt32 GetRootLength() { return mPrefRootLength; }
220 :
221 : nsresult RemoveObserverFromMap(const char *aDomain, nsISupports *aObserver);
222 :
223 : static nsresult NotifyObserver(const char *newpref, void *data);
224 :
225 : protected:
226 : nsPrefBranch() /* disallow use of this constructer */
227 : { }
228 :
229 : nsresult GetDefaultFromPropertiesFile(const char *aPrefName, PRUnichar **return_buf);
230 : void RemoveExpiredCallback(PrefCallback *aCallback);
231 : const char *getPrefName(const char *aPrefName);
232 : void freeObserverList(void);
233 :
234 : friend PLDHashOperator
235 : FreeObserverFunc(PrefCallback *aKey,
236 : nsAutoPtr<PrefCallback> &aCallback,
237 : void *aArgs);
238 :
239 : private:
240 : PRInt32 mPrefRootLength;
241 : nsCString mPrefRoot;
242 : bool mIsDefault;
243 :
244 : bool mFreeingObserverList;
245 : nsClassHashtable<PrefCallback, PrefCallback> mObservers;
246 : };
247 :
248 :
249 : class nsPrefLocalizedString : public nsIPrefLocalizedString,
250 : public nsISupportsString
251 : {
252 : public:
253 : nsPrefLocalizedString();
254 : virtual ~nsPrefLocalizedString();
255 :
256 : NS_DECL_ISUPPORTS
257 1800 : NS_FORWARD_NSISUPPORTSSTRING(mUnicodeString->)
258 0 : NS_FORWARD_NSISUPPORTSPRIMITIVE(mUnicodeString->)
259 :
260 : nsresult Init();
261 :
262 : private:
263 : NS_IMETHOD GetData(PRUnichar**);
264 : NS_IMETHOD SetData(const PRUnichar* aData);
265 : NS_IMETHOD SetDataWithLength(PRUint32 aLength, const PRUnichar *aData);
266 :
267 : nsCOMPtr<nsISupportsString> mUnicodeString;
268 : };
269 :
270 :
271 : class nsRelativeFilePref : public nsIRelativeFilePref
272 : {
273 : public:
274 : NS_DECL_ISUPPORTS
275 : NS_DECL_NSIRELATIVEFILEPREF
276 :
277 : nsRelativeFilePref();
278 : virtual ~nsRelativeFilePref();
279 :
280 : private:
281 : nsCOMPtr<nsILocalFile> mFile;
282 : nsCString mRelativeToKey;
283 : };
|