diff options
Diffstat (limited to 'dom/xslt/base')
-rw-r--r-- | dom/xslt/base/moz.build | 23 | ||||
-rw-r--r-- | dom/xslt/base/txCore.h | 42 | ||||
-rw-r--r-- | dom/xslt/base/txDouble.cpp | 194 | ||||
-rw-r--r-- | dom/xslt/base/txErrorObserver.h | 36 | ||||
-rw-r--r-- | dom/xslt/base/txExpandedName.cpp | 37 | ||||
-rw-r--r-- | dom/xslt/base/txExpandedName.h | 50 | ||||
-rw-r--r-- | dom/xslt/base/txExpandedNameMap.cpp | 94 | ||||
-rw-r--r-- | dom/xslt/base/txExpandedNameMap.h | 153 | ||||
-rw-r--r-- | dom/xslt/base/txList.cpp | 249 | ||||
-rw-r--r-- | dom/xslt/base/txList.h | 152 | ||||
-rw-r--r-- | dom/xslt/base/txLog.h | 23 | ||||
-rw-r--r-- | dom/xslt/base/txNamespaceMap.cpp | 81 | ||||
-rw-r--r-- | dom/xslt/base/txNamespaceMap.h | 38 | ||||
-rw-r--r-- | dom/xslt/base/txOwningArray.h | 29 | ||||
-rw-r--r-- | dom/xslt/base/txStack.h | 99 | ||||
-rw-r--r-- | dom/xslt/base/txStringUtils.h | 28 | ||||
-rw-r--r-- | dom/xslt/base/txURIUtils.cpp | 87 | ||||
-rw-r--r-- | dom/xslt/base/txURIUtils.h | 40 |
18 files changed, 1455 insertions, 0 deletions
diff --git a/dom/xslt/base/moz.build b/dom/xslt/base/moz.build new file mode 100644 index 0000000000..1b22391983 --- /dev/null +++ b/dom/xslt/base/moz.build @@ -0,0 +1,23 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + "txDouble.cpp", + "txExpandedName.cpp", + "txExpandedNameMap.cpp", + "txList.cpp", + "txNamespaceMap.cpp", + "txURIUtils.cpp", +] + +LOCAL_INCLUDES += [ + "..", + "../xml", + "../xpath", + "../xslt", +] + +FINAL_LIBRARY = "xul" diff --git a/dom/xslt/base/txCore.h b/dom/xslt/base/txCore.h new file mode 100644 index 0000000000..6e462a5a31 --- /dev/null +++ b/dom/xslt/base/txCore.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __txCore_h__ +#define __txCore_h__ + +#include "nscore.h" +#include "nsDebug.h" +#include "nsISupportsImpl.h" +#include "nsStringFwd.h" + +class txObject { + public: + MOZ_COUNTED_DEFAULT_CTOR(txObject) + + /** + * Deletes this txObject + */ + MOZ_COUNTED_DTOR_VIRTUAL(txObject) +}; + +/** + * Utility class for doubles + */ +class txDouble { + public: + /** + * Converts the value of the given double to a string, and appends + * the result to the destination string. + */ + static void toString(double aValue, nsAString& aDest); + + /** + * Converts the given String to a double, if the string value does not + * represent a double, NaN will be returned. + */ + static double toDouble(const nsAString& aStr); +}; + +#endif diff --git a/dom/xslt/base/txDouble.cpp b/dom/xslt/base/txDouble.cpp new file mode 100644 index 0000000000..ad7fa690be --- /dev/null +++ b/dom/xslt/base/txDouble.cpp @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/FloatingPoint.h" + +#include "nsString.h" +#include "txCore.h" +#include "txXMLUtils.h" +#include <math.h> +#include <stdlib.h> +#include <algorithm> +#ifdef WIN32 +# include <float.h> +#endif +#include "prdtoa.h" + +/* + * Utility class for doubles + */ + +/* + * Converts the given String to a double, if the String value does not + * represent a double, NaN will be returned + */ +class txStringToDouble { + public: + txStringToDouble() : mState(eWhitestart), mSign(ePositive) {} + + void Parse(const nsAString& aSource) { + if (mState == eIllegal) { + return; + } + uint32_t i = 0; + char16_t c; + auto len = aSource.Length(); + for (; i < len; ++i) { + c = aSource[i]; + switch (mState) { + case eWhitestart: + if (c == '-') { + mState = eDecimal; + mSign = eNegative; + } else if (c >= '0' && c <= '9') { + mState = eDecimal; + mBuffer.Append((char)c); + } else if (c == '.') { + mState = eMantissa; + mBuffer.Append((char)c); + } else if (!XMLUtils::isWhitespace(c)) { + mState = eIllegal; + return; + } + break; + case eDecimal: + if (c >= '0' && c <= '9') { + mBuffer.Append((char)c); + } else if (c == '.') { + mState = eMantissa; + mBuffer.Append((char)c); + } else if (XMLUtils::isWhitespace(c)) { + mState = eWhiteend; + } else { + mState = eIllegal; + return; + } + break; + case eMantissa: + if (c >= '0' && c <= '9') { + mBuffer.Append((char)c); + } else if (XMLUtils::isWhitespace(c)) { + mState = eWhiteend; + } else { + mState = eIllegal; + return; + } + break; + case eWhiteend: + if (!XMLUtils::isWhitespace(c)) { + mState = eIllegal; + return; + } + break; + default: + break; + } + } + } + + double getDouble() { + if (mState == eIllegal || mBuffer.IsEmpty() || + (mBuffer.Length() == 1 && mBuffer[0] == '.')) { + return mozilla::UnspecifiedNaN<double>(); + } + return static_cast<double>(mSign) * PR_strtod(mBuffer.get(), nullptr); + } + + private: + nsAutoCString mBuffer; + enum { eWhitestart, eDecimal, eMantissa, eWhiteend, eIllegal } mState; + enum { eNegative = -1, ePositive = 1 } mSign; +}; + +double txDouble::toDouble(const nsAString& aSrc) { + txStringToDouble sink; + sink.Parse(aSrc); + return sink.getDouble(); +} + +/* + * Converts the value of the given double to a String, and places + * The result into the destination String. + * @return the given dest string + */ +void txDouble::toString(double aValue, nsAString& aDest) { + // check for special cases + + if (std::isnan(aValue)) { + aDest.AppendLiteral("NaN"); + return; + } + if (std::isinf(aValue)) { + if (aValue < 0) aDest.Append(char16_t('-')); + aDest.AppendLiteral("Infinity"); + return; + } + + // Mantissa length is 17, so this is plenty + const int buflen = 20; + char buf[buflen]; + + int intDigits, sign; + char* endp; + PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1); + + // compute length + int32_t length = endp - buf; + if (length > intDigits) { + // decimal point needed + ++length; + if (intDigits < 1) { + // leading zeros, -intDigits + 1 + length += 1 - intDigits; + } + } else { + // trailing zeros, total length given by intDigits + length = intDigits; + } + if (aValue < 0) ++length; + // grow the string + uint32_t oldlength = aDest.Length(); + if (!aDest.SetLength(oldlength + length, mozilla::fallible)) + return; // out of memory + auto dest = aDest.BeginWriting(); + std::advance(dest, oldlength); + if (aValue < 0) { + *dest = '-'; + ++dest; + } + int i; + // leading zeros + if (intDigits < 1) { + *dest = '0'; + ++dest; + *dest = '.'; + ++dest; + for (i = 0; i > intDigits; --i) { + *dest = '0'; + ++dest; + } + } + // mantissa + int firstlen = std::min<size_t>(intDigits, endp - buf); + for (i = 0; i < firstlen; i++) { + *dest = buf[i]; + ++dest; + } + if (i < endp - buf) { + if (i > 0) { + *dest = '.'; + ++dest; + } + for (; i < endp - buf; i++) { + *dest = buf[i]; + ++dest; + } + } + // trailing zeros + for (; i < intDigits; i++) { + *dest = '0'; + ++dest; + } +} diff --git a/dom/xslt/base/txErrorObserver.h b/dom/xslt/base/txErrorObserver.h new file mode 100644 index 0000000000..30b541f2a9 --- /dev/null +++ b/dom/xslt/base/txErrorObserver.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MITRE_ERROROBSERVER_H +#define MITRE_ERROROBSERVER_H + +#include "txCore.h" + +/** + * A simple interface for observing errors + **/ +class ErrorObserver { + public: + /** + * Default Destructor for ErrorObserver + **/ + virtual ~ErrorObserver(){}; + + /** + * Notifies this Error observer of a new error aRes + **/ + virtual void receiveError(const nsAString& errorMessage, nsresult aRes) = 0; + + /** + * Notifies this Error observer of a new error, with default + * error code NS_ERROR_FAILURE + **/ + void receiveError(const nsAString& errorMessage) { + receiveError(errorMessage, NS_ERROR_FAILURE); + } + +}; //-- ErrorObserver + +#endif diff --git a/dom/xslt/base/txExpandedName.cpp b/dom/xslt/base/txExpandedName.cpp new file mode 100644 index 0000000000..af11476056 --- /dev/null +++ b/dom/xslt/base/txExpandedName.cpp @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "txExpandedName.h" +#include "nsString.h" +#include "nsReadableUtils.h" +#include "txStringUtils.h" +#include "txNamespaceMap.h" +#include "txXMLUtils.h" + +nsresult txExpandedName::init(const nsAString& aQName, + txNamespaceMap* aResolver, bool aUseDefault) { + const nsString& qName = PromiseFlatString(aQName); + const char16_t* colon; + bool valid = XMLUtils::isValidQName(qName, &colon); + if (!valid) { + return NS_ERROR_FAILURE; + } + + if (colon) { + RefPtr<nsAtom> prefix = NS_Atomize(Substring(qName.get(), colon)); + int32_t namespaceID = aResolver->lookupNamespace(prefix); + if (namespaceID == kNameSpaceID_Unknown) return NS_ERROR_FAILURE; + mNamespaceID = namespaceID; + + const char16_t* end; + qName.EndReading(end); + mLocalName = NS_Atomize(Substring(colon + 1, end)); + } else { + mNamespaceID = + aUseDefault ? aResolver->lookupNamespace(nullptr) : kNameSpaceID_None; + mLocalName = NS_Atomize(aQName); + } + return NS_OK; +} diff --git a/dom/xslt/base/txExpandedName.h b/dom/xslt/base/txExpandedName.h new file mode 100644 index 0000000000..76d82a8eee --- /dev/null +++ b/dom/xslt/base/txExpandedName.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TRANSFRMX_EXPANDEDNAME_H +#define TRANSFRMX_EXPANDEDNAME_H + +#include "nsCOMPtr.h" +#include "nsAtom.h" +#include "mozilla/dom/NameSpaceConstants.h" + +class txNamespaceMap; + +class txExpandedName { + public: + txExpandedName() : mNamespaceID(kNameSpaceID_None) {} + + txExpandedName(int32_t aNsID, nsAtom* aLocalName) + : mNamespaceID(aNsID), mLocalName(aLocalName) {} + + txExpandedName(const txExpandedName& aOther) = default; + + nsresult init(const nsAString& aQName, txNamespaceMap* aResolver, + bool aUseDefault); + + void reset() { + mNamespaceID = kNameSpaceID_None; + mLocalName = nullptr; + } + + bool isNull() { return mNamespaceID == kNameSpaceID_None && !mLocalName; } + + txExpandedName& operator=(const txExpandedName& rhs) = default; + + bool operator==(const txExpandedName& rhs) const { + return ((mLocalName == rhs.mLocalName) && + (mNamespaceID == rhs.mNamespaceID)); + } + + bool operator!=(const txExpandedName& rhs) const { + return ((mLocalName != rhs.mLocalName) || + (mNamespaceID != rhs.mNamespaceID)); + } + + int32_t mNamespaceID; + RefPtr<nsAtom> mLocalName; +}; + +#endif diff --git a/dom/xslt/base/txExpandedNameMap.cpp b/dom/xslt/base/txExpandedNameMap.cpp new file mode 100644 index 0000000000..996799abf0 --- /dev/null +++ b/dom/xslt/base/txExpandedNameMap.cpp @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "txExpandedNameMap.h" +#include "txCore.h" + +class txMapItemComparator { + public: + bool Equals(const txExpandedNameMap_base::MapItem& aItem, + const txExpandedName& aKey) const { + return aItem.mNamespaceID == aKey.mNamespaceID && + aItem.mLocalName == aKey.mLocalName; + } +}; + +/** + * Adds an item, if an item with this key already exists an error is + * returned + * @param aKey key for item to add + * @param aValue value of item to add + * @return errorcode + */ +nsresult txExpandedNameMap_base::addItem(const txExpandedName& aKey, + void* aValue) { + size_t pos = mItems.IndexOf(aKey, 0, txMapItemComparator()); + if (pos != mItems.NoIndex) { + return NS_ERROR_XSLT_ALREADY_SET; + } + + MapItem* item = mItems.AppendElement(); + item->mNamespaceID = aKey.mNamespaceID; + item->mLocalName = aKey.mLocalName; + item->mValue = aValue; + + return NS_OK; +} + +/** + * Sets an item, if an item with this key already exists it is overwritten + * with the new value + * @param aKey key for item to set + * @param aValue value of item to set + * @return errorcode + */ +nsresult txExpandedNameMap_base::setItem(const txExpandedName& aKey, + void* aValue, void** aOldValue) { + *aOldValue = nullptr; + size_t pos = mItems.IndexOf(aKey, 0, txMapItemComparator()); + if (pos != mItems.NoIndex) { + *aOldValue = mItems[pos].mValue; + mItems[pos].mValue = aValue; + return NS_OK; + } + + MapItem* item = mItems.AppendElement(); + item->mNamespaceID = aKey.mNamespaceID; + item->mLocalName = aKey.mLocalName; + item->mValue = aValue; + + return NS_OK; +} + +/** + * Gets an item + * @param aKey key for item to get + * @return item with specified key, or null if no such item exists + */ +void* txExpandedNameMap_base::getItem(const txExpandedName& aKey) const { + size_t pos = mItems.IndexOf(aKey, 0, txMapItemComparator()); + if (pos != mItems.NoIndex) { + return mItems[pos].mValue; + } + + return nullptr; +} + +/** + * Removes an item, deleting it if the map owns the values + * @param aKey key for item to remove + * @return item with specified key, or null if it has been deleted + * or no such item exists + */ +void* txExpandedNameMap_base::removeItem(const txExpandedName& aKey) { + void* value = nullptr; + size_t pos = mItems.IndexOf(aKey, 0, txMapItemComparator()); + if (pos != mItems.NoIndex) { + value = mItems[pos].mValue; + mItems.RemoveElementAt(pos); + } + + return value; +} diff --git a/dom/xslt/base/txExpandedNameMap.h b/dom/xslt/base/txExpandedNameMap.h new file mode 100644 index 0000000000..6e308a65f8 --- /dev/null +++ b/dom/xslt/base/txExpandedNameMap.h @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TRANSFRMX_EXPANDEDNAMEMAP_H +#define TRANSFRMX_EXPANDEDNAMEMAP_H + +#include "mozilla/UniquePtr.h" +#include "mozilla/UniquePtrExtensions.h" +#include "nsError.h" +#include "txExpandedName.h" +#include "nsTArray.h" + +class txExpandedNameMap_base { + protected: + /** + * Adds an item, if an item with this key already exists an error is + * returned + * @param aKey key for item to add + * @param aValue value of item to add + * @return errorcode + */ + nsresult addItem(const txExpandedName& aKey, void* aValue); + + /** + * Sets an item, if an item with this key already exists it is overwritten + * with the new value + * @param aKey key for item to set + * @param aValue value of item to set + * @return errorcode + */ + nsresult setItem(const txExpandedName& aKey, void* aValue, void** aOldValue); + + /** + * Gets an item + * @param aKey key for item to get + * @return item with specified key, or null if no such item exists + */ + void* getItem(const txExpandedName& aKey) const; + + /** + * Removes an item, deleting it if the map owns the values + * @param aKey key for item to remove + * @return item with specified key, or null if it has been deleted + * or no such item exists + */ + void* removeItem(const txExpandedName& aKey); + + /** + * Clears the items + */ + void clearItems() { mItems.Clear(); } + + class iterator_base { + public: + explicit iterator_base(txExpandedNameMap_base& aMap) + : mMap(aMap), mCurrentPos(uint32_t(-1)) {} + + bool next() { return ++mCurrentPos < mMap.mItems.Length(); } + + const txExpandedName key() { + NS_ASSERTION(mCurrentPos < mMap.mItems.Length(), + "invalid position in txExpandedNameMap::iterator"); + return txExpandedName(mMap.mItems[mCurrentPos].mNamespaceID, + mMap.mItems[mCurrentPos].mLocalName); + } + + protected: + void* itemValue() { + NS_ASSERTION(mCurrentPos < mMap.mItems.Length(), + "invalid position in txExpandedNameMap::iterator"); + return mMap.mItems[mCurrentPos].mValue; + } + + private: + txExpandedNameMap_base& mMap; + uint32_t mCurrentPos; + }; + + friend class iterator_base; + + friend class txMapItemComparator; + struct MapItem { + int32_t mNamespaceID; + RefPtr<nsAtom> mLocalName; + void* mValue; + }; + + nsTArray<MapItem> mItems; +}; + +template <class E> +class txExpandedNameMap : public txExpandedNameMap_base { + public: + nsresult add(const txExpandedName& aKey, E* aValue) { + return addItem(aKey, (void*)aValue); + } + + nsresult set(const txExpandedName& aKey, E* aValue) { + void* oldValue; + return setItem(aKey, (void*)aValue, &oldValue); + } + + E* get(const txExpandedName& aKey) const { return (E*)getItem(aKey); } + + E* remove(const txExpandedName& aKey) { return (E*)removeItem(aKey); } + + void clear() { clearItems(); } + + class iterator : public iterator_base { + public: + explicit iterator(txExpandedNameMap& aMap) : iterator_base(aMap) {} + + E* value() { return (E*)itemValue(); } + }; +}; + +template <class E> +class txOwningExpandedNameMap : public txExpandedNameMap_base { + public: + ~txOwningExpandedNameMap() { clear(); } + + nsresult add(const txExpandedName& aKey, E* aValue) { + return addItem(aKey, (void*)aValue); + } + + nsresult set(const txExpandedName& aKey, E* aValue) { + mozilla::UniquePtr<E> oldValue; + return setItem(aKey, (void*)aValue, getter_Transfers(oldValue)); + } + + E* get(const txExpandedName& aKey) const { return (E*)getItem(aKey); } + + void remove(const txExpandedName& aKey) { delete (E*)removeItem(aKey); } + + void clear() { + uint32_t i, len = mItems.Length(); + for (i = 0; i < len; ++i) { + delete (E*)mItems[i].mValue; + } + clearItems(); + } + + class iterator : public iterator_base { + public: + explicit iterator(txOwningExpandedNameMap& aMap) : iterator_base(aMap) {} + + E* value() { return (E*)itemValue(); } + }; +}; + +#endif // TRANSFRMX_EXPANDEDNAMEMAP_H diff --git a/dom/xslt/base/txList.cpp b/dom/xslt/base/txList.cpp new file mode 100644 index 0000000000..a361490784 --- /dev/null +++ b/dom/xslt/base/txList.cpp @@ -0,0 +1,249 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "txList.h" + +//----------------------------/ +//- Implementation of txList -/ +//----------------------------/ + +/** + * Default constructor for a txList; + **/ + +txList::txList() { + firstItem = 0; + lastItem = 0; + itemCount = 0; +} //-- txList; + +/** + * txList destructor, cleans up ListItems, but will not delete the Object + * references + */ +txList::~txList() { clear(); } //-- ~txList + +void txList::add(void* objPtr) { insertBefore(objPtr, nullptr); } //-- add + +/** + * Returns the number of items in this txList + **/ +int32_t List::getLength() { return itemCount; } //-- getLength + +/** + * Inserts the given Object pointer as the item just after refItem. + * If refItem is a null pointer the Object will be inserted at the + * beginning of the txList (ie, insert after nothing). + * This method assumes refItem is a member of this list, and since this + * is a private method, I feel that's a valid assumption + **/ +void txList::insertAfter(void* objPtr, ListItem* refItem) { + insertBefore(objPtr, refItem ? refItem->nextItem : firstItem); +} //-- insertAfter + +/** + * Inserts the given Object pointer as the item just before refItem. + * If refItem is a null pointer the Object will be inserted at the + * end of the txList (ie, insert before nothing). + * This method assumes refItem is a member of this list, and since this + * is a private method, I feel that's a valid assumption + **/ +void txList::insertBefore(void* objPtr, ListItem* refItem) { + ListItem* item = new ListItem; + item->objPtr = objPtr; + item->nextItem = 0; + item->prevItem = 0; + + //-- if refItem == null insert at end + if (!refItem) { + //-- add to back of list + if (lastItem) { + lastItem->nextItem = item; + item->prevItem = lastItem; + } + lastItem = item; + if (!firstItem) firstItem = item; + } else { + //-- insert before given item + item->nextItem = refItem; + item->prevItem = refItem->prevItem; + refItem->prevItem = item; + + if (item->prevItem) + item->prevItem->nextItem = item; + else + firstItem = item; + } + + // increase the item count + ++itemCount; +} //-- insertBefore + +txList::ListItem* txList::remove(ListItem* item) { + if (!item) return item; + + //-- adjust the previous item's next pointer + if (item->prevItem) { + item->prevItem->nextItem = item->nextItem; + } + //-- adjust the next item's previous pointer + if (item->nextItem) { + item->nextItem->prevItem = item->prevItem; + } + + //-- adjust first and last items + if (item == firstItem) firstItem = item->nextItem; + if (item == lastItem) lastItem = item->prevItem; + + //-- decrease Item count + --itemCount; + return item; +} //-- remove + +void txList::clear() { + ListItem* item = firstItem; + while (item) { + ListItem* tItem = item; + item = item->nextItem; + delete tItem; + } + firstItem = 0; + lastItem = 0; + itemCount = 0; +} + +//------------------------------------/ +//- Implementation of txListIterator -/ +//------------------------------------/ + +/** + * Creates a new txListIterator for the given txList + * @param list, the txList to create an Iterator for + **/ +txListIterator::txListIterator(txList* list) { + this->list = list; + currentItem = 0; + atEndOfList = false; +} //-- txListIterator + +/** + * Adds the Object pointer to the txList pointed to by this txListIterator. + * The Object pointer is inserted as the next item in the txList + * based on the current position within the txList + * @param objPtr the Object pointer to add to the list + **/ +void txListIterator::addAfter(void* objPtr) { + if (currentItem || !atEndOfList) { + list->insertAfter(objPtr, currentItem); + } else { + list->insertBefore(objPtr, nullptr); + } +} //-- addAfter + +/** + * Adds the Object pointer to the txList pointed to by this txListIterator. + * The Object pointer is inserted as the previous item in the txList + * based on the current position within the txList + * @param objPtr the Object pointer to add to the list + **/ +void txListIterator::addBefore(void* objPtr) { + if (currentItem || atEndOfList) { + list->insertBefore(objPtr, currentItem); + } else { + list->insertAfter(objPtr, nullptr); + } +} //-- addBefore + +/** + * Returns true if a successful call to the next() method can be made + * @return true if a successful call to the next() method can be made, + * otherwise false + **/ +bool txListIterator::hasNext() { + bool hasNext = false; + if (currentItem) + hasNext = (currentItem->nextItem != 0); + else if (!atEndOfList) + hasNext = (list->firstItem != 0); + + return hasNext; +} //-- hasNext + +/** + * Returns the next Object pointer in the list + **/ +void* txListIterator::next() { + void* obj = 0; + if (currentItem) + currentItem = currentItem->nextItem; + else if (!atEndOfList) + currentItem = list->firstItem; + + if (currentItem) + obj = currentItem->objPtr; + else + atEndOfList = true; + + return obj; +} //-- next + +/** + * Returns the previous Object in the list + **/ +void* txListIterator::previous() { + void* obj = 0; + + if (currentItem) + currentItem = currentItem->prevItem; + else if (atEndOfList) + currentItem = list->lastItem; + + if (currentItem) obj = currentItem->objPtr; + + atEndOfList = false; + + return obj; +} //-- previous + +/** + * Returns the current Object + **/ +void* txListIterator::current() { + if (currentItem) return currentItem->objPtr; + + return 0; +} //-- current + +/** + * Removes the Object last returned by the next() or previous() methods; + * @return the removed Object pointer + **/ +void* txListIterator::remove() { + void* obj = 0; + if (currentItem) { + obj = currentItem->objPtr; + txList::ListItem* item = currentItem; + previous(); //-- make previous item the current item + list->remove(item); + delete item; + } + return obj; +} //-- remove + +/** + * Resets the current location within the txList to the beginning of the txList + **/ +void txListIterator::reset() { + atEndOfList = false; + currentItem = 0; +} //-- reset + +/** + * Move the iterator to right after the last element + **/ +void txListIterator::resetToEnd() { + atEndOfList = true; + currentItem = 0; +} //-- moveToEnd diff --git a/dom/xslt/base/txList.h b/dom/xslt/base/txList.h new file mode 100644 index 0000000000..eeafd12dda --- /dev/null +++ b/dom/xslt/base/txList.h @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TRANSFRMX_LIST_H +#define TRANSFRMX_LIST_H + +#include "txCore.h" + +class txListIterator; + +/** + * Represents an ordered list of Object pointers. Modeled after a Java 2 List. + **/ +class txList : public txObject { + friend class txListIterator; + + public: + /** + * Creates an empty txList + **/ + txList(); + + /** + * txList destructor, object references will not be deleted. + **/ + ~txList(); + + /** + * Returns the number of items in this txList + **/ + int32_t getLength(); + + /** + * Returns true if there are no items in this txList + */ + inline bool isEmpty() { return itemCount == 0; } + + /** + * Adds the given Object to the list + **/ + void add(void* objPtr); + + /* + * Removes all the objects from the list + */ + void clear(); + + protected: + struct ListItem { + ListItem* nextItem; + ListItem* prevItem; + void* objPtr; + }; + + /** + * Removes the given ListItem pointer from the list + **/ + ListItem* remove(ListItem* sItem); + + private: + txList(const txList& aOther); // not implemented + + ListItem* firstItem; + ListItem* lastItem; + int32_t itemCount; + + void insertAfter(void* objPtr, ListItem* sItem); + void insertBefore(void* objPtr, ListItem* sItem); +}; + +/** + * An Iterator for the txList Class + **/ +class txListIterator { + public: + /** + * Creates a new txListIterator for the given txList + * @param list, the txList to create an Iterator for + **/ + explicit txListIterator(txList* list); + + /** + * Adds the Object pointer to the txList pointed to by this txListIterator. + * The Object pointer is inserted as the next item in the txList + * based on the current position within the txList + * @param objPtr the Object pointer to add to the list + **/ + void addAfter(void* objPtr); + + /** + * Adds the Object pointer to the txList pointed to by this txListIterator. + * The Object pointer is inserted as the previous item in the txList + * based on the current position within the txList + * @param objPtr the Object pointer to add to the list + **/ + void addBefore(void* objPtr); + + /** + * Returns true if a successful call to the next() method can be made + * @return true if a successful call to the next() method can be made, + * otherwise false + **/ + bool hasNext(); + + /** + * Returns the next Object pointer from the list + **/ + void* next(); + + /** + * Returns the previous Object pointer from the list + **/ + void* previous(); + + /** + * Returns the current Object + **/ + void* current(); + + /** + * Removes the Object last returned by the next() or previous() methods; + * @return the removed Object pointer + **/ + void* remove(); + + /** + * Resets the current location within the txList to the beginning of the + * txList + **/ + void reset(); + + /** + * Resets the current location within the txList to the end of the txList + **/ + void resetToEnd(); + + private: + //-- points to the current list item + txList::ListItem* currentItem; + + //-- points to the list to iterator over + txList* list; + + //-- we've moved off the end of the list + bool atEndOfList; +}; + +using List = txList; + +#endif diff --git a/dom/xslt/base/txLog.h b/dom/xslt/base/txLog.h new file mode 100644 index 0000000000..c5b03ca83e --- /dev/null +++ b/dom/xslt/base/txLog.h @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef txLog_h__ +#define txLog_h__ + +#include "mozilla/Logging.h" + +class txLog { + public: + static mozilla::LazyLogModule xpath; + static mozilla::LazyLogModule xslt; +}; + +#define TX_LG_IMPL \ + mozilla::LazyLogModule txLog::xpath("xpath"); \ + mozilla::LazyLogModule txLog::xslt("xslt"); + +#define TX_LG_CREATE + +#endif diff --git a/dom/xslt/base/txNamespaceMap.cpp b/dom/xslt/base/txNamespaceMap.cpp new file mode 100644 index 0000000000..284e08a705 --- /dev/null +++ b/dom/xslt/base/txNamespaceMap.cpp @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "txNamespaceMap.h" +#include "nsGkAtoms.h" +#include "txXPathNode.h" + +txNamespaceMap::txNamespaceMap() = default; + +txNamespaceMap::txNamespaceMap(const txNamespaceMap& aOther) + : mPrefixes(aOther.mPrefixes.Clone()), + mNamespaces(aOther.mNamespaces.Clone()) {} + +nsresult txNamespaceMap::mapNamespace(nsAtom* aPrefix, + const nsAString& aNamespaceURI) { + nsAtom* prefix = aPrefix == nsGkAtoms::_empty ? nullptr : aPrefix; + + int32_t nsId; + if (prefix && aNamespaceURI.IsEmpty()) { + // Remove the mapping + int32_t index = mPrefixes.IndexOf(prefix); + if (index >= 0) { + mPrefixes.RemoveElementAt(index); + mNamespaces.RemoveElementAt(index); + } + + return NS_OK; + } + + if (aNamespaceURI.IsEmpty()) { + // Set default to empty namespace + nsId = kNameSpaceID_None; + } else { + nsId = txNamespaceManager::getNamespaceID(aNamespaceURI); + NS_ENSURE_FALSE(nsId == kNameSpaceID_Unknown, NS_ERROR_FAILURE); + } + + // Check if the mapping already exists + int32_t index = mPrefixes.IndexOf(prefix); + if (index >= 0) { + mNamespaces.ElementAt(index) = nsId; + + return NS_OK; + } + + // New mapping + mPrefixes.AppendElement(prefix); + mNamespaces.AppendElement(nsId); + + return NS_OK; +} + +int32_t txNamespaceMap::lookupNamespace(nsAtom* aPrefix) { + if (aPrefix == nsGkAtoms::xml) { + return kNameSpaceID_XML; + } + + nsAtom* prefix = aPrefix == nsGkAtoms::_empty ? 0 : aPrefix; + + int32_t index = mPrefixes.IndexOf(prefix); + if (index >= 0) { + return mNamespaces.SafeElementAt(index, kNameSpaceID_Unknown); + } + + if (!prefix) { + return kNameSpaceID_None; + } + + return kNameSpaceID_Unknown; +} + +int32_t txNamespaceMap::lookupNamespaceWithDefault(const nsAString& aPrefix) { + RefPtr<nsAtom> prefix = NS_Atomize(aPrefix); + if (prefix != nsGkAtoms::_poundDefault) { + return lookupNamespace(prefix); + } + + return lookupNamespace(nullptr); +} diff --git a/dom/xslt/base/txNamespaceMap.h b/dom/xslt/base/txNamespaceMap.h new file mode 100644 index 0000000000..e2be7ebf15 --- /dev/null +++ b/dom/xslt/base/txNamespaceMap.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TRANSFRMX_TXNAMESPACEMAP_H +#define TRANSFRMX_TXNAMESPACEMAP_H + +#include "nsAtom.h" +#include "nsCOMPtr.h" +#include "nsTArray.h" + +class txNamespaceMap { + public: + txNamespaceMap(); + txNamespaceMap(const txNamespaceMap& aOther); + + nsrefcnt AddRef() { return ++mRefCnt; } + nsrefcnt Release() { + if (--mRefCnt == 0) { + mRefCnt = 1; // stabilize + delete this; + return 0; + } + return mRefCnt; + } + + nsresult mapNamespace(nsAtom* aPrefix, const nsAString& aNamespaceURI); + int32_t lookupNamespace(nsAtom* aPrefix); + int32_t lookupNamespaceWithDefault(const nsAString& aPrefix); + + private: + nsAutoRefCnt mRefCnt; + nsTArray<RefPtr<nsAtom>> mPrefixes; + nsTArray<int32_t> mNamespaces; +}; + +#endif // TRANSFRMX_TXNAMESPACEMAP_H diff --git a/dom/xslt/base/txOwningArray.h b/dom/xslt/base/txOwningArray.h new file mode 100644 index 0000000000..f25015a597 --- /dev/null +++ b/dom/xslt/base/txOwningArray.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef txOwningArray_h__ +#define txOwningArray_h__ + +// Class acting like a nsTArray except that it deletes its objects +// on destruction. It does not however delete its objects on operations +// like RemoveElementsAt or on |array[i] = bar|. + +template <class E> +class txOwningArray : public nsTArray<E*> { + public: + typedef nsTArray<E*> base_type; + typedef typename base_type::value_type value_type; + + ~txOwningArray() { + value_type* iter = base_type::Elements(); + value_type* end = iter + base_type::Length(); + for (; iter < end; ++iter) { + delete *iter; + } + } +}; + +#endif // txOwningArray_h__ diff --git a/dom/xslt/base/txStack.h b/dom/xslt/base/txStack.h new file mode 100644 index 0000000000..9a9269ed69 --- /dev/null +++ b/dom/xslt/base/txStack.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef txStack_h___ +#define txStack_h___ + +#include "nsTArray.h" + +class txStack : private nsTArray<void*> { + public: + /** + * Returns the specified object from the top of this stack, + * without removing it from the stack. + * + * @return a pointer to the object that is the top of this stack. + */ + inline void* peek() { + NS_ASSERTION(!isEmpty(), "peeking at empty stack"); + return !isEmpty() ? ElementAt(Length() - 1) : nullptr; + } + + /** + * Adds the specified object to the top of this stack. + * + * @param obj a pointer to the object that is to be added to the + * top of this stack. + */ + inline void push(void* aObject) { AppendElement(aObject); } + + /** + * Removes and returns the specified object from the top of this + * stack. + * + * @return a pointer to the object that was the top of this stack. + */ + inline void* pop() { + void* object = nullptr; + NS_ASSERTION(!isEmpty(), "popping from empty stack"); + if (!isEmpty()) { + object = PopLastElement(); + } + return object; + } + + /** + * Returns true if there are no objects in the stack. + * + * @return true if there are no objects in the stack. + */ + inline bool isEmpty() { return IsEmpty(); } + + /** + * Returns the number of elements in the Stack. + * + * @return the number of elements in the Stack. + */ + inline int32_t size() { return Length(); } + + private: + friend class txStackIterator; +}; + +class txStackIterator { + public: + /** + * Creates an iterator for the given stack. + * + * @param aStack the stack to create an iterator for. + */ + inline explicit txStackIterator(txStack* aStack) + : mStack(aStack), mPosition(0) {} + + /** + * Returns true if there is more objects on the stack. + * + * @return . + */ + inline bool hasNext() { return (mPosition < mStack->Length()); } + + /** + * Returns the next object pointer from the stack. + * + * @return . + */ + inline void* next() { + if (mPosition == mStack->Length()) { + return nullptr; + } + return mStack->ElementAt(mPosition++); + } + + private: + txStack* mStack; + uint32_t mPosition; +}; + +#endif /* txStack_h___ */ diff --git a/dom/xslt/base/txStringUtils.h b/dom/xslt/base/txStringUtils.h new file mode 100644 index 0000000000..2064c01720 --- /dev/null +++ b/dom/xslt/base/txStringUtils.h @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef txStringUtils_h__ +#define txStringUtils_h__ + +#include "nsAString.h" +#include "nsAtom.h" +#include "nsUnicharUtils.h" +#include "nsContentUtils.h" // For ASCIIToLower(). + +/** + * Check equality between a string and an atom containing ASCII. + */ +inline bool TX_StringEqualsAtom(const nsAString& aString, nsAtom* aAtom) { + return aAtom->Equals(aString); +} + +inline already_AddRefed<nsAtom> TX_ToLowerCaseAtom(nsAtom* aAtom) { + nsAutoString str; + aAtom->ToString(str); + nsContentUtils::ASCIIToLower(str); + return NS_Atomize(str); +} + +#endif // txStringUtils_h__ diff --git a/dom/xslt/base/txURIUtils.cpp b/dom/xslt/base/txURIUtils.cpp new file mode 100644 index 0000000000..bbb06221cf --- /dev/null +++ b/dom/xslt/base/txURIUtils.cpp @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "txURIUtils.h" +#include "nsNetUtil.h" +#include "mozilla/dom/Document.h" +#include "nsIPrincipal.h" +#include "mozilla/LoadInfo.h" +#include "mozilla/dom/nsCSPContext.h" + +using mozilla::dom::Document; +using mozilla::net::LoadInfo; + +/** + * URIUtils + * A set of utilities for handling URIs + **/ + +/** + * Resolves the given href argument, using the given documentBase + * if necessary. + * The new resolved href will be appended to the given dest String + **/ +void URIUtils::resolveHref(const nsAString& href, const nsAString& base, + nsAString& dest) { + if (base.IsEmpty()) { + dest.Append(href); + return; + } + if (href.IsEmpty()) { + dest.Append(base); + return; + } + nsCOMPtr<nsIURI> pURL; + nsAutoString resultHref; + nsresult result = NS_NewURI(getter_AddRefs(pURL), base); + if (NS_SUCCEEDED(result)) { + NS_MakeAbsoluteURI(resultHref, href, pURL); + dest.Append(resultHref); + } +} //-- resolveHref + +// static +void URIUtils::ResetWithSource(Document* aNewDoc, nsINode* aSourceNode) { + nsCOMPtr<Document> sourceDoc = aSourceNode->OwnerDoc(); + nsIPrincipal* sourcePrincipal = sourceDoc->NodePrincipal(); + nsIPrincipal* sourcePartitionedPrincipal = sourceDoc->PartitionedPrincipal(); + + // Copy the channel and loadgroup from the source document. + nsCOMPtr<nsILoadGroup> loadGroup = sourceDoc->GetDocumentLoadGroup(); + nsCOMPtr<nsIChannel> channel = sourceDoc->GetChannel(); + if (!channel) { + // Need to synthesize one + nsresult rv = NS_NewChannel( + getter_AddRefs(channel), sourceDoc->GetDocumentURI(), sourceDoc, + nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL, nsIContentPolicy::TYPE_OTHER, + nullptr, // aPerformanceStorage + loadGroup, + nullptr, // aCallbacks + nsIChannel::LOAD_BYPASS_SERVICE_WORKER); + + if (NS_FAILED(rv)) { + return; + } + } + + aNewDoc->Reset(channel, loadGroup); + aNewDoc->SetPrincipals(sourcePrincipal, sourcePartitionedPrincipal); + aNewDoc->SetBaseURI(sourceDoc->GetDocBaseURI()); + aNewDoc->SetSandboxFlags(sourceDoc->GetSandboxFlags()); + aNewDoc->SetReferrerInfo(sourceDoc->GetReferrerInfo()); + aNewDoc->SetEmbedderPolicy(sourceDoc->GetEmbedderPolicy()); + + // Inherit the csp if there is one + nsCOMPtr<nsIContentSecurityPolicy> csp = sourceDoc->GetCsp(); + if (csp) { + RefPtr<nsCSPContext> cspToInherit = new nsCSPContext(); + cspToInherit->InitFromOther(static_cast<nsCSPContext*>(csp.get())); + aNewDoc->SetCsp(cspToInherit); + } + // Copy charset + aNewDoc->SetDocumentCharacterSetSource( + sourceDoc->GetDocumentCharacterSetSource()); + aNewDoc->SetDocumentCharacterSet(sourceDoc->GetDocumentCharacterSet()); +} diff --git a/dom/xslt/base/txURIUtils.h b/dom/xslt/base/txURIUtils.h new file mode 100644 index 0000000000..96082b99f7 --- /dev/null +++ b/dom/xslt/base/txURIUtils.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef TRANSFRMX_URIUTILS_H +#define TRANSFRMX_URIUTILS_H + +#include "txCore.h" + +class nsINode; + +namespace mozilla::dom { +class Document; +} // namespace mozilla::dom + +/** + * A utility class for URI handling + * Not yet finished, only handles file URI at this point + **/ + +class URIUtils { + public: + /** + * Reset the given document with the document of the source node + */ + static void ResetWithSource(mozilla::dom::Document* aNewDoc, + nsINode* aSourceNode); + + /** + * Resolves the given href argument, using the given documentBase + * if necessary. + * The new resolved href will be appended to the given dest String + **/ + static void resolveHref(const nsAString& href, const nsAString& base, + nsAString& dest); +}; //-- URIUtils + +/* */ +#endif |