summaryrefslogtreecommitdiffstats
path: root/dom/xslt/xslt/txEXSLTFunctions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xslt/xslt/txEXSLTFunctions.cpp')
-rw-r--r--dom/xslt/xslt/txEXSLTFunctions.cpp818
1 files changed, 818 insertions, 0 deletions
diff --git a/dom/xslt/xslt/txEXSLTFunctions.cpp b/dom/xslt/xslt/txEXSLTFunctions.cpp
new file mode 100644
index 0000000000..d4882d0b13
--- /dev/null
+++ b/dom/xslt/xslt/txEXSLTFunctions.cpp
@@ -0,0 +1,818 @@
+/* -*- 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/ArrayUtils.h"
+#include "mozilla/EnumeratedArray.h"
+#include "mozilla/EnumeratedRange.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/MacroArgs.h"
+#include "mozilla/MacroForEach.h"
+
+#include "nsAtom.h"
+#include "nsGkAtoms.h"
+#include "txExecutionState.h"
+#include "txExpr.h"
+#include "txIXPathContext.h"
+#include "txIEXSLTFunctions.h"
+#include "txNodeSet.h"
+#include "txOutputFormat.h"
+#include "txRtfHandler.h"
+#include "txXPathTreeWalker.h"
+#include "nsImportModule.h"
+#include "nsPrintfCString.h"
+#include "nsComponentManagerUtils.h"
+#include "nsContentCID.h"
+#include "nsContentCreatorFunctions.h"
+#include "nsIContent.h"
+#include "txMozillaXMLOutput.h"
+#include "nsTextNode.h"
+#include "mozilla/dom/DocumentFragmentBinding.h"
+#include "prtime.h"
+#include "xpcprivate.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+class txStylesheetCompilerState;
+
+// ------------------------------------------------------------------
+// Utility functions
+// ------------------------------------------------------------------
+
+static Document* getSourceDocument(txIEvalContext* aContext) {
+ txExecutionState* es =
+ static_cast<txExecutionState*>(aContext->getPrivateContext());
+ if (!es) {
+ NS_ERROR("Need txExecutionState!");
+
+ return nullptr;
+ }
+
+ const txXPathNode& document = es->getSourceDocument();
+ return txXPathNativeNode::getDocument(document);
+}
+
+static nsresult convertRtfToNode(txIEvalContext* aContext,
+ txResultTreeFragment* aRtf) {
+ Document* doc = getSourceDocument(aContext);
+ if (!doc) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ RefPtr<DocumentFragment> domFragment =
+ new (doc->NodeInfoManager()) DocumentFragment(doc->NodeInfoManager());
+
+ txOutputFormat format;
+ txMozillaXMLOutput mozHandler(&format, domFragment, true);
+
+ nsresult rv = aRtf->flushToHandler(&mozHandler);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = mozHandler.closePrevious(true);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // The txResultTreeFragment will own this.
+ const txXPathNode* node =
+ txXPathNativeNode::createXPathNode(domFragment, true);
+ NS_ENSURE_TRUE(node, NS_ERROR_OUT_OF_MEMORY);
+
+ aRtf->setNode(node);
+
+ return NS_OK;
+}
+
+static nsresult createTextNode(txIEvalContext* aContext, nsString& aValue,
+ txXPathNode** aResult) {
+ Document* doc = getSourceDocument(aContext);
+ if (!doc) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ RefPtr<nsTextNode> text =
+ new (doc->NodeInfoManager()) nsTextNode(doc->NodeInfoManager());
+
+ nsresult rv = text->SetText(aValue, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ *aResult = txXPathNativeNode::createXPathNode(text, true);
+ NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
+
+ return NS_OK;
+}
+
+static nsresult createAndAddToResult(nsAtom* aName, const nsAString& aValue,
+ txNodeSet* aResultSet,
+ DocumentFragment* aResultHolder) {
+ Document* doc = aResultHolder->OwnerDoc();
+ nsCOMPtr<Element> elem =
+ doc->CreateElem(nsDependentAtomString(aName), nullptr, kNameSpaceID_None);
+ NS_ENSURE_TRUE(elem, NS_ERROR_NULL_POINTER);
+
+ RefPtr<nsTextNode> text =
+ new (doc->NodeInfoManager()) nsTextNode(doc->NodeInfoManager());
+
+ nsresult rv = text->SetText(aValue, false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ ErrorResult error;
+ elem->AppendChildTo(text, false, error);
+ if (error.Failed()) {
+ return error.StealNSResult();
+ }
+
+ aResultHolder->AppendChildTo(elem, false, error);
+ if (error.Failed()) {
+ return error.StealNSResult();
+ }
+
+ UniquePtr<txXPathNode> xpathNode(
+ txXPathNativeNode::createXPathNode(elem, true));
+ NS_ENSURE_TRUE(xpathNode, NS_ERROR_OUT_OF_MEMORY);
+
+ aResultSet->append(*xpathNode);
+
+ return NS_OK;
+}
+
+// Need to update this array if types are added to the ResultType enum in
+// txAExprResult.
+static const char* const sTypes[] = {"node-set", "boolean", "number", "string",
+ "RTF"};
+
+// ------------------------------------------------------------------
+// Function implementations
+// ------------------------------------------------------------------
+
+enum class txEXSLTType {
+ // http://exslt.org/common
+ NODE_SET,
+ OBJECT_TYPE,
+
+ // http://exslt.org/dates-and-times
+ DATE_TIME,
+
+ // http://exslt.org/math
+ MAX,
+ MIN,
+ HIGHEST,
+ LOWEST,
+
+ // http://exslt.org/regular-expressions
+ MATCH,
+ REPLACE,
+ TEST,
+
+ // http://exslt.org/sets
+ DIFFERENCE_, // not DIFFERENCE to avoid a conflict with a winuser.h macro
+ DISTINCT,
+ HAS_SAME_NODE,
+ INTERSECTION,
+ LEADING,
+ TRAILING,
+
+ // http://exslt.org/strings
+ CONCAT,
+ SPLIT,
+ TOKENIZE,
+
+ _LIMIT,
+};
+
+struct txEXSLTFunctionDescriptor {
+ int8_t mMinParams;
+ int8_t mMaxParams;
+ Expr::ResultType mReturnType;
+ nsStaticAtom* mName;
+ bool (*mCreator)(txEXSLTType, FunctionCall**);
+ int32_t mNamespaceID;
+};
+
+static EnumeratedArray<txEXSLTType, txEXSLTType::_LIMIT,
+ txEXSLTFunctionDescriptor>
+ descriptTable;
+
+class txEXSLTFunctionCall : public FunctionCall {
+ public:
+ explicit txEXSLTFunctionCall(txEXSLTType aType) : mType(aType) {}
+
+ static bool Create(txEXSLTType aType, FunctionCall** aFunction) {
+ *aFunction = new txEXSLTFunctionCall(aType);
+ return true;
+ }
+
+ TX_DECL_FUNCTION
+
+ private:
+ txEXSLTType mType;
+};
+
+class txEXSLTRegExFunctionCall : public FunctionCall {
+ public:
+ explicit txEXSLTRegExFunctionCall(txEXSLTType aType) : mType(aType) {}
+
+ static bool Create(txEXSLTType aType, FunctionCall** aFunction) {
+ *aFunction = new txEXSLTRegExFunctionCall(aType);
+ return true;
+ }
+
+ TX_DECL_FUNCTION
+
+ private:
+ txEXSLTType mType;
+};
+
+nsresult txEXSLTFunctionCall::evaluate(txIEvalContext* aContext,
+ txAExprResult** aResult) {
+ *aResult = nullptr;
+ if (!requireParams(descriptTable[mType].mMinParams,
+ descriptTable[mType].mMaxParams, aContext)) {
+ return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
+ }
+
+ nsresult rv = NS_OK;
+ switch (mType) {
+ case txEXSLTType::NODE_SET: {
+ RefPtr<txAExprResult> exprResult;
+ rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (exprResult->getResultType() == txAExprResult::NODESET) {
+ exprResult.forget(aResult);
+ } else {
+ RefPtr<txNodeSet> resultSet;
+ rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (exprResult->getResultType() ==
+ txAExprResult::RESULT_TREE_FRAGMENT) {
+ txResultTreeFragment* rtf =
+ static_cast<txResultTreeFragment*>(exprResult.get());
+
+ const txXPathNode* node = rtf->getNode();
+ if (!node) {
+ rv = convertRtfToNode(aContext, rtf);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ node = rtf->getNode();
+ }
+
+ resultSet->append(*node);
+ } else {
+ nsAutoString value;
+ exprResult->stringValue(value);
+
+ UniquePtr<txXPathNode> node;
+ rv = createTextNode(aContext, value, getter_Transfers(node));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ resultSet->append(*node);
+ }
+
+ NS_ADDREF(*aResult = resultSet);
+ }
+
+ return NS_OK;
+ }
+ case txEXSLTType::OBJECT_TYPE: {
+ RefPtr<txAExprResult> exprResult;
+ nsresult rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<StringResult> strRes;
+ rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ AppendASCIItoUTF16(MakeStringSpan(sTypes[exprResult->getResultType()]),
+ strRes->mValue);
+
+ NS_ADDREF(*aResult = strRes);
+
+ return NS_OK;
+ }
+ case txEXSLTType::DIFFERENCE_:
+ case txEXSLTType::INTERSECTION: {
+ RefPtr<txNodeSet> nodes1;
+ rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes1));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<txNodeSet> nodes2;
+ rv = evaluateToNodeSet(mParams[1], aContext, getter_AddRefs(nodes2));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<txNodeSet> resultSet;
+ rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool insertOnFound = mType == txEXSLTType::INTERSECTION;
+
+ int32_t searchPos = 0;
+ int32_t i, len = nodes1->size();
+ for (i = 0; i < len; ++i) {
+ const txXPathNode& node = nodes1->get(i);
+ int32_t foundPos = nodes2->indexOf(node, searchPos);
+ if (foundPos >= 0) {
+ searchPos = foundPos + 1;
+ }
+
+ if ((foundPos >= 0) == insertOnFound) {
+ rv = resultSet->append(node);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ NS_ADDREF(*aResult = resultSet);
+
+ return NS_OK;
+ }
+ case txEXSLTType::DISTINCT: {
+ RefPtr<txNodeSet> nodes;
+ rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<txNodeSet> resultSet;
+ rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsTHashSet<nsString> hash;
+
+ int32_t i, len = nodes->size();
+ for (i = 0; i < len; ++i) {
+ nsAutoString str;
+ const txXPathNode& node = nodes->get(i);
+ txXPathNodeUtils::appendNodeValue(node, str);
+ if (hash.EnsureInserted(str)) {
+ rv = resultSet->append(node);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ NS_ADDREF(*aResult = resultSet);
+
+ return NS_OK;
+ }
+ case txEXSLTType::HAS_SAME_NODE: {
+ RefPtr<txNodeSet> nodes1;
+ rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes1));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<txNodeSet> nodes2;
+ rv = evaluateToNodeSet(mParams[1], aContext, getter_AddRefs(nodes2));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool found = false;
+ int32_t i, len = nodes1->size();
+ for (i = 0; i < len; ++i) {
+ if (nodes2->contains(nodes1->get(i))) {
+ found = true;
+ break;
+ }
+ }
+
+ aContext->recycler()->getBoolResult(found, aResult);
+
+ return NS_OK;
+ }
+ case txEXSLTType::LEADING:
+ case txEXSLTType::TRAILING: {
+ RefPtr<txNodeSet> nodes1;
+ rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes1));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<txNodeSet> nodes2;
+ rv = evaluateToNodeSet(mParams[1], aContext, getter_AddRefs(nodes2));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (nodes2->isEmpty()) {
+ *aResult = nodes1;
+ NS_ADDREF(*aResult);
+
+ return NS_OK;
+ }
+
+ RefPtr<txNodeSet> resultSet;
+ rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ int32_t end = nodes1->indexOf(nodes2->get(0));
+ if (end >= 0) {
+ int32_t i = 0;
+ if (mType == txEXSLTType::TRAILING) {
+ i = end + 1;
+ end = nodes1->size();
+ }
+ for (; i < end; ++i) {
+ rv = resultSet->append(nodes1->get(i));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ NS_ADDREF(*aResult = resultSet);
+
+ return NS_OK;
+ }
+ case txEXSLTType::CONCAT: {
+ RefPtr<txNodeSet> nodes;
+ rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString str;
+ int32_t i, len = nodes->size();
+ for (i = 0; i < len; ++i) {
+ txXPathNodeUtils::appendNodeValue(nodes->get(i), str);
+ }
+
+ return aContext->recycler()->getStringResult(str, aResult);
+ }
+ case txEXSLTType::SPLIT:
+ case txEXSLTType::TOKENIZE: {
+ // Evaluate parameters
+ nsAutoString string;
+ rv = mParams[0]->evaluateToString(aContext, string);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString pattern;
+ if (mParams.Length() == 2) {
+ rv = mParams[1]->evaluateToString(aContext, pattern);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else if (mType == txEXSLTType::SPLIT) {
+ pattern.Assign(' ');
+ } else {
+ pattern.AssignLiteral("\t\r\n ");
+ }
+
+ // Set up holders for the result
+ Document* sourceDoc = getSourceDocument(aContext);
+ NS_ENSURE_STATE(sourceDoc);
+
+ RefPtr<DocumentFragment> docFrag = new (sourceDoc->NodeInfoManager())
+ DocumentFragment(sourceDoc->NodeInfoManager());
+
+ RefPtr<txNodeSet> resultSet;
+ rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint32_t tailIndex;
+
+ // Start splitting
+ if (pattern.IsEmpty()) {
+ nsString::const_char_iterator start = string.BeginReading();
+ nsString::const_char_iterator end = string.EndReading();
+ for (; start < end; ++start) {
+ rv = createAndAddToResult(nsGkAtoms::token,
+ Substring(start, start + 1), resultSet,
+ docFrag);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ tailIndex = string.Length();
+ } else if (mType == txEXSLTType::SPLIT) {
+ nsAString::const_iterator strStart, strEnd;
+ string.BeginReading(strStart);
+ string.EndReading(strEnd);
+ nsAString::const_iterator start = strStart, end = strEnd;
+
+ while (FindInReadable(pattern, start, end)) {
+ if (start != strStart) {
+ rv = createAndAddToResult(nsGkAtoms::token,
+ Substring(strStart, start), resultSet,
+ docFrag);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ strStart = start = end;
+ end = strEnd;
+ }
+
+ tailIndex = strStart.get() - string.get();
+ } else {
+ int32_t found, start = 0;
+ while ((found = string.FindCharInSet(pattern, start)) != kNotFound) {
+ if (found != start) {
+ rv = createAndAddToResult(nsGkAtoms::token,
+ Substring(string, start, found - start),
+ resultSet, docFrag);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ start = found + 1;
+ }
+
+ tailIndex = start;
+ }
+
+ // Add tail if needed
+ if (tailIndex != (uint32_t)string.Length()) {
+ rv = createAndAddToResult(
+ nsGkAtoms::token, Substring(string, tailIndex), resultSet, docFrag);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ NS_ADDREF(*aResult = resultSet);
+
+ return NS_OK;
+ }
+ case txEXSLTType::MAX:
+ case txEXSLTType::MIN: {
+ RefPtr<txNodeSet> nodes;
+ rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (nodes->isEmpty()) {
+ return aContext->recycler()->getNumberResult(UnspecifiedNaN<double>(),
+ aResult);
+ }
+
+ bool findMax = mType == txEXSLTType::MAX;
+
+ double res = findMax ? mozilla::NegativeInfinity<double>()
+ : mozilla::PositiveInfinity<double>();
+ int32_t i, len = nodes->size();
+ for (i = 0; i < len; ++i) {
+ nsAutoString str;
+ txXPathNodeUtils::appendNodeValue(nodes->get(i), str);
+ double val = txDouble::toDouble(str);
+ if (std::isnan(val)) {
+ res = UnspecifiedNaN<double>();
+ break;
+ }
+
+ if (findMax ? (val > res) : (val < res)) {
+ res = val;
+ }
+ }
+
+ return aContext->recycler()->getNumberResult(res, aResult);
+ }
+ case txEXSLTType::HIGHEST:
+ case txEXSLTType::LOWEST: {
+ RefPtr<txNodeSet> nodes;
+ rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (nodes->isEmpty()) {
+ NS_ADDREF(*aResult = nodes);
+
+ return NS_OK;
+ }
+
+ RefPtr<txNodeSet> resultSet;
+ rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool findMax = mType == txEXSLTType::HIGHEST;
+ double res = findMax ? mozilla::NegativeInfinity<double>()
+ : mozilla::PositiveInfinity<double>();
+ int32_t i, len = nodes->size();
+ for (i = 0; i < len; ++i) {
+ nsAutoString str;
+ const txXPathNode& node = nodes->get(i);
+ txXPathNodeUtils::appendNodeValue(node, str);
+ double val = txDouble::toDouble(str);
+ if (std::isnan(val)) {
+ resultSet->clear();
+ break;
+ }
+ if (findMax ? (val > res) : (val < res)) {
+ resultSet->clear();
+ res = val;
+ }
+
+ if (res == val) {
+ rv = resultSet->append(node);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ NS_ADDREF(*aResult = resultSet);
+
+ return NS_OK;
+ }
+ case txEXSLTType::DATE_TIME: {
+ // http://exslt.org/date/functions/date-time/
+
+ PRExplodedTime prtime;
+ PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime);
+
+ int32_t offset =
+ (prtime.tm_params.tp_gmt_offset + prtime.tm_params.tp_dst_offset) /
+ 60;
+
+ bool isneg = offset < 0;
+ if (isneg) offset = -offset;
+
+ StringResult* strRes;
+ rv = aContext->recycler()->getStringResult(&strRes);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // format: YYYY-MM-DDTTHH:MM:SS.sss+00:00
+ CopyASCIItoUTF16(
+ nsPrintfCString("%04hd-%02" PRId32 "-%02" PRId32 "T%02" PRId32
+ ":%02" PRId32 ":%02" PRId32 ".%03" PRId32
+ "%c%02" PRId32 ":%02" PRId32,
+ prtime.tm_year, prtime.tm_month + 1, prtime.tm_mday,
+ prtime.tm_hour, prtime.tm_min, prtime.tm_sec,
+ prtime.tm_usec / 10000, isneg ? '-' : '+',
+ offset / 60, offset % 60),
+ strRes->mValue);
+
+ *aResult = strRes;
+
+ return NS_OK;
+ }
+ default: {
+ aContext->receiveError(u"Internal error"_ns, NS_ERROR_UNEXPECTED);
+ return NS_ERROR_UNEXPECTED;
+ }
+ }
+
+ MOZ_ASSERT_UNREACHABLE("Missing return?");
+ return NS_ERROR_UNEXPECTED;
+}
+
+Expr::ResultType txEXSLTFunctionCall::getReturnType() {
+ return descriptTable[mType].mReturnType;
+}
+
+bool txEXSLTFunctionCall::isSensitiveTo(ContextSensitivity aContext) {
+ if (mType == txEXSLTType::NODE_SET || mType == txEXSLTType::SPLIT ||
+ mType == txEXSLTType::TOKENIZE) {
+ return (aContext & PRIVATE_CONTEXT) || argsSensitiveTo(aContext);
+ }
+ return argsSensitiveTo(aContext);
+}
+
+#ifdef TX_TO_STRING
+void txEXSLTFunctionCall::appendName(nsAString& aDest) {
+ aDest.Append(descriptTable[mType].mName->GetUTF16String());
+}
+#endif
+
+nsresult txEXSLTRegExFunctionCall::evaluate(txIEvalContext* aContext,
+ txAExprResult** aResult) {
+ *aResult = nullptr;
+ if (!requireParams(descriptTable[mType].mMinParams,
+ descriptTable[mType].mMaxParams, aContext)) {
+ return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
+ }
+
+ nsAutoString string;
+ nsresult rv = mParams[0]->evaluateToString(aContext, string);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString regex;
+ rv = mParams[1]->evaluateToString(aContext, regex);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString flags;
+ if (mParams.Length() >= 3) {
+ rv = mParams[2]->evaluateToString(aContext, flags);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsCOMPtr<txIEXSLTFunctions> funcs =
+ do_ImportESModule("resource://gre/modules/txEXSLTRegExFunctions.sys.mjs");
+ MOZ_ALWAYS_TRUE(funcs);
+
+ switch (mType) {
+ case txEXSLTType::MATCH: {
+ nsCOMPtr<Document> sourceDoc = getSourceDocument(aContext);
+ NS_ENSURE_STATE(sourceDoc);
+
+ RefPtr<DocumentFragment> docFrag;
+ rv = funcs->Match(string, regex, flags, sourceDoc,
+ getter_AddRefs(docFrag));
+ NS_ENSURE_SUCCESS(rv, rv);
+ NS_ENSURE_STATE(docFrag);
+
+ RefPtr<txNodeSet> resultSet;
+ rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ UniquePtr<txXPathNode> node;
+ for (nsIContent* result = docFrag->GetFirstChild(); result;
+ result = result->GetNextSibling()) {
+ node = WrapUnique(txXPathNativeNode::createXPathNode(result, true));
+ rv = resultSet->add(*node);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ resultSet.forget(aResult);
+
+ return NS_OK;
+ }
+ case txEXSLTType::REPLACE: {
+ nsAutoString replace;
+ rv = mParams[3]->evaluateToString(aContext, replace);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoString result;
+ rv = funcs->Replace(string, regex, flags, replace, result);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aContext->recycler()->getStringResult(result, aResult);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+ }
+ case txEXSLTType::TEST: {
+ bool result;
+ rv = funcs->Test(string, regex, flags, &result);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ aContext->recycler()->getBoolResult(result, aResult);
+
+ return NS_OK;
+ }
+ default: {
+ aContext->receiveError(u"Internal error"_ns, NS_ERROR_UNEXPECTED);
+ return NS_ERROR_UNEXPECTED;
+ }
+ }
+
+ MOZ_ASSERT_UNREACHABLE("Missing return?");
+ return NS_ERROR_UNEXPECTED;
+}
+
+Expr::ResultType txEXSLTRegExFunctionCall::getReturnType() {
+ return descriptTable[mType].mReturnType;
+}
+
+bool txEXSLTRegExFunctionCall::isSensitiveTo(ContextSensitivity aContext) {
+ if (mType == txEXSLTType::MATCH) {
+ return (aContext & PRIVATE_CONTEXT) || argsSensitiveTo(aContext);
+ }
+ return argsSensitiveTo(aContext);
+}
+
+#ifdef TX_TO_STRING
+void txEXSLTRegExFunctionCall::appendName(nsAString& aDest) {
+ aDest.Append(descriptTable[mType].mName->GetUTF16String());
+}
+#endif
+
+extern nsresult TX_ConstructEXSLTFunction(nsAtom* aName, int32_t aNamespaceID,
+ txStylesheetCompilerState* aState,
+ FunctionCall** aResult) {
+ for (auto i : MakeEnumeratedRange(txEXSLTType::_LIMIT)) {
+ const txEXSLTFunctionDescriptor& desc = descriptTable[i];
+ if (aName == desc.mName && aNamespaceID == desc.mNamespaceID) {
+ return desc.mCreator(i, aResult) ? NS_OK : NS_ERROR_FAILURE;
+ }
+ }
+
+ return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
+}
+
+extern bool TX_InitEXSLTFunction() {
+#define EXSLT_FUNCS(NS, CLASS, ...) \
+ { \
+ int32_t nsid = txNamespaceManager::getNamespaceID(nsLiteralString(NS)); \
+ if (nsid == kNameSpaceID_Unknown) { \
+ return false; \
+ } \
+ MOZ_FOR_EACH(EXSLT_FUNC, (nsid, CLASS, ), (__VA_ARGS__)) \
+ }
+
+#define EXSLT_FUNC(NS, CLASS, ...) \
+ descriptTable[txEXSLTType::MOZ_ARG_1 __VA_ARGS__] = { \
+ MOZ_ARGS_AFTER_1 __VA_ARGS__, CLASS::Create, NS};
+
+ EXSLT_FUNCS(u"http://exslt.org/common", txEXSLTFunctionCall,
+ (NODE_SET, 1, 1, Expr::NODESET_RESULT, nsGkAtoms::nodeSet),
+ (OBJECT_TYPE, 1, 1, Expr::STRING_RESULT, nsGkAtoms::objectType))
+
+ EXSLT_FUNCS(u"http://exslt.org/dates-and-times", txEXSLTFunctionCall,
+ (DATE_TIME, 0, 0, Expr::STRING_RESULT, nsGkAtoms::dateTime))
+
+ EXSLT_FUNCS(u"http://exslt.org/math", txEXSLTFunctionCall,
+ (MAX, 1, 1, Expr::NUMBER_RESULT, nsGkAtoms::max),
+ (MIN, 1, 1, Expr::NUMBER_RESULT, nsGkAtoms::min),
+ (HIGHEST, 1, 1, Expr::NODESET_RESULT, nsGkAtoms::highest),
+ (LOWEST, 1, 1, Expr::NODESET_RESULT, nsGkAtoms::lowest))
+
+ EXSLT_FUNCS(u"http://exslt.org/regular-expressions", txEXSLTRegExFunctionCall,
+ (MATCH, 2, 3, Expr::NODESET_RESULT, nsGkAtoms::match),
+ (REPLACE, 4, 4, Expr::STRING_RESULT, nsGkAtoms::replace),
+ (TEST, 2, 3, Expr::BOOLEAN_RESULT, nsGkAtoms::test))
+
+ EXSLT_FUNCS(
+ u"http://exslt.org/sets", txEXSLTFunctionCall,
+ (DIFFERENCE_, 2, 2, Expr::NODESET_RESULT, nsGkAtoms::difference),
+ (DISTINCT, 1, 1, Expr::NODESET_RESULT, nsGkAtoms::distinct),
+ (HAS_SAME_NODE, 2, 2, Expr::BOOLEAN_RESULT, nsGkAtoms::hasSameNode),
+ (INTERSECTION, 2, 2, Expr::NODESET_RESULT, nsGkAtoms::intersection),
+ (LEADING, 2, 2, Expr::NODESET_RESULT, nsGkAtoms::leading),
+ (TRAILING, 2, 2, Expr::NODESET_RESULT, nsGkAtoms::trailing))
+
+ EXSLT_FUNCS(u"http://exslt.org/strings", txEXSLTFunctionCall,
+ (CONCAT, 1, 1, Expr::STRING_RESULT, nsGkAtoms::concat),
+ (SPLIT, 1, 2, Expr::STRING_RESULT, nsGkAtoms::split),
+ (TOKENIZE, 1, 2, Expr::STRING_RESULT, nsGkAtoms::tokenize))
+
+#undef EXSLT_FUNCS
+#undef EXSLT_FUNC
+#undef EXSLT_FUNC_HELPER
+#undef EXSLT_FUNC_HELPER2
+
+ return true;
+}