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/. */
7 #include "nsStringEnumerator.h"
8 #include "nsSimpleEnumerator.h"
9 #include "nsSupportsPrimitives.h"
10 #include "mozilla/Attributes.h"
11 #include "mozilla/ResultExtensions.h"
12 #include "mozilla/Try.h"
13 #include "mozilla/dom/IteratorResultBinding.h"
14 #include "mozilla/dom/RootedDictionary.h"
15 #include "mozilla/dom/ToJSValue.h"
18 using namespace mozilla
;
19 using namespace mozilla::dom
;
23 class JSStringEnumerator final
: public nsIJSEnumerator
{
25 NS_DECL_NSIJSENUMERATOR
27 explicit JSStringEnumerator(nsIStringEnumerator
* aEnumerator
)
28 : mEnumerator(aEnumerator
) {
29 MOZ_ASSERT(mEnumerator
);
33 ~JSStringEnumerator() = default;
35 nsCOMPtr
<nsIStringEnumerator
> mEnumerator
;
38 } // anonymous namespace
40 nsresult
JSStringEnumerator::Iterator(nsIJSEnumerator
** aResult
) {
41 RefPtr
<JSStringEnumerator
> result(this);
42 result
.forget(aResult
);
46 nsresult
JSStringEnumerator::Next(JSContext
* aCx
,
47 JS::MutableHandleValue aResult
) {
48 RootedDictionary
<IteratorResult
> result(aCx
);
51 if (NS_FAILED(mEnumerator
->GetNext(elem
))) {
58 JS::MutableHandleValue::fromMarkedLocation(&result
.mValue
))) {
59 return NS_ERROR_OUT_OF_MEMORY
;
63 if (!ToJSValue(aCx
, result
, aResult
)) {
64 return NS_ERROR_OUT_OF_MEMORY
;
69 NS_IMPL_ISUPPORTS(JSStringEnumerator
, nsIJSEnumerator
)
72 // nsStringEnumeratorBase
75 nsresult
nsStringEnumeratorBase::GetNext(nsAString
& aResult
) {
77 MOZ_TRY(GetNext(str
));
79 CopyUTF8toUTF16(str
, aResult
);
84 nsStringEnumeratorBase::StringIterator(nsIJSEnumerator
** aRetVal
) {
85 auto result
= MakeRefPtr
<JSStringEnumerator
>(this);
86 result
.forget(aRetVal
);
94 class nsStringEnumerator final
: public nsSimpleEnumerator
,
95 public nsIStringEnumerator
,
96 public nsIUTF8StringEnumerator
{
98 nsStringEnumerator(const nsTArray
<nsString
>* aArray
, bool aOwnsArray
)
99 : mArray(aArray
), mIndex(0), mOwnsArray(aOwnsArray
), mIsUnicode(true) {}
101 nsStringEnumerator(const nsTArray
<nsCString
>* aArray
, bool aOwnsArray
)
102 : mCArray(aArray
), mIndex(0), mOwnsArray(aOwnsArray
), mIsUnicode(false) {}
104 nsStringEnumerator(const nsTArray
<nsString
>* aArray
, nsISupports
* aOwner
)
111 nsStringEnumerator(const nsTArray
<nsCString
>* aArray
, nsISupports
* aOwner
)
118 NS_DECL_ISUPPORTS_INHERITED
119 NS_DECL_NSIUTF8STRINGENUMERATOR
120 NS_DECL_NSISTRINGENUMERATORBASE
122 // have to declare nsIStringEnumerator manually, because of
123 // overlapping method names
124 NS_IMETHOD
GetNext(nsAString
& aResult
) override
;
125 NS_DECL_NSISIMPLEENUMERATOR
127 const nsID
& DefaultInterface() override
{
129 return NS_GET_IID(nsISupportsString
);
131 return NS_GET_IID(nsISupportsCString
);
135 ~nsStringEnumerator() {
137 // const-casting is safe here, because the NS_New*
138 // constructors make sure mOwnsArray is consistent with
139 // the constness of the objects
141 delete const_cast<nsTArray
<nsString
>*>(mArray
);
143 delete const_cast<nsTArray
<nsCString
>*>(mCArray
);
149 const nsTArray
<nsString
>* mArray
;
150 const nsTArray
<nsCString
>* mCArray
;
153 inline uint32_t Count() {
154 return mIsUnicode
? mArray
->Length() : mCArray
->Length();
159 // the owner allows us to hold a strong reference to the object
160 // that owns the array. Having a non-null value in mOwner implies
161 // that mOwnsArray is false, because we rely on the real owner
162 // to release the array
163 nsCOMPtr
<nsISupports
> mOwner
;
168 NS_IMPL_ISUPPORTS_INHERITED(nsStringEnumerator
, nsSimpleEnumerator
,
169 nsIStringEnumerator
, nsIUTF8StringEnumerator
)
172 nsStringEnumerator::HasMore(bool* aResult
) {
173 *aResult
= mIndex
< Count();
178 nsStringEnumerator::HasMoreElements(bool* aResult
) { return HasMore(aResult
); }
181 nsStringEnumerator::GetNext(nsISupports
** aResult
) {
182 if (mIndex
>= mArray
->Length()) {
183 return NS_ERROR_FAILURE
;
187 nsSupportsString
* stringImpl
= new nsSupportsString();
189 stringImpl
->SetData(mArray
->ElementAt(mIndex
++));
190 *aResult
= stringImpl
;
192 nsSupportsCString
* cstringImpl
= new nsSupportsCString();
194 cstringImpl
->SetData(mCArray
->ElementAt(mIndex
++));
195 *aResult
= cstringImpl
;
202 nsStringEnumerator::GetNext(nsAString
& aResult
) {
203 if (NS_WARN_IF(mIndex
>= Count())) {
204 return NS_ERROR_UNEXPECTED
;
208 aResult
= mArray
->ElementAt(mIndex
++);
210 CopyUTF8toUTF16(mCArray
->ElementAt(mIndex
++), aResult
);
217 nsStringEnumerator::GetNext(nsACString
& aResult
) {
218 if (NS_WARN_IF(mIndex
>= Count())) {
219 return NS_ERROR_UNEXPECTED
;
223 CopyUTF16toUTF8(mArray
->ElementAt(mIndex
++), aResult
);
225 aResult
= mCArray
->ElementAt(mIndex
++);
232 nsStringEnumerator::StringIterator(nsIJSEnumerator
** aRetVal
) {
233 auto result
= MakeRefPtr
<JSStringEnumerator
>(this);
234 result
.forget(aRetVal
);
239 static inline nsresult
StringEnumeratorTail(T
** aResult
) {
241 return NS_ERROR_OUT_OF_MEMORY
;
251 nsresult
NS_NewStringEnumerator(nsIStringEnumerator
** aResult
,
252 const nsTArray
<nsString
>* aArray
,
253 nsISupports
* aOwner
) {
254 if (NS_WARN_IF(!aResult
) || NS_WARN_IF(!aArray
)) {
255 return NS_ERROR_INVALID_ARG
;
258 *aResult
= new nsStringEnumerator(aArray
, aOwner
);
259 return StringEnumeratorTail(aResult
);
262 nsresult
NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator
** aResult
,
263 const nsTArray
<nsCString
>* aArray
,
264 nsISupports
* aOwner
) {
265 if (NS_WARN_IF(!aResult
) || NS_WARN_IF(!aArray
)) {
266 return NS_ERROR_INVALID_ARG
;
269 *aResult
= new nsStringEnumerator(aArray
, aOwner
);
270 return StringEnumeratorTail(aResult
);
273 nsresult
NS_NewAdoptingStringEnumerator(nsIStringEnumerator
** aResult
,
274 nsTArray
<nsString
>* aArray
) {
275 if (NS_WARN_IF(!aResult
) || NS_WARN_IF(!aArray
)) {
276 return NS_ERROR_INVALID_ARG
;
279 *aResult
= new nsStringEnumerator(aArray
, true);
280 return StringEnumeratorTail(aResult
);
283 nsresult
NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator
** aResult
,
284 nsTArray
<nsCString
>* aArray
) {
285 if (NS_WARN_IF(!aResult
) || NS_WARN_IF(!aArray
)) {
286 return NS_ERROR_INVALID_ARG
;
289 *aResult
= new nsStringEnumerator(aArray
, true);
290 return StringEnumeratorTail(aResult
);
293 // const ones internally just forward to the non-const equivalents
294 nsresult
NS_NewStringEnumerator(nsIStringEnumerator
** aResult
,
295 const nsTArray
<nsString
>* aArray
) {
296 if (NS_WARN_IF(!aResult
) || NS_WARN_IF(!aArray
)) {
297 return NS_ERROR_INVALID_ARG
;
300 *aResult
= new nsStringEnumerator(aArray
, false);
301 return StringEnumeratorTail(aResult
);
304 nsresult
NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator
** aResult
,
305 const nsTArray
<nsCString
>* aArray
) {
306 if (NS_WARN_IF(!aResult
) || NS_WARN_IF(!aArray
)) {
307 return NS_ERROR_INVALID_ARG
;
310 *aResult
= new nsStringEnumerator(aArray
, false);
311 return StringEnumeratorTail(aResult
);