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