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 : public nsISimpleEnumerator,
18                             public nsIUTF8StringEnumerator,
19                             public nsIStringEnumerator {
20  public:
EmptyEnumeratorImpl()21   EmptyEnumeratorImpl() {}
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   // can't use NS_DECL_NSISTRINGENUMERATOR because they share the
30   // HasMore() signature
31 
32   NS_IMETHOD GetNext(nsAString& aResult) override;
33 
GetInstance()34   static EmptyEnumeratorImpl* GetInstance() {
35     static const EmptyEnumeratorImpl kInstance;
36     return const_cast<EmptyEnumeratorImpl*>(&kInstance);
37   }
38 };
39 
40 // nsISupports interface
NS_IMETHODIMP_(MozExternalRefCountType)41 NS_IMETHODIMP_(MozExternalRefCountType)
42 EmptyEnumeratorImpl::AddRef(void) { return 2; }
43 
NS_IMETHODIMP_(MozExternalRefCountType)44 NS_IMETHODIMP_(MozExternalRefCountType)
45 EmptyEnumeratorImpl::Release(void) { return 1; }
46 
NS_IMPL_QUERY_INTERFACE(EmptyEnumeratorImpl,nsISimpleEnumerator,nsIUTF8StringEnumerator,nsIStringEnumerator)47 NS_IMPL_QUERY_INTERFACE(EmptyEnumeratorImpl, nsISimpleEnumerator,
48                         nsIUTF8StringEnumerator, nsIStringEnumerator)
49 
50 // nsISimpleEnumerator interface
51 NS_IMETHODIMP
52 EmptyEnumeratorImpl::HasMoreElements(bool* aResult) {
53   *aResult = false;
54   return NS_OK;
55 }
56 
57 NS_IMETHODIMP
HasMore(bool * aResult)58 EmptyEnumeratorImpl::HasMore(bool* aResult) {
59   *aResult = false;
60   return NS_OK;
61 }
62 
63 NS_IMETHODIMP
GetNext(nsISupports ** aResult)64 EmptyEnumeratorImpl::GetNext(nsISupports** aResult) {
65   return NS_ERROR_UNEXPECTED;
66 }
67 
68 NS_IMETHODIMP
GetNext(nsACString & aResult)69 EmptyEnumeratorImpl::GetNext(nsACString& aResult) {
70   return NS_ERROR_UNEXPECTED;
71 }
72 
73 NS_IMETHODIMP
GetNext(nsAString & aResult)74 EmptyEnumeratorImpl::GetNext(nsAString& aResult) { return NS_ERROR_UNEXPECTED; }
75 
NS_NewEmptyEnumerator(nsISimpleEnumerator ** aResult)76 nsresult NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult) {
77   *aResult = EmptyEnumeratorImpl::GetInstance();
78   return NS_OK;
79 }
80 
81 ////////////////////////////////////////////////////////////////////////////////
82 
83 class nsSingletonEnumerator final : public nsISimpleEnumerator {
84  public:
85   NS_DECL_ISUPPORTS
86 
87   // nsISimpleEnumerator methods
88   NS_IMETHOD HasMoreElements(bool* aResult) override;
89   NS_IMETHOD GetNext(nsISupports** aResult) override;
90 
91   explicit nsSingletonEnumerator(nsISupports* aValue);
92 
93  private:
94   ~nsSingletonEnumerator();
95 
96  protected:
97   nsCOMPtr<nsISupports> mValue;
98   bool mConsumed;
99 };
100 
nsSingletonEnumerator(nsISupports * aValue)101 nsSingletonEnumerator::nsSingletonEnumerator(nsISupports* aValue)
102     : mValue(aValue) {
103   mConsumed = (mValue ? false : true);
104 }
105 
106 nsSingletonEnumerator::~nsSingletonEnumerator() = default;
107 
NS_IMPL_ISUPPORTS(nsSingletonEnumerator,nsISimpleEnumerator)108 NS_IMPL_ISUPPORTS(nsSingletonEnumerator, nsISimpleEnumerator)
109 
110 NS_IMETHODIMP
111 nsSingletonEnumerator::HasMoreElements(bool* aResult) {
112   NS_PRECONDITION(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   NS_PRECONDITION(aResult != 0, "null ptr");
124   if (!aResult) {
125     return NS_ERROR_NULL_POINTER;
126   }
127 
128   if (mConsumed) {
129     return NS_ERROR_UNEXPECTED;
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 nsISimpleEnumerator {
149  public:
150   NS_DECL_ISUPPORTS
151 
152   // nsISimpleEnumerator methods
153   NS_IMETHOD HasMoreElements(bool* aResult) override;
154   NS_IMETHOD GetNext(nsISupports** aResult) override;
155 
156   nsUnionEnumerator(nsISimpleEnumerator* aFirstEnumerator,
157                     nsISimpleEnumerator* aSecondEnumerator);
158 
159  private:
160   ~nsUnionEnumerator();
161 
162  protected:
163   nsCOMPtr<nsISimpleEnumerator> mFirstEnumerator, mSecondEnumerator;
164   bool mConsumed;
165   bool mAtSecond;
166 };
167 
nsUnionEnumerator(nsISimpleEnumerator * aFirstEnumerator,nsISimpleEnumerator * aSecondEnumerator)168 nsUnionEnumerator::nsUnionEnumerator(nsISimpleEnumerator* aFirstEnumerator,
169                                      nsISimpleEnumerator* aSecondEnumerator)
170     : mFirstEnumerator(aFirstEnumerator),
171       mSecondEnumerator(aSecondEnumerator),
172       mConsumed(false),
173       mAtSecond(false) {}
174 
175 nsUnionEnumerator::~nsUnionEnumerator() = default;
176 
NS_IMPL_ISUPPORTS(nsUnionEnumerator,nsISimpleEnumerator)177 NS_IMPL_ISUPPORTS(nsUnionEnumerator, nsISimpleEnumerator)
178 
179 NS_IMETHODIMP
180 nsUnionEnumerator::HasMoreElements(bool* aResult) {
181   NS_PRECONDITION(aResult != 0, "null ptr");
182   if (!aResult) {
183     return NS_ERROR_NULL_POINTER;
184   }
185 
186   nsresult rv;
187 
188   if (mConsumed) {
189     *aResult = false;
190     return NS_OK;
191   }
192 
193   if (!mAtSecond) {
194     rv = mFirstEnumerator->HasMoreElements(aResult);
195     if (NS_FAILED(rv)) {
196       return rv;
197     }
198 
199     if (*aResult) {
200       return NS_OK;
201     }
202 
203     mAtSecond = true;
204   }
205 
206   rv = mSecondEnumerator->HasMoreElements(aResult);
207   if (NS_FAILED(rv)) {
208     return rv;
209   }
210 
211   if (*aResult) {
212     return NS_OK;
213   }
214 
215   *aResult = false;
216   mConsumed = true;
217   return NS_OK;
218 }
219 
220 NS_IMETHODIMP
GetNext(nsISupports ** aResult)221 nsUnionEnumerator::GetNext(nsISupports** aResult) {
222   NS_PRECONDITION(aResult != 0, "null ptr");
223   if (!aResult) {
224     return NS_ERROR_NULL_POINTER;
225   }
226 
227   if (mConsumed) {
228     return NS_ERROR_UNEXPECTED;
229   }
230 
231   if (!mAtSecond) {
232     return mFirstEnumerator->GetNext(aResult);
233   }
234 
235   return mSecondEnumerator->GetNext(aResult);
236 }
237 
NS_NewUnionEnumerator(nsISimpleEnumerator ** aResult,nsISimpleEnumerator * aFirstEnumerator,nsISimpleEnumerator * aSecondEnumerator)238 nsresult NS_NewUnionEnumerator(nsISimpleEnumerator** aResult,
239                                nsISimpleEnumerator* aFirstEnumerator,
240                                nsISimpleEnumerator* aSecondEnumerator) {
241   *aResult = nullptr;
242   if (!aFirstEnumerator) {
243     *aResult = aSecondEnumerator;
244   } else if (!aSecondEnumerator) {
245     *aResult = aFirstEnumerator;
246   } else {
247     auto* enumer = new nsUnionEnumerator(aFirstEnumerator, aSecondEnumerator);
248     if (!enumer) {
249       return NS_ERROR_OUT_OF_MEMORY;
250     }
251     *aResult = enumer;
252   }
253   NS_ADDREF(*aResult);
254   return NS_OK;
255 }
256