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 "nsHashPropertyBag.h"
8 : #include "nsArray.h"
9 : #include "nsArrayEnumerator.h"
10 : #include "nsIVariant.h"
11 : #include "nsIProperty.h"
12 : #include "nsThreadUtils.h"
13 : #include "nsVariant.h"
14 : #include "mozilla/Attributes.h"
15 : #include "mozilla/Move.h"
16 :
17 : /*
18 : * nsHashPropertyBagBase implementation.
19 : */
20 :
21 : NS_IMETHODIMP
22 0 : nsHashPropertyBagBase::HasKey(const nsAString& aName, bool* aResult)
23 : {
24 0 : *aResult = mPropertyHash.Get(aName, nullptr);
25 0 : return NS_OK;
26 : }
27 :
28 : NS_IMETHODIMP
29 1 : nsHashPropertyBagBase::Get(const nsAString& aName, nsIVariant** aResult)
30 : {
31 1 : if (!mPropertyHash.Get(aName, aResult)) {
32 0 : *aResult = nullptr;
33 : }
34 :
35 1 : return NS_OK;
36 : }
37 :
38 : NS_IMETHODIMP
39 40 : nsHashPropertyBagBase::GetProperty(const nsAString& aName, nsIVariant** aResult)
40 : {
41 40 : bool isFound = mPropertyHash.Get(aName, aResult);
42 40 : if (!isFound) {
43 7 : return NS_ERROR_FAILURE;
44 : }
45 :
46 33 : return NS_OK;
47 : }
48 :
49 : NS_IMETHODIMP
50 43 : nsHashPropertyBagBase::SetProperty(const nsAString& aName, nsIVariant* aValue)
51 : {
52 43 : if (NS_WARN_IF(!aValue)) {
53 0 : return NS_ERROR_INVALID_ARG;
54 : }
55 :
56 43 : mPropertyHash.Put(aName, aValue);
57 :
58 43 : return NS_OK;
59 : }
60 :
61 : NS_IMETHODIMP
62 0 : nsHashPropertyBagBase::DeleteProperty(const nsAString& aName)
63 : {
64 0 : return mPropertyHash.Remove(aName) ? NS_OK : NS_ERROR_FAILURE;
65 : }
66 :
67 :
68 : //
69 : // nsSimpleProperty class and impl; used for GetEnumerator
70 : //
71 :
72 : class nsSimpleProperty final : public nsIProperty
73 : {
74 0 : ~nsSimpleProperty() {}
75 :
76 : public:
77 0 : nsSimpleProperty(const nsAString& aName, nsIVariant* aValue)
78 0 : : mName(aName)
79 0 : , mValue(aValue)
80 : {
81 0 : }
82 :
83 : NS_DECL_ISUPPORTS
84 : NS_DECL_NSIPROPERTY
85 : protected:
86 : nsString mName;
87 : nsCOMPtr<nsIVariant> mValue;
88 : };
89 :
90 0 : NS_IMPL_ISUPPORTS(nsSimpleProperty, nsIProperty)
91 :
92 : NS_IMETHODIMP
93 0 : nsSimpleProperty::GetName(nsAString& aName)
94 : {
95 0 : aName.Assign(mName);
96 0 : return NS_OK;
97 : }
98 :
99 : NS_IMETHODIMP
100 0 : nsSimpleProperty::GetValue(nsIVariant** aValue)
101 : {
102 0 : NS_IF_ADDREF(*aValue = mValue);
103 0 : return NS_OK;
104 : }
105 :
106 : // end nsSimpleProperty
107 :
108 : NS_IMETHODIMP
109 0 : nsHashPropertyBagBase::GetEnumerator(nsISimpleEnumerator** aResult)
110 : {
111 0 : nsCOMPtr<nsIMutableArray> propertyArray = nsArray::Create();
112 0 : if (!propertyArray) {
113 0 : return NS_ERROR_OUT_OF_MEMORY;
114 : }
115 :
116 0 : for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
117 0 : const nsAString& key = iter.Key();
118 0 : nsIVariant* data = iter.UserData();
119 0 : nsSimpleProperty* sprop = new nsSimpleProperty(key, data);
120 0 : propertyArray->AppendElement(sprop, false);
121 : }
122 :
123 0 : return NS_NewArrayEnumerator(aResult, propertyArray);
124 : }
125 :
126 : #define IMPL_GETSETPROPERTY_AS(Name, Type) \
127 : NS_IMETHODIMP \
128 : nsHashPropertyBagBase::GetPropertyAs ## Name (const nsAString & prop, Type *_retval) \
129 : { \
130 : nsIVariant* v = mPropertyHash.GetWeak(prop); \
131 : if (!v) \
132 : return NS_ERROR_NOT_AVAILABLE; \
133 : return v->GetAs ## Name(_retval); \
134 : } \
135 : \
136 : NS_IMETHODIMP \
137 : nsHashPropertyBagBase::SetPropertyAs ## Name (const nsAString & prop, Type value) \
138 : { \
139 : nsCOMPtr<nsIWritableVariant> var = new nsVariant(); \
140 : var->SetAs ## Name(value); \
141 : return SetProperty(prop, var); \
142 : }
143 :
144 22 : IMPL_GETSETPROPERTY_AS(Int32, int32_t)
145 2 : IMPL_GETSETPROPERTY_AS(Uint32, uint32_t)
146 0 : IMPL_GETSETPROPERTY_AS(Int64, int64_t)
147 2 : IMPL_GETSETPROPERTY_AS(Uint64, uint64_t)
148 0 : IMPL_GETSETPROPERTY_AS(Double, double)
149 34 : IMPL_GETSETPROPERTY_AS(Bool, bool)
150 :
151 :
152 : NS_IMETHODIMP
153 0 : nsHashPropertyBagBase::GetPropertyAsAString(const nsAString& aProp,
154 : nsAString& aResult)
155 : {
156 0 : nsIVariant* v = mPropertyHash.GetWeak(aProp);
157 0 : if (!v) {
158 0 : return NS_ERROR_NOT_AVAILABLE;
159 : }
160 0 : return v->GetAsAString(aResult);
161 : }
162 :
163 : NS_IMETHODIMP
164 25 : nsHashPropertyBagBase::GetPropertyAsACString(const nsAString& aProp,
165 : nsACString& aResult)
166 : {
167 25 : nsIVariant* v = mPropertyHash.GetWeak(aProp);
168 25 : if (!v) {
169 25 : return NS_ERROR_NOT_AVAILABLE;
170 : }
171 0 : return v->GetAsACString(aResult);
172 : }
173 :
174 : NS_IMETHODIMP
175 0 : nsHashPropertyBagBase::GetPropertyAsAUTF8String(const nsAString& aProp,
176 : nsACString& aResult)
177 : {
178 0 : nsIVariant* v = mPropertyHash.GetWeak(aProp);
179 0 : if (!v) {
180 0 : return NS_ERROR_NOT_AVAILABLE;
181 : }
182 0 : return v->GetAsAUTF8String(aResult);
183 : }
184 :
185 : NS_IMETHODIMP
186 28 : nsHashPropertyBagBase::GetPropertyAsInterface(const nsAString& aProp,
187 : const nsIID& aIID,
188 : void** aResult)
189 : {
190 28 : nsIVariant* v = mPropertyHash.GetWeak(aProp);
191 28 : if (!v) {
192 25 : return NS_ERROR_NOT_AVAILABLE;
193 : }
194 6 : nsCOMPtr<nsISupports> val;
195 3 : nsresult rv = v->GetAsISupports(getter_AddRefs(val));
196 3 : if (NS_FAILED(rv)) {
197 0 : return rv;
198 : }
199 3 : if (!val) {
200 : // We have a value, but it's null
201 2 : *aResult = nullptr;
202 2 : return NS_OK;
203 : }
204 1 : return val->QueryInterface(aIID, aResult);
205 : }
206 :
207 : NS_IMETHODIMP
208 0 : nsHashPropertyBagBase::SetPropertyAsAString(const nsAString& aProp,
209 : const nsAString& aValue)
210 : {
211 0 : nsCOMPtr<nsIWritableVariant> var = new nsVariant();
212 0 : var->SetAsAString(aValue);
213 0 : return SetProperty(aProp, var);
214 : }
215 :
216 : NS_IMETHODIMP
217 5 : nsHashPropertyBagBase::SetPropertyAsACString(const nsAString& aProp,
218 : const nsACString& aValue)
219 : {
220 10 : nsCOMPtr<nsIWritableVariant> var = new nsVariant();
221 5 : var->SetAsACString(aValue);
222 10 : return SetProperty(aProp, var);
223 : }
224 :
225 : NS_IMETHODIMP
226 0 : nsHashPropertyBagBase::SetPropertyAsAUTF8String(const nsAString& aProp,
227 : const nsACString& aValue)
228 : {
229 0 : nsCOMPtr<nsIWritableVariant> var = new nsVariant();
230 0 : var->SetAsAUTF8String(aValue);
231 0 : return SetProperty(aProp, var);
232 : }
233 :
234 : NS_IMETHODIMP
235 8 : nsHashPropertyBagBase::SetPropertyAsInterface(const nsAString& aProp,
236 : nsISupports* aValue)
237 : {
238 16 : nsCOMPtr<nsIWritableVariant> var = new nsVariant();
239 8 : var->SetAsISupports(aValue);
240 16 : return SetProperty(aProp, var);
241 : }
242 :
243 :
244 : /*
245 : * nsHashPropertyBag implementation.
246 : */
247 :
248 9286 : NS_IMPL_ADDREF(nsHashPropertyBag)
249 9214 : NS_IMPL_RELEASE(nsHashPropertyBag)
250 :
251 1699 : NS_INTERFACE_MAP_BEGIN(nsHashPropertyBag)
252 1699 : NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
253 1699 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
254 1699 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
255 1596 : NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
256 1538 : NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
257 1529 : NS_INTERFACE_MAP_END
258 :
259 : /*
260 : * We need to ensure that the hashtable is destroyed on the main thread, as
261 : * the nsIVariant values are main-thread only objects.
262 : */
263 0 : class ProxyHashtableDestructor final : public mozilla::Runnable
264 : {
265 : public:
266 : using HashtableType = nsInterfaceHashtable<nsStringHashKey, nsIVariant>;
267 0 : explicit ProxyHashtableDestructor(HashtableType&& aTable)
268 0 : : mozilla::Runnable("ProxyHashtableDestructor")
269 0 : , mPropertyHash(mozilla::Move(aTable))
270 0 : {}
271 :
272 : NS_IMETHODIMP
273 0 : Run()
274 : {
275 0 : MOZ_ASSERT(NS_IsMainThread());
276 0 : HashtableType table(mozilla::Move(mPropertyHash));
277 0 : return NS_OK;
278 : }
279 :
280 : private:
281 : HashtableType mPropertyHash;
282 : };
283 :
284 2312 : nsHashPropertyBag::~nsHashPropertyBag()
285 : {
286 1156 : if (!NS_IsMainThread()) {
287 : RefPtr<ProxyHashtableDestructor> runnable =
288 0 : new ProxyHashtableDestructor(mozilla::Move(mPropertyHash));
289 0 : MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
290 : }
291 1156 : }
292 :
293 : /*
294 : * nsHashPropertyBagCC implementation.
295 : */
296 :
297 0 : NS_IMPL_CYCLE_COLLECTION(nsHashPropertyBagCC, mPropertyHash)
298 :
299 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHashPropertyBagCC)
300 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHashPropertyBagCC)
301 :
302 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsHashPropertyBagCC)
303 0 : NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag)
304 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIPropertyBag, nsIWritablePropertyBag)
305 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWritablePropertyBag)
306 0 : NS_INTERFACE_MAP_ENTRY(nsIPropertyBag2)
307 0 : NS_INTERFACE_MAP_ENTRY(nsIWritablePropertyBag2)
308 0 : NS_INTERFACE_MAP_END
|