michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsXPathExpression.h" michael@0: #include "txExpr.h" michael@0: #include "txExprResult.h" michael@0: #include "nsError.h" michael@0: #include "nsIDOMCharacterData.h" michael@0: #include "nsDOMClassInfoID.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsXPathResult.h" michael@0: #include "txURIUtils.h" michael@0: #include "txXPathTreeWalker.h" michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION(nsXPathExpression, mDocument) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPathExpression) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPathExpression) michael@0: michael@0: DOMCI_DATA(XPathExpression, nsXPathExpression) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXPathExpression) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDOMXPathExpression) michael@0: NS_INTERFACE_MAP_ENTRY(nsIDOMNSXPathExpression) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMXPathExpression) michael@0: NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XPathExpression) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: nsXPathExpression::nsXPathExpression(nsAutoPtr& aExpression, michael@0: txResultRecycler* aRecycler, michael@0: nsIDOMDocument *aDocument) michael@0: : mExpression(aExpression), michael@0: mRecycler(aRecycler), michael@0: mDocument(aDocument) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsXPathExpression::Evaluate(nsIDOMNode *aContextNode, michael@0: uint16_t aType, michael@0: nsISupports *aInResult, michael@0: nsISupports **aResult) michael@0: { michael@0: return EvaluateWithContext(aContextNode, 1, 1, aType, aInResult, aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsXPathExpression::EvaluateWithContext(nsIDOMNode *aContextNode, michael@0: uint32_t aContextPosition, michael@0: uint32_t aContextSize, michael@0: uint16_t aType, michael@0: nsISupports *aInResult, michael@0: nsISupports **aResult) michael@0: { michael@0: nsCOMPtr context = do_QueryInterface(aContextNode); michael@0: NS_ENSURE_ARG(context); michael@0: michael@0: if (aContextPosition > aContextSize) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (!nsContentUtils::CanCallerAccess(aContextNode)) michael@0: return NS_ERROR_DOM_SECURITY_ERR; michael@0: michael@0: if (mDocument && mDocument != aContextNode) { michael@0: nsCOMPtr contextDocument; michael@0: aContextNode->GetOwnerDocument(getter_AddRefs(contextDocument)); michael@0: michael@0: if (mDocument != contextDocument) { michael@0: return NS_ERROR_DOM_WRONG_DOCUMENT_ERR; michael@0: } michael@0: } michael@0: michael@0: uint16_t nodeType = context->NodeType(); michael@0: michael@0: if (nodeType == nsIDOMNode::TEXT_NODE || michael@0: nodeType == nsIDOMNode::CDATA_SECTION_NODE) { michael@0: nsCOMPtr textNode = do_QueryInterface(aContextNode); michael@0: NS_ENSURE_TRUE(textNode, NS_ERROR_FAILURE); michael@0: michael@0: if (textNode) { michael@0: uint32_t textLength; michael@0: textNode->GetLength(&textLength); michael@0: if (textLength == 0) michael@0: return NS_ERROR_DOM_NOT_SUPPORTED_ERR; michael@0: } michael@0: michael@0: // XXX Need to get logical XPath text node for CDATASection michael@0: // and Text nodes. michael@0: } michael@0: else if (nodeType != nsIDOMNode::DOCUMENT_NODE && michael@0: nodeType != nsIDOMNode::ELEMENT_NODE && michael@0: nodeType != nsIDOMNode::ATTRIBUTE_NODE && michael@0: nodeType != nsIDOMNode::COMMENT_NODE && michael@0: nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) { michael@0: return NS_ERROR_DOM_NOT_SUPPORTED_ERR; michael@0: } michael@0: michael@0: NS_ENSURE_ARG(aResult); michael@0: *aResult = nullptr; michael@0: michael@0: nsAutoPtr contextNode(txXPathNativeNode::createXPathNode(aContextNode)); michael@0: if (!contextNode) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize, michael@0: mRecycler); michael@0: nsRefPtr exprResult; michael@0: nsresult rv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: uint16_t resultType = aType; michael@0: if (aType == nsIDOMXPathResult::ANY_TYPE) { michael@0: short exprResultType = exprResult->getResultType(); michael@0: switch (exprResultType) { michael@0: case txAExprResult::NUMBER: michael@0: resultType = nsIDOMXPathResult::NUMBER_TYPE; michael@0: break; michael@0: case txAExprResult::STRING: michael@0: resultType = nsIDOMXPathResult::STRING_TYPE; michael@0: break; michael@0: case txAExprResult::BOOLEAN: michael@0: resultType = nsIDOMXPathResult::BOOLEAN_TYPE; michael@0: break; michael@0: case txAExprResult::NODESET: michael@0: resultType = nsIDOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE; michael@0: break; michael@0: case txAExprResult::RESULT_TREE_FRAGMENT: michael@0: NS_ERROR("Can't return a tree fragment!"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: // We need a result object and it must be our implementation. michael@0: nsCOMPtr xpathResult = do_QueryInterface(aInResult); michael@0: if (!xpathResult) { michael@0: // Either no aInResult or not one of ours. michael@0: xpathResult = new nsXPathResult(); michael@0: NS_ENSURE_TRUE(xpathResult, NS_ERROR_OUT_OF_MEMORY); michael@0: } michael@0: rv = xpathResult->SetExprResult(exprResult, resultType, context); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return CallQueryInterface(xpathResult, aResult); michael@0: } michael@0: michael@0: /* michael@0: * Implementation of the txIEvalContext private to nsXPathExpression michael@0: * EvalContextImpl bases on only one context node and no variables michael@0: */ michael@0: michael@0: nsresult michael@0: nsXPathExpression::EvalContextImpl::getVariable(int32_t aNamespace, michael@0: nsIAtom* aLName, michael@0: txAExprResult*& aResult) michael@0: { michael@0: aResult = 0; michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: bool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: void* nsXPathExpression::EvalContextImpl::getPrivateContext() michael@0: { michael@0: // we don't have a private context here. michael@0: return nullptr; michael@0: } michael@0: michael@0: txResultRecycler* nsXPathExpression::EvalContextImpl::recycler() michael@0: { michael@0: return mRecycler; michael@0: } michael@0: michael@0: void nsXPathExpression::EvalContextImpl::receiveError(const nsAString& aMsg, michael@0: nsresult aRes) michael@0: { michael@0: mLastError = aRes; michael@0: // forward aMsg to console service? michael@0: } michael@0: michael@0: const txXPathNode& nsXPathExpression::EvalContextImpl::getContextNode() michael@0: { michael@0: return mContextNode; michael@0: } michael@0: michael@0: uint32_t nsXPathExpression::EvalContextImpl::size() michael@0: { michael@0: return mContextSize; michael@0: } michael@0: michael@0: uint32_t nsXPathExpression::EvalContextImpl::position() michael@0: { michael@0: return mContextPosition; michael@0: }