diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/xslt/base | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/xslt/base')
-rw-r--r-- | dom/xslt/base/moz.build | 26 | ||||
-rw-r--r-- | dom/xslt/base/txCore.h | 51 | ||||
-rw-r--r-- | dom/xslt/base/txDouble.cpp | 215 | ||||
-rw-r--r-- | dom/xslt/base/txErrorObserver.h | 41 | ||||
-rw-r--r-- | dom/xslt/base/txExpandedName.cpp | 41 | ||||
-rw-r--r-- | dom/xslt/base/txExpandedName.h | 70 | ||||
-rw-r--r-- | dom/xslt/base/txExpandedNameMap.cpp | 104 | ||||
-rw-r--r-- | dom/xslt/base/txExpandedNameMap.h | 203 | ||||
-rw-r--r-- | dom/xslt/base/txList.cpp | 278 | ||||
-rw-r--r-- | dom/xslt/base/txList.h | 161 | ||||
-rw-r--r-- | dom/xslt/base/txLog.h | 24 | ||||
-rw-r--r-- | dom/xslt/base/txNamespaceMap.cpp | 98 | ||||
-rw-r--r-- | dom/xslt/base/txNamespaceMap.h | 43 | ||||
-rw-r--r-- | dom/xslt/base/txOwningArray.h | 32 | ||||
-rw-r--r-- | dom/xslt/base/txStack.h | 122 | ||||
-rw-r--r-- | dom/xslt/base/txStringUtils.h | 34 | ||||
-rw-r--r-- | dom/xslt/base/txURIUtils.cpp | 78 | ||||
-rw-r--r-- | dom/xslt/base/txURIUtils.h | 37 |
18 files changed, 1658 insertions, 0 deletions
diff --git a/dom/xslt/base/moz.build b/dom/xslt/base/moz.build new file mode 100644 index 000000000..7d9cd70fa --- /dev/null +++ b/dom/xslt/base/moz.build @@ -0,0 +1,26 @@ +# -*- 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' + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] diff --git a/dom/xslt/base/txCore.h b/dom/xslt/base/txCore.h new file mode 100644 index 000000000..3bce3c089 --- /dev/null +++ b/dom/xslt/base/txCore.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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" + +class nsAString; + +class txObject +{ +public: + txObject() + { + MOZ_COUNT_CTOR(txObject); + } + + /** + * Deletes this txObject + */ + virtual ~txObject() + { + MOZ_COUNT_DTOR(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 000000000..f52d1b885 --- /dev/null +++ b/dom/xslt/base/txDouble.cpp @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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: + typedef char16_t input_type; + typedef char16_t value_type; + txStringToDouble(): mState(eWhitestart), mSign(ePositive) {} + + void + write(const input_type* aSource, uint32_t aSourceLength) + { + if (mState == eIllegal) { + return; + } + uint32_t i = 0; + char16_t c; + for ( ; i < aSourceLength; ++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 mSign*PR_strtod(mBuffer.get(), 0); + } +private: + nsAutoCString mBuffer; + enum { + eWhitestart, + eDecimal, + eMantissa, + eWhiteend, + eIllegal + } mState; + enum { + eNegative = -1, + ePositive = 1 + } mSign; +}; + +double txDouble::toDouble(const nsAString& aSrc) +{ + txStringToDouble sink; + nsAString::const_iterator fromBegin, fromEnd; + copy_string(aSrc.BeginReading(fromBegin), aSrc.EndReading(fromEnd), sink); + 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 (mozilla::IsNaN(aValue)) { + aDest.AppendLiteral("NaN"); + return; + } + if (mozilla::IsInfinite(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 + nsAString::iterator dest; + aDest.BeginWriting(dest).advance(int32_t(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 000000000..3c6be8294 --- /dev/null +++ b/dom/xslt/base/txErrorObserver.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 000000000..43283e425 --- /dev/null +++ b/dom/xslt/base/txExpandedName.cpp @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 nsAFlatString& qName = PromiseFlatString(aQName); + const char16_t* colon; + bool valid = XMLUtils::isValidQName(qName, &colon); + if (!valid) { + return NS_ERROR_FAILURE; + } + + if (colon) { + nsCOMPtr<nsIAtom> 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 000000000..b49fa5134 --- /dev/null +++ b/dom/xslt/base/txExpandedName.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsIAtom.h" +#include "mozilla/dom/NameSpaceConstants.h" + +class txNamespaceMap; + +class txExpandedName { +public: + txExpandedName() : mNamespaceID(kNameSpaceID_None) + { + } + + txExpandedName(int32_t aNsID, + nsIAtom* aLocalName) : mNamespaceID(aNsID), + mLocalName(aLocalName) + { + } + + txExpandedName(const txExpandedName& aOther) : + mNamespaceID(aOther.mNamespaceID), + mLocalName(aOther.mLocalName) + { + } + + 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) + { + mNamespaceID = rhs.mNamespaceID; + mLocalName = rhs.mLocalName; + return *this; + } + + 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; + nsCOMPtr<nsIAtom> mLocalName; +}; + +#endif diff --git a/dom/xslt/base/txExpandedNameMap.cpp b/dom/xslt/base/txExpandedNameMap.cpp new file mode 100644 index 000000000..b033d6155 --- /dev/null +++ b/dom/xslt/base/txExpandedNameMap.cpp @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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(); + NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); + + 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(); + NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); + + 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 000000000..de0861427 --- /dev/null +++ b/dom/xslt/base/txExpandedNameMap.h @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsAutoPtr.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; + nsCOMPtr<nsIAtom> 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) + { + nsAutoPtr<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 000000000..fa4952ad9 --- /dev/null +++ b/dom/xslt/base/txList.cpp @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 + +nsresult txList::add(void* objPtr) +{ + return insertBefore(objPtr, 0); +} //-- 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 +**/ +nsresult txList::insertAfter(void* objPtr, ListItem* refItem) +{ + //-- if refItem == null insert at front + if (!refItem) + return insertBefore(objPtr, firstItem); + return insertBefore(objPtr, refItem->nextItem); +} //-- 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 +**/ +nsresult 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; + + return NS_OK; +} //-- 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 +**/ +nsresult txListIterator::addAfter(void* objPtr) +{ + if (currentItem || !atEndOfList) + return list->insertAfter(objPtr, currentItem); + return list->insertBefore(objPtr, 0); + +} //-- 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 +**/ +nsresult txListIterator::addBefore(void* objPtr) +{ + if (currentItem || atEndOfList) + return list->insertBefore(objPtr, currentItem); + return list->insertAfter(objPtr, 0); + +} //-- 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 000000000..180bab1af --- /dev/null +++ b/dom/xslt/base/txList.h @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 + **/ + nsresult 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; + + nsresult insertAfter(void* objPtr, ListItem* sItem); + nsresult 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 + **/ + nsresult 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 + **/ + nsresult 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; +}; + +typedef txList List; + +#endif diff --git a/dom/xslt/base/txLog.h b/dom/xslt/base/txLog.h new file mode 100644 index 000000000..0387c9d60 --- /dev/null +++ b/dom/xslt/base/txLog.h @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 000000000..cb6c4b164 --- /dev/null +++ b/dom/xslt/base/txNamespaceMap.cpp @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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() +{ +} + +txNamespaceMap::txNamespaceMap(const txNamespaceMap& aOther) + : mPrefixes(aOther.mPrefixes) +{ + mNamespaces = aOther.mNamespaces; //bah! I want a copy-constructor! +} + +nsresult +txNamespaceMap::mapNamespace(nsIAtom* aPrefix, const nsAString& aNamespaceURI) +{ + nsIAtom* 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.RemoveObjectAt(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 + if (!mPrefixes.AppendObject(prefix)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + if (mNamespaces.AppendElement(nsId) == nullptr) { + mPrefixes.RemoveObjectAt(mPrefixes.Count() - 1); + + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +int32_t +txNamespaceMap::lookupNamespace(nsIAtom* aPrefix) +{ + if (aPrefix == nsGkAtoms::xml) { + return kNameSpaceID_XML; + } + + nsIAtom* 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) +{ + nsCOMPtr<nsIAtom> 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 000000000..0e6be57c6 --- /dev/null +++ b/dom/xslt/base/txNamespaceMap.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsIAtom.h" +#include "nsCOMArray.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(nsIAtom* aPrefix, const nsAString& aNamespaceURI); + int32_t lookupNamespace(nsIAtom* aPrefix); + int32_t lookupNamespaceWithDefault(const nsAString& aPrefix); + +private: + nsAutoRefCnt mRefCnt; + nsCOMArray<nsIAtom> 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 000000000..6ec7ebd22 --- /dev/null +++ b/dom/xslt/base/txOwningArray.h @@ -0,0 +1,32 @@ +/* -*- 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::elem_type elem_type; + + ~txOwningArray() + { + elem_type* iter = base_type::Elements(); + elem_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 000000000..53ce29862 --- /dev/null +++ b/dom/xslt/base/txStack.h @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 nsresult push(void* aObject) + { + return AppendElement(aObject) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + } + + /** + * 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()) + { + const uint32_t count = Length() - 1; + object = ElementAt(count); + RemoveElementAt(count); + } + 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 000000000..6f45fe661 --- /dev/null +++ b/dom/xslt/base/txStringUtils.h @@ -0,0 +1,34 @@ +/* -*- 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 "nsIAtom.h" +#include "nsUnicharUtils.h" +#include "nsContentUtils.h" // For ASCIIToLower(). + +typedef nsCaseInsensitiveStringComparator txCaseInsensitiveStringComparator; + +/** + * Check equality between a string and an atom containing ASCII. + */ +inline bool +TX_StringEqualsAtom(const nsASingleFragmentString& aString, nsIAtom* aAtom) +{ + return aAtom->Equals(aString); +} + +inline already_AddRefed<nsIAtom> +TX_ToLowerCaseAtom(nsIAtom* 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 000000000..3f3556f80 --- /dev/null +++ b/dom/xslt/base/txURIUtils.cpp @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 "nsIDocument.h" +#include "nsIHttpChannelInternal.h" +#include "nsIPrincipal.h" +#include "mozilla/LoadInfo.h" + +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(nsIDocument *aNewDoc, nsINode *aSourceNode) +{ + nsCOMPtr<nsIDocument> sourceDoc = aSourceNode->OwnerDoc(); + nsIPrincipal* sourcePrincipal = sourceDoc->NodePrincipal(); + + // 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, + loadGroup, + nullptr, // aCallbacks + nsIChannel::LOAD_BYPASS_SERVICE_WORKER); + + if (NS_FAILED(rv)) { + return; + } + } + + aNewDoc->Reset(channel, loadGroup); + aNewDoc->SetPrincipal(sourcePrincipal); + aNewDoc->SetBaseURI(sourceDoc->GetDocBaseURI()); + + // 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 000000000..ad182a00a --- /dev/null +++ b/dom/xslt/base/txURIUtils.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 nsIDocument; +class nsINode; + +/** + * 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(nsIDocument *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 |