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/Attributes.h"
8 
9 #include "nsEnumeratorUtils.h"
10 
11 #include "nsISimpleEnumerator.h"
12 #include "nsIStringEnumerator.h"
13 
14 #include "nsCOMPtr.h"
15 #include "mozilla/RefPtr.h"
16 
17 class EmptyEnumeratorImpl
18   : public nsISimpleEnumerator
19   , public nsIUTF8StringEnumerator
20   , public nsIStringEnumerator
21 {
22 public:
EmptyEnumeratorImpl()23   EmptyEnumeratorImpl() {}
24 
25   // nsISupports interface
26   NS_DECL_ISUPPORTS_INHERITED  // not really inherited, but no mRefCnt
27 
28   // nsISimpleEnumerator
29   NS_DECL_NSISIMPLEENUMERATOR
30   NS_DECL_NSIUTF8STRINGENUMERATOR
31   // can't use NS_DECL_NSISTRINGENUMERATOR because they share the
32   // HasMore() signature
33   NS_IMETHOD GetNext(nsAString& aResult) override;
34 
GetInstance()35   static EmptyEnumeratorImpl* GetInstance()
36   {
37     static const EmptyEnumeratorImpl kInstance;
38     return const_cast<EmptyEnumeratorImpl*>(&kInstance);
39   }
40 };
41 
42 // nsISupports interface
NS_IMETHODIMP_(MozExternalRefCountType)43 NS_IMETHODIMP_(MozExternalRefCountType)
44 EmptyEnumeratorImpl::AddRef(void)
45 {
46   return 2;
47 }
48 
NS_IMETHODIMP_(MozExternalRefCountType)49 NS_IMETHODIMP_(MozExternalRefCountType)
50 EmptyEnumeratorImpl::Release(void)
51 {
52   return 1;
53 }
54 
NS_IMPL_QUERY_INTERFACE(EmptyEnumeratorImpl,nsISimpleEnumerator,nsIUTF8StringEnumerator,nsIStringEnumerator)55 NS_IMPL_QUERY_INTERFACE(EmptyEnumeratorImpl, nsISimpleEnumerator,
56                         nsIUTF8StringEnumerator, nsIStringEnumerator)
57 
58 // nsISimpleEnumerator interface
59 NS_IMETHODIMP
60 EmptyEnumeratorImpl::HasMoreElements(bool* aResult)
61 {
62   *aResult = false;
63   return NS_OK;
64 }
65 
66 NS_IMETHODIMP
HasMore(bool * aResult)67 EmptyEnumeratorImpl::HasMore(bool* aResult)
68 {
69   *aResult = false;
70   return NS_OK;
71 }
72 
73 NS_IMETHODIMP
GetNext(nsISupports ** aResult)74 EmptyEnumeratorImpl::GetNext(nsISupports** aResult)
75 {
76   return NS_ERROR_UNEXPECTED;
77 }
78 
79 NS_IMETHODIMP
GetNext(nsACString & aResult)80 EmptyEnumeratorImpl::GetNext(nsACString& aResult)
81 {
82   return NS_ERROR_UNEXPECTED;
83 }
84 
85 NS_IMETHODIMP
GetNext(nsAString & aResult)86 EmptyEnumeratorImpl::GetNext(nsAString& aResult)
87 {
88   return NS_ERROR_UNEXPECTED;
89 }
90 
91 nsresult
NS_NewEmptyEnumerator(nsISimpleEnumerator ** aResult)92 NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult)
93 {
94   *aResult = EmptyEnumeratorImpl::GetInstance();
95   return NS_OK;
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 
100 class nsSingletonEnumerator final : public nsISimpleEnumerator
101 {
102 public:
103   NS_DECL_ISUPPORTS
104 
105   // nsISimpleEnumerator methods
106   NS_IMETHOD HasMoreElements(bool* aResult) override;
107   NS_IMETHOD GetNext(nsISupports** aResult) override;
108 
109   explicit nsSingletonEnumerator(nsISupports* aValue);
110 
111 private:
112   ~nsSingletonEnumerator();
113 
114 protected:
115   nsCOMPtr<nsISupports> mValue;
116   bool mConsumed;
117 };
118 
nsSingletonEnumerator(nsISupports * aValue)119 nsSingletonEnumerator::nsSingletonEnumerator(nsISupports* aValue)
120   : mValue(aValue)
121 {
122   mConsumed = (mValue ? false : true);
123 }
124 
~nsSingletonEnumerator()125 nsSingletonEnumerator::~nsSingletonEnumerator()
126 {
127 }
128 
NS_IMPL_ISUPPORTS(nsSingletonEnumerator,nsISimpleEnumerator)129 NS_IMPL_ISUPPORTS(nsSingletonEnumerator, nsISimpleEnumerator)
130 
131 NS_IMETHODIMP
132 nsSingletonEnumerator::HasMoreElements(bool* aResult)
133 {
134   NS_PRECONDITION(aResult != 0, "null ptr");
135   if (!aResult) {
136     return NS_ERROR_NULL_POINTER;
137   }
138 
139   *aResult = !mConsumed;
140   return NS_OK;
141 }
142 
143 
144 NS_IMETHODIMP
GetNext(nsISupports ** aResult)145 nsSingletonEnumerator::GetNext(nsISupports** aResult)
146 {
147   NS_PRECONDITION(aResult != 0, "null ptr");
148   if (!aResult) {
149     return NS_ERROR_NULL_POINTER;
150   }
151 
152   if (mConsumed) {
153     return NS_ERROR_UNEXPECTED;
154   }
155 
156   mConsumed = true;
157 
158   *aResult = mValue;
159   NS_ADDREF(*aResult);
160   return NS_OK;
161 }
162 
163 nsresult
NS_NewSingletonEnumerator(nsISimpleEnumerator ** aResult,nsISupports * aSingleton)164 NS_NewSingletonEnumerator(nsISimpleEnumerator** aResult,
165                           nsISupports* aSingleton)
166 {
167   RefPtr<nsSingletonEnumerator> enumer = new nsSingletonEnumerator(aSingleton);
168   enumer.forget(aResult);
169   return NS_OK;
170 }
171 
172 ////////////////////////////////////////////////////////////////////////////////
173 
174 class nsUnionEnumerator final : public nsISimpleEnumerator
175 {
176 public:
177   NS_DECL_ISUPPORTS
178 
179   // nsISimpleEnumerator methods
180   NS_IMETHOD HasMoreElements(bool* aResult) override;
181   NS_IMETHOD GetNext(nsISupports** aResult) override;
182 
183   nsUnionEnumerator(nsISimpleEnumerator* aFirstEnumerator,
184                     nsISimpleEnumerator* aSecondEnumerator);
185 
186 private:
187   ~nsUnionEnumerator();
188 
189 protected:
190   nsCOMPtr<nsISimpleEnumerator> mFirstEnumerator, mSecondEnumerator;
191   bool mConsumed;
192   bool mAtSecond;
193 };
194 
nsUnionEnumerator(nsISimpleEnumerator * aFirstEnumerator,nsISimpleEnumerator * aSecondEnumerator)195 nsUnionEnumerator::nsUnionEnumerator(nsISimpleEnumerator* aFirstEnumerator,
196                                      nsISimpleEnumerator* aSecondEnumerator)
197   : mFirstEnumerator(aFirstEnumerator)
198   , mSecondEnumerator(aSecondEnumerator)
199   , mConsumed(false)
200   , mAtSecond(false)
201 {
202 }
203 
~nsUnionEnumerator()204 nsUnionEnumerator::~nsUnionEnumerator()
205 {
206 }
207 
NS_IMPL_ISUPPORTS(nsUnionEnumerator,nsISimpleEnumerator)208 NS_IMPL_ISUPPORTS(nsUnionEnumerator, nsISimpleEnumerator)
209 
210 NS_IMETHODIMP
211 nsUnionEnumerator::HasMoreElements(bool* aResult)
212 {
213   NS_PRECONDITION(aResult != 0, "null ptr");
214   if (!aResult) {
215     return NS_ERROR_NULL_POINTER;
216   }
217 
218   nsresult rv;
219 
220   if (mConsumed) {
221     *aResult = false;
222     return NS_OK;
223   }
224 
225   if (!mAtSecond) {
226     rv = mFirstEnumerator->HasMoreElements(aResult);
227     if (NS_FAILED(rv)) {
228       return rv;
229     }
230 
231     if (*aResult) {
232       return NS_OK;
233     }
234 
235     mAtSecond = true;
236   }
237 
238   rv = mSecondEnumerator->HasMoreElements(aResult);
239   if (NS_FAILED(rv)) {
240     return rv;
241   }
242 
243   if (*aResult) {
244     return NS_OK;
245   }
246 
247   *aResult = false;
248   mConsumed = true;
249   return NS_OK;
250 }
251 
252 NS_IMETHODIMP
GetNext(nsISupports ** aResult)253 nsUnionEnumerator::GetNext(nsISupports** aResult)
254 {
255   NS_PRECONDITION(aResult != 0, "null ptr");
256   if (!aResult) {
257     return NS_ERROR_NULL_POINTER;
258   }
259 
260   if (mConsumed) {
261     return NS_ERROR_UNEXPECTED;
262   }
263 
264   if (!mAtSecond) {
265     return mFirstEnumerator->GetNext(aResult);
266   }
267 
268   return mSecondEnumerator->GetNext(aResult);
269 }
270 
271 nsresult
NS_NewUnionEnumerator(nsISimpleEnumerator ** aResult,nsISimpleEnumerator * aFirstEnumerator,nsISimpleEnumerator * aSecondEnumerator)272 NS_NewUnionEnumerator(nsISimpleEnumerator** aResult,
273                       nsISimpleEnumerator* aFirstEnumerator,
274                       nsISimpleEnumerator* aSecondEnumerator)
275 {
276   *aResult = nullptr;
277   if (!aFirstEnumerator) {
278     *aResult = aSecondEnumerator;
279   } else if (!aSecondEnumerator) {
280     *aResult = aFirstEnumerator;
281   } else {
282     nsUnionEnumerator* enumer = new nsUnionEnumerator(aFirstEnumerator,
283                                                       aSecondEnumerator);
284     if (!enumer) {
285       return NS_ERROR_OUT_OF_MEMORY;
286     }
287     *aResult = enumer;
288   }
289   NS_ADDREF(*aResult);
290   return NS_OK;
291 }
292