/* -*- 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/dom/XPathEvaluator.h" #include #include "XPathResult.h" #include "mozilla/UniquePtrExtensions.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/XPathEvaluatorBinding.h" #include "mozilla/dom/XPathExpression.h" #include "mozilla/dom/XPathNSResolverBinding.h" #include "nsAtom.h" #include "nsCOMPtr.h" #include "nsContentCID.h" #include "nsContentUtils.h" #include "nsDOMString.h" #include "nsError.h" #include "nsNameSpaceManager.h" #include "txExpr.h" #include "txExprParser.h" #include "txIXPathContext.h" #include "txURIUtils.h" namespace mozilla::dom { // txIParseContext implementation class XPathEvaluatorParseContext : public txIParseContext { public: XPathEvaluatorParseContext(XPathNSResolver* aResolver, bool aIsCaseSensitive) : mResolver(aResolver), mResolverNode(nullptr), mLastError(NS_OK), mIsCaseSensitive(aIsCaseSensitive) {} XPathEvaluatorParseContext(nsINode* aResolver, bool aIsCaseSensitive) : mResolver(nullptr), mResolverNode(aResolver), mLastError(NS_OK), mIsCaseSensitive(aIsCaseSensitive) {} nsresult getError() { return mLastError; } nsresult resolveNamespacePrefix(nsAtom* aPrefix, int32_t& aID) override; nsresult resolveFunctionCall(nsAtom* aName, int32_t aID, FunctionCall** aFunction) override; bool caseInsensitiveNameTests() override; void SetErrorOffset(uint32_t aOffset) override; private: XPathNSResolver* mResolver; nsINode* mResolverNode; nsresult mLastError; bool mIsCaseSensitive; }; XPathEvaluator::XPathEvaluator(Document* aDocument) : mDocument(do_GetWeakReference(aDocument)) {} XPathEvaluator::~XPathEvaluator() = default; XPathExpression* XPathEvaluator::CreateExpression(const nsAString& aExpression, XPathNSResolver* aResolver, ErrorResult& aRv) { nsCOMPtr doc = do_QueryReferent(mDocument); XPathEvaluatorParseContext pContext(aResolver, !(doc && doc->IsHTMLDocument())); return CreateExpression(aExpression, &pContext, doc, aRv); } XPathExpression* XPathEvaluator::CreateExpression(const nsAString& aExpression, nsINode* aResolver, ErrorResult& aRv) { nsCOMPtr doc = do_QueryReferent(mDocument); XPathEvaluatorParseContext pContext(aResolver, !(doc && doc->IsHTMLDocument())); return CreateExpression(aExpression, &pContext, doc, aRv); } XPathExpression* XPathEvaluator::CreateExpression(const nsAString& aExpression, txIParseContext* aContext, Document* aDocument, ErrorResult& aRv) { if (!mRecycler) { mRecycler = new txResultRecycler; } UniquePtr expression; aRv = txExprParser::createExpr(PromiseFlatString(aExpression), aContext, getter_Transfers(expression)); if (aRv.Failed()) { if (!aRv.ErrorCodeIs(NS_ERROR_DOM_NAMESPACE_ERR)) { aRv.SuppressException(); aRv.ThrowSyntaxError("The expression is not a legal expression"); } return nullptr; } return new XPathExpression(std::move(expression), mRecycler, aDocument); } bool XPathEvaluator::WrapObject(JSContext* aCx, JS::Handle aGivenProto, JS::MutableHandle aReflector) { return dom::XPathEvaluator_Binding::Wrap(aCx, this, aGivenProto, aReflector); } /* static */ XPathEvaluator* XPathEvaluator::Constructor(const GlobalObject& aGlobal) { return new XPathEvaluator(nullptr); } already_AddRefed XPathEvaluator::Evaluate( JSContext* aCx, const nsAString& aExpression, nsINode& aContextNode, XPathNSResolver* aResolver, uint16_t aType, JS::Handle aResult, ErrorResult& rv) { UniquePtr expression( CreateExpression(aExpression, aResolver, rv)); if (rv.Failed()) { return nullptr; } return expression->Evaluate(aCx, aContextNode, aType, aResult, rv); } /* * Implementation of txIParseContext private to XPathEvaluator, based on a * XPathNSResolver */ nsresult XPathEvaluatorParseContext::resolveNamespacePrefix(nsAtom* aPrefix, int32_t& aID) { aID = kNameSpaceID_Unknown; if (!mResolver && !mResolverNode) { return NS_ERROR_DOM_NAMESPACE_ERR; } nsAutoString prefix; if (aPrefix) { aPrefix->ToString(prefix); } nsAutoString ns; if (mResolver) { ErrorResult rv; mResolver->LookupNamespaceURI(prefix, ns, rv); if (rv.Failed()) { return rv.StealNSResult(); } } else { if (aPrefix == nsGkAtoms::xml) { ns.AssignLiteral("http://www.w3.org/XML/1998/namespace"); } else { mResolverNode->LookupNamespaceURI(prefix, ns); } } if (DOMStringIsNull(ns)) { return NS_ERROR_DOM_NAMESPACE_ERR; } if (ns.IsEmpty()) { aID = kNameSpaceID_None; return NS_OK; } // get the namespaceID for the URI return nsNameSpaceManager::GetInstance()->RegisterNameSpace(ns, aID); } nsresult XPathEvaluatorParseContext::resolveFunctionCall(nsAtom* aName, int32_t aID, FunctionCall** aFn) { return NS_ERROR_XPATH_UNKNOWN_FUNCTION; } bool XPathEvaluatorParseContext::caseInsensitiveNameTests() { return !mIsCaseSensitive; } void XPathEvaluatorParseContext::SetErrorOffset(uint32_t aOffset) {} } // namespace mozilla::dom