Bug 1874684 - Part 31: Correctly reject invalid durations in some RoundDuration calls...
[gecko.git] / xpcom / ds / nsStringEnumerator.cpp
blob34576c7f50f254a3c03f56f22ff501d03c6dd6db
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"
16 #include "nsTArray.h"
18 using namespace mozilla;
19 using namespace mozilla::dom;
21 namespace {
23 class JSStringEnumerator final : public nsIJSEnumerator {
24 NS_DECL_ISUPPORTS
25 NS_DECL_NSIJSENUMERATOR
27 explicit JSStringEnumerator(nsIStringEnumerator* aEnumerator)
28 : mEnumerator(aEnumerator) {
29 MOZ_ASSERT(mEnumerator);
32 private:
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);
43 return NS_OK;
46 nsresult JSStringEnumerator::Next(JSContext* aCx,
47 JS::MutableHandleValue aResult) {
48 RootedDictionary<IteratorResult> result(aCx);
50 nsAutoString elem;
51 if (NS_FAILED(mEnumerator->GetNext(elem))) {
52 result.mDone = true;
53 } else {
54 result.mDone = false;
56 if (!ToJSValue(
57 aCx, 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;
66 return NS_OK;
69 NS_IMPL_ISUPPORTS(JSStringEnumerator, nsIJSEnumerator)
72 // nsStringEnumeratorBase
75 nsresult nsStringEnumeratorBase::GetNext(nsAString& aResult) {
76 nsAutoCString str;
77 MOZ_TRY(GetNext(str));
79 CopyUTF8toUTF16(str, aResult);
80 return NS_OK;
83 NS_IMETHODIMP
84 nsStringEnumeratorBase::StringIterator(nsIJSEnumerator** aRetVal) {
85 auto result = MakeRefPtr<JSStringEnumerator>(this);
86 result.forget(aRetVal);
87 return NS_OK;
91 // nsStringEnumerator
94 class nsStringEnumerator final : public nsSimpleEnumerator,
95 public nsIStringEnumerator,
96 public nsIUTF8StringEnumerator {
97 public:
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)
105 : mArray(aArray),
106 mIndex(0),
107 mOwner(aOwner),
108 mOwnsArray(false),
109 mIsUnicode(true) {}
111 nsStringEnumerator(const nsTArray<nsCString>* aArray, nsISupports* aOwner)
112 : mCArray(aArray),
113 mIndex(0),
114 mOwner(aOwner),
115 mOwnsArray(false),
116 mIsUnicode(false) {}
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 {
128 if (mIsUnicode) {
129 return NS_GET_IID(nsISupportsString);
131 return NS_GET_IID(nsISupportsCString);
134 private:
135 ~nsStringEnumerator() {
136 if (mOwnsArray) {
137 // const-casting is safe here, because the NS_New*
138 // constructors make sure mOwnsArray is consistent with
139 // the constness of the objects
140 if (mIsUnicode) {
141 delete const_cast<nsTArray<nsString>*>(mArray);
142 } else {
143 delete const_cast<nsTArray<nsCString>*>(mCArray);
148 union {
149 const nsTArray<nsString>* mArray;
150 const nsTArray<nsCString>* mCArray;
153 inline uint32_t Count() {
154 return mIsUnicode ? mArray->Length() : mCArray->Length();
157 uint32_t mIndex;
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;
164 bool mOwnsArray;
165 bool mIsUnicode;
168 NS_IMPL_ISUPPORTS_INHERITED(nsStringEnumerator, nsSimpleEnumerator,
169 nsIStringEnumerator, nsIUTF8StringEnumerator)
171 NS_IMETHODIMP
172 nsStringEnumerator::HasMore(bool* aResult) {
173 *aResult = mIndex < Count();
174 return NS_OK;
177 NS_IMETHODIMP
178 nsStringEnumerator::HasMoreElements(bool* aResult) { return HasMore(aResult); }
180 NS_IMETHODIMP
181 nsStringEnumerator::GetNext(nsISupports** aResult) {
182 if (mIndex >= mArray->Length()) {
183 return NS_ERROR_FAILURE;
186 if (mIsUnicode) {
187 nsSupportsString* stringImpl = new nsSupportsString();
189 stringImpl->SetData(mArray->ElementAt(mIndex++));
190 *aResult = stringImpl;
191 } else {
192 nsSupportsCString* cstringImpl = new nsSupportsCString();
194 cstringImpl->SetData(mCArray->ElementAt(mIndex++));
195 *aResult = cstringImpl;
197 NS_ADDREF(*aResult);
198 return NS_OK;
201 NS_IMETHODIMP
202 nsStringEnumerator::GetNext(nsAString& aResult) {
203 if (NS_WARN_IF(mIndex >= Count())) {
204 return NS_ERROR_UNEXPECTED;
207 if (mIsUnicode) {
208 aResult = mArray->ElementAt(mIndex++);
209 } else {
210 CopyUTF8toUTF16(mCArray->ElementAt(mIndex++), aResult);
213 return NS_OK;
216 NS_IMETHODIMP
217 nsStringEnumerator::GetNext(nsACString& aResult) {
218 if (NS_WARN_IF(mIndex >= Count())) {
219 return NS_ERROR_UNEXPECTED;
222 if (mIsUnicode) {
223 CopyUTF16toUTF8(mArray->ElementAt(mIndex++), aResult);
224 } else {
225 aResult = mCArray->ElementAt(mIndex++);
228 return NS_OK;
231 NS_IMETHODIMP
232 nsStringEnumerator::StringIterator(nsIJSEnumerator** aRetVal) {
233 auto result = MakeRefPtr<JSStringEnumerator>(this);
234 result.forget(aRetVal);
235 return NS_OK;
238 template <class T>
239 static inline nsresult StringEnumeratorTail(T** aResult) {
240 if (!*aResult) {
241 return NS_ERROR_OUT_OF_MEMORY;
243 NS_ADDREF(*aResult);
244 return NS_OK;
248 // constructors
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);