michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: #include "nsStringEnumerator.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: #include "nsSupportsPrimitives.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsTArray.h" michael@0: michael@0: // michael@0: // nsStringEnumerator michael@0: // michael@0: michael@0: class nsStringEnumerator MOZ_FINAL : public nsIStringEnumerator, michael@0: public nsIUTF8StringEnumerator, michael@0: public nsISimpleEnumerator michael@0: { michael@0: public: michael@0: nsStringEnumerator(const nsTArray* aArray, bool aOwnsArray) : michael@0: mArray(aArray), mIndex(0), mOwnsArray(aOwnsArray), mIsUnicode(true) michael@0: {} michael@0: michael@0: nsStringEnumerator(const nsTArray* aArray, bool aOwnsArray) : michael@0: mCArray(aArray), mIndex(0), mOwnsArray(aOwnsArray), mIsUnicode(false) michael@0: {} michael@0: michael@0: nsStringEnumerator(const nsTArray* aArray, nsISupports* aOwner) : michael@0: mArray(aArray), mIndex(0), mOwner(aOwner), mOwnsArray(false), mIsUnicode(true) michael@0: {} michael@0: michael@0: nsStringEnumerator(const nsTArray* aArray, nsISupports* aOwner) : michael@0: mCArray(aArray), mIndex(0), mOwner(aOwner), mOwnsArray(false), mIsUnicode(false) michael@0: {} michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIUTF8STRINGENUMERATOR michael@0: michael@0: // have to declare nsIStringEnumerator manually, because of michael@0: // overlapping method names michael@0: NS_IMETHOD GetNext(nsAString& aResult); michael@0: NS_DECL_NSISIMPLEENUMERATOR michael@0: michael@0: private: michael@0: ~nsStringEnumerator() { michael@0: if (mOwnsArray) { michael@0: // const-casting is safe here, because the NS_New* michael@0: // constructors make sure mOwnsArray is consistent with michael@0: // the constness of the objects michael@0: if (mIsUnicode) michael@0: delete const_cast*>(mArray); michael@0: else michael@0: delete const_cast*>(mCArray); michael@0: } michael@0: } michael@0: michael@0: union { michael@0: const nsTArray* mArray; michael@0: const nsTArray* mCArray; michael@0: }; michael@0: michael@0: inline uint32_t Count() { michael@0: return mIsUnicode ? mArray->Length() : mCArray->Length(); michael@0: } michael@0: michael@0: uint32_t mIndex; michael@0: michael@0: // the owner allows us to hold a strong reference to the object michael@0: // that owns the array. Having a non-null value in mOwner implies michael@0: // that mOwnsArray is false, because we rely on the real owner michael@0: // to release the array michael@0: nsCOMPtr mOwner; michael@0: bool mOwnsArray; michael@0: bool mIsUnicode; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsStringEnumerator, michael@0: nsIStringEnumerator, michael@0: nsIUTF8StringEnumerator, michael@0: nsISimpleEnumerator) michael@0: michael@0: NS_IMETHODIMP michael@0: nsStringEnumerator::HasMore(bool* aResult) michael@0: { michael@0: *aResult = mIndex < Count(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsStringEnumerator::HasMoreElements(bool* aResult) michael@0: { michael@0: return HasMore(aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsStringEnumerator::GetNext(nsISupports** aResult) michael@0: { michael@0: if (mIsUnicode) { michael@0: nsSupportsStringImpl* stringImpl = new nsSupportsStringImpl(); michael@0: if (!stringImpl) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: stringImpl->SetData(mArray->ElementAt(mIndex++)); michael@0: *aResult = stringImpl; michael@0: } michael@0: else { michael@0: nsSupportsCStringImpl* cstringImpl = new nsSupportsCStringImpl(); michael@0: if (!cstringImpl) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: cstringImpl->SetData(mCArray->ElementAt(mIndex++)); michael@0: *aResult = cstringImpl; michael@0: } michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsStringEnumerator::GetNext(nsAString& aResult) michael@0: { michael@0: if (NS_WARN_IF(mIndex >= Count())) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: if (mIsUnicode) michael@0: aResult = mArray->ElementAt(mIndex++); michael@0: else michael@0: CopyUTF8toUTF16(mCArray->ElementAt(mIndex++), aResult); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsStringEnumerator::GetNext(nsACString& aResult) michael@0: { michael@0: if (NS_WARN_IF(mIndex >= Count())) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: if (mIsUnicode) michael@0: CopyUTF16toUTF8(mArray->ElementAt(mIndex++), aResult); michael@0: else michael@0: aResult = mCArray->ElementAt(mIndex++); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: template michael@0: static inline nsresult michael@0: StringEnumeratorTail(T** aResult) michael@0: { michael@0: if (!*aResult) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // constructors michael@0: // michael@0: michael@0: nsresult michael@0: NS_NewStringEnumerator(nsIStringEnumerator** aResult, michael@0: const nsTArray* aArray, nsISupports* aOwner) michael@0: { michael@0: if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *aResult = new nsStringEnumerator(aArray, aOwner); michael@0: return StringEnumeratorTail(aResult); michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, michael@0: const nsTArray* aArray, nsISupports* aOwner) michael@0: { michael@0: if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *aResult = new nsStringEnumerator(aArray, aOwner); michael@0: return StringEnumeratorTail(aResult); michael@0: } michael@0: michael@0: nsresult michael@0: NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, michael@0: nsTArray* aArray) michael@0: { michael@0: if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *aResult = new nsStringEnumerator(aArray, true); michael@0: return StringEnumeratorTail(aResult); michael@0: } michael@0: michael@0: nsresult michael@0: NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, michael@0: nsTArray* aArray) michael@0: { michael@0: if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *aResult = new nsStringEnumerator(aArray, true); michael@0: return StringEnumeratorTail(aResult); michael@0: } michael@0: michael@0: // const ones internally just forward to the non-const equivalents michael@0: nsresult michael@0: NS_NewStringEnumerator(nsIStringEnumerator** aResult, michael@0: const nsTArray* aArray) michael@0: { michael@0: if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *aResult = new nsStringEnumerator(aArray, false); michael@0: return StringEnumeratorTail(aResult); michael@0: } michael@0: michael@0: nsresult michael@0: NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, michael@0: const nsTArray* aArray) michael@0: { michael@0: if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: *aResult = new nsStringEnumerator(aArray, false); michael@0: return StringEnumeratorTail(aResult); michael@0: } michael@0: