summaryrefslogtreecommitdiffstats
path: root/dom/xslt/xslt/txBufferingHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xslt/xslt/txBufferingHandler.cpp')
-rw-r--r--dom/xslt/xslt/txBufferingHandler.cpp385
1 files changed, 385 insertions, 0 deletions
diff --git a/dom/xslt/xslt/txBufferingHandler.cpp b/dom/xslt/xslt/txBufferingHandler.cpp
new file mode 100644
index 0000000000..a0c7a39f73
--- /dev/null
+++ b/dom/xslt/xslt/txBufferingHandler.cpp
@@ -0,0 +1,385 @@
+/* -*- 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 "txBufferingHandler.h"
+
+using mozilla::MakeUnique;
+
+class txOutputTransaction {
+ public:
+ enum txTransactionType {
+ eAttributeTransaction,
+ eAttributeAtomTransaction,
+ eCharacterTransaction,
+ eCharacterNoOETransaction,
+ eCommentTransaction,
+ eEndDocumentTransaction,
+ eEndElementTransaction,
+ ePITransaction,
+ eStartDocumentTransaction,
+ eStartElementAtomTransaction,
+ eStartElementTransaction
+ };
+ explicit txOutputTransaction(txTransactionType aType) : mType(aType) {
+ MOZ_COUNT_CTOR(txOutputTransaction);
+ }
+ MOZ_COUNTED_DTOR_VIRTUAL(txOutputTransaction)
+ txTransactionType mType;
+};
+
+class txCharacterTransaction : public txOutputTransaction {
+ public:
+ txCharacterTransaction(txTransactionType aType, uint32_t aLength)
+ : txOutputTransaction(aType), mLength(aLength) {
+ MOZ_COUNT_CTOR_INHERITED(txCharacterTransaction, txOutputTransaction);
+ }
+ virtual ~txCharacterTransaction() {
+ MOZ_COUNT_DTOR_INHERITED(txCharacterTransaction, txOutputTransaction);
+ }
+ uint32_t mLength;
+};
+
+class txCommentTransaction : public txOutputTransaction {
+ public:
+ explicit txCommentTransaction(const nsAString& aValue)
+ : txOutputTransaction(eCommentTransaction), mValue(aValue) {
+ MOZ_COUNT_CTOR_INHERITED(txCommentTransaction, txOutputTransaction);
+ }
+ virtual ~txCommentTransaction() {
+ MOZ_COUNT_DTOR_INHERITED(txCommentTransaction, txOutputTransaction);
+ }
+ nsString mValue;
+};
+
+class txPITransaction : public txOutputTransaction {
+ public:
+ txPITransaction(const nsAString& aTarget, const nsAString& aData)
+ : txOutputTransaction(ePITransaction), mTarget(aTarget), mData(aData) {
+ MOZ_COUNT_CTOR_INHERITED(txPITransaction, txOutputTransaction);
+ }
+ virtual ~txPITransaction() {
+ MOZ_COUNT_DTOR_INHERITED(txPITransaction, txOutputTransaction);
+ }
+ nsString mTarget;
+ nsString mData;
+};
+
+class txStartElementAtomTransaction : public txOutputTransaction {
+ public:
+ txStartElementAtomTransaction(nsAtom* aPrefix, nsAtom* aLocalName,
+ nsAtom* aLowercaseLocalName, int32_t aNsID)
+ : txOutputTransaction(eStartElementAtomTransaction),
+ mPrefix(aPrefix),
+ mLocalName(aLocalName),
+ mLowercaseLocalName(aLowercaseLocalName),
+ mNsID(aNsID) {
+ MOZ_COUNT_CTOR_INHERITED(txStartElementAtomTransaction,
+ txOutputTransaction);
+ }
+ virtual ~txStartElementAtomTransaction() {
+ MOZ_COUNT_DTOR_INHERITED(txStartElementAtomTransaction,
+ txOutputTransaction);
+ }
+ RefPtr<nsAtom> mPrefix;
+ RefPtr<nsAtom> mLocalName;
+ RefPtr<nsAtom> mLowercaseLocalName;
+ int32_t mNsID;
+};
+
+class txStartElementTransaction : public txOutputTransaction {
+ public:
+ txStartElementTransaction(nsAtom* aPrefix, const nsAString& aLocalName,
+ int32_t aNsID)
+ : txOutputTransaction(eStartElementTransaction),
+ mPrefix(aPrefix),
+ mLocalName(aLocalName),
+ mNsID(aNsID) {
+ MOZ_COUNT_CTOR_INHERITED(txStartElementTransaction, txOutputTransaction);
+ }
+ virtual ~txStartElementTransaction() {
+ MOZ_COUNT_DTOR_INHERITED(txStartElementTransaction, txOutputTransaction);
+ }
+ RefPtr<nsAtom> mPrefix;
+ nsString mLocalName;
+ int32_t mNsID;
+};
+
+class txAttributeTransaction : public txOutputTransaction {
+ public:
+ txAttributeTransaction(nsAtom* aPrefix, const nsAString& aLocalName,
+ int32_t aNsID, const nsString& aValue)
+ : txOutputTransaction(eAttributeTransaction),
+ mPrefix(aPrefix),
+ mLocalName(aLocalName),
+ mNsID(aNsID),
+ mValue(aValue) {
+ MOZ_COUNT_CTOR_INHERITED(txAttributeTransaction, txOutputTransaction);
+ }
+ virtual ~txAttributeTransaction() {
+ MOZ_COUNT_DTOR_INHERITED(txAttributeTransaction, txOutputTransaction);
+ }
+ RefPtr<nsAtom> mPrefix;
+ nsString mLocalName;
+ int32_t mNsID;
+ nsString mValue;
+};
+
+class txAttributeAtomTransaction : public txOutputTransaction {
+ public:
+ txAttributeAtomTransaction(nsAtom* aPrefix, nsAtom* aLocalName,
+ nsAtom* aLowercaseLocalName, int32_t aNsID,
+ const nsString& aValue)
+ : txOutputTransaction(eAttributeAtomTransaction),
+ mPrefix(aPrefix),
+ mLocalName(aLocalName),
+ mLowercaseLocalName(aLowercaseLocalName),
+ mNsID(aNsID),
+ mValue(aValue) {
+ MOZ_COUNT_CTOR_INHERITED(txAttributeAtomTransaction, txOutputTransaction);
+ }
+ virtual ~txAttributeAtomTransaction() {
+ MOZ_COUNT_DTOR_INHERITED(txAttributeAtomTransaction, txOutputTransaction);
+ }
+ RefPtr<nsAtom> mPrefix;
+ RefPtr<nsAtom> mLocalName;
+ RefPtr<nsAtom> mLowercaseLocalName;
+ int32_t mNsID;
+ nsString mValue;
+};
+
+txBufferingHandler::txBufferingHandler() : mCanAddAttribute(false) {
+ MOZ_COUNT_CTOR(txBufferingHandler);
+ mBuffer = MakeUnique<txResultBuffer>();
+}
+
+txBufferingHandler::~txBufferingHandler() {
+ MOZ_COUNT_DTOR(txBufferingHandler);
+}
+
+nsresult txBufferingHandler::attribute(nsAtom* aPrefix, nsAtom* aLocalName,
+ nsAtom* aLowercaseLocalName,
+ int32_t aNsID, const nsString& aValue) {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ if (!mCanAddAttribute) {
+ // XXX ErrorReport: Can't add attributes without element
+ return NS_OK;
+ }
+
+ txOutputTransaction* transaction = new txAttributeAtomTransaction(
+ aPrefix, aLocalName, aLowercaseLocalName, aNsID, aValue);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::attribute(nsAtom* aPrefix,
+ const nsAString& aLocalName,
+ const int32_t aNsID,
+ const nsString& aValue) {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ if (!mCanAddAttribute) {
+ // XXX ErrorReport: Can't add attributes without element
+ return NS_OK;
+ }
+
+ txOutputTransaction* transaction =
+ new txAttributeTransaction(aPrefix, aLocalName, aNsID, aValue);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::characters(const nsAString& aData, bool aDOE) {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ mCanAddAttribute = false;
+
+ txOutputTransaction::txTransactionType type =
+ aDOE ? txOutputTransaction::eCharacterNoOETransaction
+ : txOutputTransaction::eCharacterTransaction;
+
+ txOutputTransaction* transaction = mBuffer->getLastTransaction();
+ if (transaction && transaction->mType == type) {
+ mBuffer->mStringValue.Append(aData);
+ static_cast<txCharacterTransaction*>(transaction)->mLength +=
+ aData.Length();
+ return NS_OK;
+ }
+
+ transaction = new txCharacterTransaction(type, aData.Length());
+ mBuffer->mStringValue.Append(aData);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::comment(const nsString& aData) {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ mCanAddAttribute = false;
+
+ txOutputTransaction* transaction = new txCommentTransaction(aData);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::endDocument(nsresult aResult) {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ txOutputTransaction* transaction =
+ new txOutputTransaction(txOutputTransaction::eEndDocumentTransaction);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::endElement() {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ mCanAddAttribute = false;
+
+ txOutputTransaction* transaction =
+ new txOutputTransaction(txOutputTransaction::eEndElementTransaction);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::processingInstruction(const nsString& aTarget,
+ const nsString& aData) {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ mCanAddAttribute = false;
+
+ txOutputTransaction* transaction = new txPITransaction(aTarget, aData);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::startDocument() {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ txOutputTransaction* transaction =
+ new txOutputTransaction(txOutputTransaction::eStartDocumentTransaction);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::startElement(nsAtom* aPrefix, nsAtom* aLocalName,
+ nsAtom* aLowercaseLocalName,
+ int32_t aNsID) {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ mCanAddAttribute = true;
+
+ txOutputTransaction* transaction = new txStartElementAtomTransaction(
+ aPrefix, aLocalName, aLowercaseLocalName, aNsID);
+ return mBuffer->addTransaction(transaction);
+}
+
+nsresult txBufferingHandler::startElement(nsAtom* aPrefix,
+ const nsAString& aLocalName,
+ const int32_t aNsID) {
+ NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ mCanAddAttribute = true;
+
+ txOutputTransaction* transaction =
+ new txStartElementTransaction(aPrefix, aLocalName, aNsID);
+ return mBuffer->addTransaction(transaction);
+}
+
+txResultBuffer::txResultBuffer() { MOZ_COUNT_CTOR(txResultBuffer); }
+
+txResultBuffer::~txResultBuffer() {
+ MOZ_COUNT_DTOR(txResultBuffer);
+ for (uint32_t i = 0, len = mTransactions.Length(); i < len; ++i) {
+ delete mTransactions[i];
+ }
+}
+
+nsresult txResultBuffer::addTransaction(txOutputTransaction* aTransaction) {
+ // XXX(Bug 1631371) Check if this should use a fallible operation as it
+ // pretended earlier, or change the return type to void.
+ mTransactions.AppendElement(aTransaction);
+ return NS_OK;
+}
+
+static nsresult flushTransaction(txOutputTransaction* aTransaction,
+ txAXMLEventHandler* aHandler,
+ nsString::const_char_iterator& aIter) {
+ switch (aTransaction->mType) {
+ case txOutputTransaction::eAttributeAtomTransaction: {
+ txAttributeAtomTransaction* transaction =
+ static_cast<txAttributeAtomTransaction*>(aTransaction);
+ return aHandler->attribute(transaction->mPrefix, transaction->mLocalName,
+ transaction->mLowercaseLocalName,
+ transaction->mNsID, transaction->mValue);
+ }
+ case txOutputTransaction::eAttributeTransaction: {
+ txAttributeTransaction* attrTransaction =
+ static_cast<txAttributeTransaction*>(aTransaction);
+ return aHandler->attribute(
+ attrTransaction->mPrefix, attrTransaction->mLocalName,
+ attrTransaction->mNsID, attrTransaction->mValue);
+ }
+ case txOutputTransaction::eCharacterTransaction:
+ case txOutputTransaction::eCharacterNoOETransaction: {
+ txCharacterTransaction* charTransaction =
+ static_cast<txCharacterTransaction*>(aTransaction);
+ nsString::const_char_iterator start = aIter;
+ nsString::const_char_iterator end = start + charTransaction->mLength;
+ aIter = end;
+ return aHandler->characters(
+ Substring(start, end),
+ aTransaction->mType ==
+ txOutputTransaction::eCharacterNoOETransaction);
+ }
+ case txOutputTransaction::eCommentTransaction: {
+ txCommentTransaction* commentTransaction =
+ static_cast<txCommentTransaction*>(aTransaction);
+ return aHandler->comment(commentTransaction->mValue);
+ }
+ case txOutputTransaction::eEndElementTransaction: {
+ return aHandler->endElement();
+ }
+ case txOutputTransaction::ePITransaction: {
+ txPITransaction* piTransaction =
+ static_cast<txPITransaction*>(aTransaction);
+ return aHandler->processingInstruction(piTransaction->mTarget,
+ piTransaction->mData);
+ }
+ case txOutputTransaction::eStartDocumentTransaction: {
+ return aHandler->startDocument();
+ }
+ case txOutputTransaction::eStartElementAtomTransaction: {
+ txStartElementAtomTransaction* transaction =
+ static_cast<txStartElementAtomTransaction*>(aTransaction);
+ return aHandler->startElement(
+ transaction->mPrefix, transaction->mLocalName,
+ transaction->mLowercaseLocalName, transaction->mNsID);
+ }
+ case txOutputTransaction::eStartElementTransaction: {
+ txStartElementTransaction* transaction =
+ static_cast<txStartElementTransaction*>(aTransaction);
+ return aHandler->startElement(
+ transaction->mPrefix, transaction->mLocalName, transaction->mNsID);
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("Unexpected transaction type");
+ }
+ }
+
+ return NS_ERROR_UNEXPECTED;
+}
+
+nsresult txResultBuffer::flushToHandler(txAXMLEventHandler* aHandler) {
+ nsString::const_char_iterator iter;
+ mStringValue.BeginReading(iter);
+
+ for (uint32_t i = 0, len = mTransactions.Length(); i < len; ++i) {
+ nsresult rv = flushTransaction(mTransactions[i], aHandler, iter);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
+txOutputTransaction* txResultBuffer::getLastTransaction() {
+ int32_t last = mTransactions.Length() - 1;
+ if (last < 0) {
+ return nullptr;
+ }
+ return mTransactions[last];
+}