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 "xpcom-config.h"
8 #include <new>
9 #include "nscore.h"
10 #include "nsCRT.h"
11 
12 #include "nsCommandParams.h"
13 #include "mozilla/HashFunctions.h"
14 
15 using namespace mozilla;
16 
17 const PLDHashTableOps nsCommandParams::sHashOps = {
18     HashKey, HashMatchEntry, HashMoveEntry, HashClearEntry};
19 
NS_IMPL_ISUPPORTS(nsCommandParams,nsICommandParams)20 NS_IMPL_ISUPPORTS(nsCommandParams, nsICommandParams)
21 
22 nsCommandParams::nsCommandParams()
23     : mValuesHash(&sHashOps, sizeof(HashEntry), 2) {}
24 
25 nsCommandParams::~nsCommandParams() = default;
26 
27 NS_IMETHODIMP
GetValueType(const char * aName,int16_t * aRetVal)28 nsCommandParams::GetValueType(const char* aName, int16_t* aRetVal) {
29   NS_ENSURE_ARG_POINTER(aRetVal);
30 
31   HashEntry* foundEntry = GetNamedEntry(aName);
32   if (foundEntry) {
33     *aRetVal = foundEntry->mEntryType;
34     return NS_OK;
35   }
36   *aRetVal = eNoType;
37   return NS_ERROR_FAILURE;
38 }
39 
40 NS_IMETHODIMP
GetBooleanValue(const char * aName,bool * aRetVal)41 nsCommandParams::GetBooleanValue(const char* aName, bool* aRetVal) {
42   NS_ENSURE_ARG_POINTER(aRetVal);
43 
44   ErrorResult error;
45   *aRetVal = GetBool(aName, error);
46   return error.StealNSResult();
47 }
48 
GetBool(const char * aName,ErrorResult & aRv) const49 bool nsCommandParams::GetBool(const char* aName, ErrorResult& aRv) const {
50   MOZ_ASSERT(!aRv.Failed());
51 
52   HashEntry* foundEntry = GetNamedEntry(aName);
53   if (foundEntry && foundEntry->mEntryType == eBooleanType) {
54     return foundEntry->mData.mBoolean;
55   }
56   aRv.Throw(NS_ERROR_FAILURE);
57   return false;
58 }
59 
60 NS_IMETHODIMP
GetLongValue(const char * aName,int32_t * aRetVal)61 nsCommandParams::GetLongValue(const char* aName, int32_t* aRetVal) {
62   NS_ENSURE_ARG_POINTER(aRetVal);
63 
64   ErrorResult error;
65   *aRetVal = GetInt(aName, error);
66   return error.StealNSResult();
67 }
68 
GetInt(const char * aName,ErrorResult & aRv) const69 int32_t nsCommandParams::GetInt(const char* aName, ErrorResult& aRv) const {
70   MOZ_ASSERT(!aRv.Failed());
71 
72   HashEntry* foundEntry = GetNamedEntry(aName);
73   if (foundEntry && foundEntry->mEntryType == eLongType) {
74     return foundEntry->mData.mLong;
75   }
76   aRv.Throw(NS_ERROR_FAILURE);
77   return 0;
78 }
79 
80 NS_IMETHODIMP
GetDoubleValue(const char * aName,double * aRetVal)81 nsCommandParams::GetDoubleValue(const char* aName, double* aRetVal) {
82   NS_ENSURE_ARG_POINTER(aRetVal);
83 
84   ErrorResult error;
85   *aRetVal = GetDouble(aName, error);
86   return error.StealNSResult();
87 }
88 
GetDouble(const char * aName,ErrorResult & aRv) const89 double nsCommandParams::GetDouble(const char* aName, ErrorResult& aRv) const {
90   MOZ_ASSERT(!aRv.Failed());
91 
92   HashEntry* foundEntry = GetNamedEntry(aName);
93   if (foundEntry && foundEntry->mEntryType == eDoubleType) {
94     return foundEntry->mData.mDouble;
95   }
96   aRv.Throw(NS_ERROR_FAILURE);
97   return 0.0;
98 }
99 
100 NS_IMETHODIMP
GetStringValue(const char * aName,nsAString & aRetVal)101 nsCommandParams::GetStringValue(const char* aName, nsAString& aRetVal) {
102   return GetString(aName, aRetVal);
103 }
104 
GetString(const char * aName,nsAString & aRetVal) const105 nsresult nsCommandParams::GetString(const char* aName,
106                                     nsAString& aRetVal) const {
107   HashEntry* foundEntry = GetNamedEntry(aName);
108   if (foundEntry && foundEntry->mEntryType == eWStringType) {
109     NS_ASSERTION(foundEntry->mData.mString, "Null string");
110     aRetVal.Assign(*foundEntry->mData.mString);
111     return NS_OK;
112   }
113   aRetVal.Truncate();
114   return NS_ERROR_FAILURE;
115 }
116 
117 NS_IMETHODIMP
GetCStringValue(const char * aName,nsACString & aRetVal)118 nsCommandParams::GetCStringValue(const char* aName, nsACString& aRetVal) {
119   return GetCString(aName, aRetVal);
120 }
121 
GetCString(const char * aName,nsACString & aRetVal) const122 nsresult nsCommandParams::GetCString(const char* aName,
123                                      nsACString& aRetVal) const {
124   HashEntry* foundEntry = GetNamedEntry(aName);
125   if (foundEntry && foundEntry->mEntryType == eStringType) {
126     NS_ASSERTION(foundEntry->mData.mCString, "Null string");
127     aRetVal.Assign(*foundEntry->mData.mCString);
128     return NS_OK;
129   }
130   aRetVal.Truncate();
131   return NS_ERROR_FAILURE;
132 }
133 
134 NS_IMETHODIMP
GetISupportsValue(const char * aName,nsISupports ** aRetVal)135 nsCommandParams::GetISupportsValue(const char* aName, nsISupports** aRetVal) {
136   NS_ENSURE_ARG_POINTER(aRetVal);
137 
138   ErrorResult error;
139   nsCOMPtr<nsISupports> result = GetISupports(aName, error);
140   if (result) {
141     result.forget(aRetVal);
142   } else {
143     *aRetVal = nullptr;
144   }
145   return error.StealNSResult();
146 }
147 
GetISupports(const char * aName,ErrorResult & aRv) const148 already_AddRefed<nsISupports> nsCommandParams::GetISupports(
149     const char* aName, ErrorResult& aRv) const {
150   MOZ_ASSERT(!aRv.Failed());
151 
152   HashEntry* foundEntry = GetNamedEntry(aName);
153   if (foundEntry && foundEntry->mEntryType == eISupportsType) {
154     nsCOMPtr<nsISupports> result = foundEntry->mISupports;
155     return result.forget();
156   }
157   aRv.Throw(NS_ERROR_FAILURE);
158   return nullptr;
159 }
160 
161 NS_IMETHODIMP
SetBooleanValue(const char * aName,bool aValue)162 nsCommandParams::SetBooleanValue(const char* aName, bool aValue) {
163   return SetBool(aName, aValue);
164 }
165 
SetBool(const char * aName,bool aValue)166 nsresult nsCommandParams::SetBool(const char* aName, bool aValue) {
167   HashEntry* foundEntry = GetOrMakeEntry(aName, eBooleanType);
168   if (!foundEntry) {
169     return NS_ERROR_OUT_OF_MEMORY;
170   }
171   foundEntry->mData.mBoolean = aValue;
172   return NS_OK;
173 }
174 
175 NS_IMETHODIMP
SetLongValue(const char * aName,int32_t aValue)176 nsCommandParams::SetLongValue(const char* aName, int32_t aValue) {
177   return SetInt(aName, aValue);
178 }
179 
SetInt(const char * aName,int32_t aValue)180 nsresult nsCommandParams::SetInt(const char* aName, int32_t aValue) {
181   HashEntry* foundEntry = GetOrMakeEntry(aName, eLongType);
182   if (!foundEntry) {
183     return NS_ERROR_OUT_OF_MEMORY;
184   }
185   foundEntry->mData.mLong = aValue;
186   return NS_OK;
187 }
188 
189 NS_IMETHODIMP
SetDoubleValue(const char * aName,double aValue)190 nsCommandParams::SetDoubleValue(const char* aName, double aValue) {
191   return SetDouble(aName, aValue);
192 }
193 
SetDouble(const char * aName,double aValue)194 nsresult nsCommandParams::SetDouble(const char* aName, double aValue) {
195   HashEntry* foundEntry = GetOrMakeEntry(aName, eDoubleType);
196   if (!foundEntry) {
197     return NS_ERROR_OUT_OF_MEMORY;
198   }
199   foundEntry->mData.mDouble = aValue;
200   return NS_OK;
201 }
202 
203 NS_IMETHODIMP
SetStringValue(const char * aName,const nsAString & aValue)204 nsCommandParams::SetStringValue(const char* aName, const nsAString& aValue) {
205   return SetString(aName, aValue);
206 }
207 
SetString(const char * aName,const nsAString & aValue)208 nsresult nsCommandParams::SetString(const char* aName,
209                                     const nsAString& aValue) {
210   HashEntry* foundEntry = GetOrMakeEntry(aName, eWStringType);
211   if (!foundEntry) {
212     return NS_ERROR_OUT_OF_MEMORY;
213   }
214   foundEntry->mData.mString = new nsString(aValue);
215   return NS_OK;
216 }
217 
218 NS_IMETHODIMP
SetCStringValue(const char * aName,const nsACString & aValue)219 nsCommandParams::SetCStringValue(const char* aName, const nsACString& aValue) {
220   return SetCString(aName, aValue);
221 }
222 
SetCString(const char * aName,const nsACString & aValue)223 nsresult nsCommandParams::SetCString(const char* aName,
224                                      const nsACString& aValue) {
225   HashEntry* foundEntry = GetOrMakeEntry(aName, eStringType);
226   if (!foundEntry) {
227     return NS_ERROR_OUT_OF_MEMORY;
228   }
229   foundEntry->mData.mCString = new nsCString(aValue);
230   return NS_OK;
231 }
232 
233 NS_IMETHODIMP
SetISupportsValue(const char * aName,nsISupports * aValue)234 nsCommandParams::SetISupportsValue(const char* aName, nsISupports* aValue) {
235   return SetISupports(aName, aValue);
236 }
237 
SetISupports(const char * aName,nsISupports * aValue)238 nsresult nsCommandParams::SetISupports(const char* aName, nsISupports* aValue) {
239   HashEntry* foundEntry = GetOrMakeEntry(aName, eISupportsType);
240   if (!foundEntry) {
241     return NS_ERROR_OUT_OF_MEMORY;
242   }
243   foundEntry->mISupports = aValue;  // addrefs
244   return NS_OK;
245 }
246 
247 NS_IMETHODIMP
RemoveValue(const char * aName)248 nsCommandParams::RemoveValue(const char* aName) {
249   mValuesHash.Remove((void*)aName);
250   return NS_OK;
251 }
252 
GetNamedEntry(const char * aName) const253 nsCommandParams::HashEntry* nsCommandParams::GetNamedEntry(
254     const char* aName) const {
255   return static_cast<HashEntry*>(mValuesHash.Search((void*)aName));
256 }
257 
GetOrMakeEntry(const char * aName,uint8_t aEntryType)258 nsCommandParams::HashEntry* nsCommandParams::GetOrMakeEntry(
259     const char* aName, uint8_t aEntryType) {
260   auto foundEntry = static_cast<HashEntry*>(mValuesHash.Search((void*)aName));
261   if (foundEntry) {  // reuse existing entry
262     foundEntry->Reset(aEntryType);
263     return foundEntry;
264   }
265 
266   foundEntry = static_cast<HashEntry*>(mValuesHash.Add((void*)aName, fallible));
267   if (!foundEntry) {
268     return nullptr;
269   }
270 
271   // Use placement new. Our ctor does not clobber keyHash, which is important.
272   new (foundEntry) HashEntry(aEntryType, aName);
273   return foundEntry;
274 }
275 
HashKey(const void * aKey)276 PLDHashNumber nsCommandParams::HashKey(const void* aKey) {
277   return HashString((const char*)aKey);
278 }
279 
HashMatchEntry(const PLDHashEntryHdr * aEntry,const void * aKey)280 bool nsCommandParams::HashMatchEntry(const PLDHashEntryHdr* aEntry,
281                                      const void* aKey) {
282   const char* keyString = (const char*)aKey;
283   const HashEntry* thisEntry = static_cast<const HashEntry*>(aEntry);
284   return thisEntry->mEntryName.Equals(keyString);
285 }
286 
HashMoveEntry(PLDHashTable * aTable,const PLDHashEntryHdr * aFrom,PLDHashEntryHdr * aTo)287 void nsCommandParams::HashMoveEntry(PLDHashTable* aTable,
288                                     const PLDHashEntryHdr* aFrom,
289                                     PLDHashEntryHdr* aTo) {
290   auto* fromEntry =
291       const_cast<HashEntry*>(static_cast<const HashEntry*>(aFrom));
292   HashEntry* toEntry = static_cast<HashEntry*>(aTo);
293 
294   new (KnownNotNull, toEntry) HashEntry(std::move(*fromEntry));
295 
296   fromEntry->~HashEntry();
297 }
298 
HashClearEntry(PLDHashTable * aTable,PLDHashEntryHdr * aEntry)299 void nsCommandParams::HashClearEntry(PLDHashTable* aTable,
300                                      PLDHashEntryHdr* aEntry) {
301   HashEntry* thisEntry = static_cast<HashEntry*>(aEntry);
302   thisEntry->~HashEntry();
303 }
304