XPathExpression.cpp (6372B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "XPathExpression.h" 7 8 #include <utility> 9 10 #include "XPathResult.h" 11 #include "mozilla/dom/BindingUtils.h" 12 #include "mozilla/dom/Text.h" 13 #include "mozilla/dom/XPathResultBinding.h" 14 #include "nsError.h" 15 #include "nsINode.h" 16 #include "txExpr.h" 17 #include "txExprResult.h" 18 #include "txIXPathContext.h" 19 #include "txURIUtils.h" 20 #include "txXPathTreeWalker.h" 21 22 namespace mozilla::dom { 23 24 class MOZ_STACK_CLASS EvalContextImpl : public txIEvalContext { 25 public: 26 EvalContextImpl(const txXPathNode& aContextNode, uint32_t aContextPosition, 27 uint32_t aContextSize, txResultRecycler* aRecycler) 28 : mContextNode(aContextNode), 29 mContextPosition(aContextPosition), 30 mContextSize(aContextSize), 31 mLastError(NS_OK), 32 mRecycler(aRecycler) {} 33 34 nsresult getError() { return mLastError; } 35 36 TX_DECL_EVAL_CONTEXT; 37 38 private: 39 const txXPathNode& mContextNode; 40 uint32_t mContextPosition; 41 uint32_t mContextSize; 42 nsresult mLastError; 43 RefPtr<txResultRecycler> mRecycler; 44 }; 45 46 XPathExpression::XPathExpression(UniquePtr<Expr>&& aExpression, 47 txResultRecycler* aRecycler, 48 Document* aDocument) 49 : mExpression(std::move(aExpression)), 50 mRecycler(aRecycler), 51 mDocument(do_GetWeakReference(aDocument)), 52 mCheckDocument(aDocument != nullptr) {} 53 54 XPathExpression::~XPathExpression() = default; 55 56 already_AddRefed<XPathResult> XPathExpression::EvaluateWithContext( 57 JSContext* aCx, nsINode& aContextNode, uint32_t aContextPosition, 58 uint32_t aContextSize, uint16_t aType, JS::Handle<JSObject*> aInResult, 59 ErrorResult& aRv) { 60 RefPtr<XPathResult> inResult; 61 if (aInResult) { 62 nsresult rv = UNWRAP_OBJECT(XPathResult, aInResult, inResult); 63 if (NS_FAILED(rv) && rv != NS_ERROR_XPC_BAD_CONVERT_JS) { 64 aRv.Throw(rv); 65 return nullptr; 66 } 67 } 68 69 return EvaluateWithContext(aContextNode, aContextPosition, aContextSize, 70 aType, inResult, aRv); 71 } 72 73 already_AddRefed<XPathResult> XPathExpression::EvaluateWithContext( 74 nsINode& aContextNode, uint32_t aContextPosition, uint32_t aContextSize, 75 uint16_t aType, XPathResult* aInResult, ErrorResult& aRv) { 76 if (aContextPosition > aContextSize) { 77 aRv.Throw(NS_ERROR_FAILURE); 78 return nullptr; 79 } 80 81 if (aType > XPathResult_Binding::FIRST_ORDERED_NODE_TYPE) { 82 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 83 return nullptr; 84 } 85 86 if (!nsContentUtils::LegacyIsCallerNativeCode() && 87 !nsContentUtils::CanCallerAccess(&aContextNode)) { 88 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); 89 return nullptr; 90 } 91 92 if (mCheckDocument) { 93 nsCOMPtr<Document> doc = do_QueryReferent(mDocument); 94 if (doc != aContextNode.OwnerDoc()) { 95 aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR); 96 return nullptr; 97 } 98 } 99 100 uint16_t nodeType = aContextNode.NodeType(); 101 102 if (nodeType == nsINode::TEXT_NODE || 103 nodeType == nsINode::CDATA_SECTION_NODE) { 104 Text* textNode = aContextNode.GetAsText(); 105 MOZ_ASSERT(textNode); 106 107 uint32_t textLength = textNode->Length(); 108 if (textLength == 0) { 109 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 110 return nullptr; 111 } 112 113 // XXX Need to get logical XPath text node for CDATASection 114 // and Text nodes. 115 } else if (nodeType != nsINode::DOCUMENT_NODE && 116 nodeType != nsINode::ELEMENT_NODE && 117 nodeType != nsINode::ATTRIBUTE_NODE && 118 nodeType != nsINode::COMMENT_NODE && 119 nodeType != nsINode::PROCESSING_INSTRUCTION_NODE) { 120 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 121 return nullptr; 122 } 123 124 Maybe<txXPathNode> contextNode = 125 txXPathNativeNode::createXPathNode(&aContextNode); 126 if (!contextNode) { 127 aRv.Throw(NS_ERROR_FAILURE); 128 return nullptr; 129 } 130 131 EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize, 132 mRecycler); 133 RefPtr<txAExprResult> exprResult; 134 aRv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult)); 135 if (aRv.Failed()) { 136 return nullptr; 137 } 138 139 uint16_t resultType = aType; 140 if (aType == XPathResult::ANY_TYPE) { 141 short exprResultType = exprResult->getResultType(); 142 switch (exprResultType) { 143 case txAExprResult::NUMBER: 144 resultType = XPathResult::NUMBER_TYPE; 145 break; 146 case txAExprResult::STRING: 147 resultType = XPathResult::STRING_TYPE; 148 break; 149 case txAExprResult::BOOLEAN: 150 resultType = XPathResult::BOOLEAN_TYPE; 151 break; 152 case txAExprResult::NODESET: 153 resultType = XPathResult::UNORDERED_NODE_ITERATOR_TYPE; 154 break; 155 case txAExprResult::RESULT_TREE_FRAGMENT: 156 aRv.Throw(NS_ERROR_FAILURE); 157 return nullptr; 158 } 159 } 160 161 RefPtr<XPathResult> xpathResult = aInResult; 162 if (!xpathResult) { 163 xpathResult = new XPathResult(&aContextNode); 164 } 165 166 xpathResult->SetExprResult(exprResult, resultType, &aContextNode, aRv); 167 if (aRv.Failed()) { 168 return nullptr; 169 } 170 171 return xpathResult.forget(); 172 } 173 174 /* 175 * Implementation of the txIEvalContext private to XPathExpression 176 * EvalContextImpl bases on only one context node and no variables 177 */ 178 179 nsresult EvalContextImpl::getVariable(int32_t aNamespace, nsAtom* aLName, 180 txAExprResult*& aResult) { 181 aResult = 0; 182 return NS_ERROR_INVALID_ARG; 183 } 184 185 nsresult EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode, 186 bool& aAllowed) { 187 aAllowed = false; 188 189 return NS_OK; 190 } 191 192 void* EvalContextImpl::getPrivateContext() { 193 // we don't have a private context here. 194 return nullptr; 195 } 196 197 txResultRecycler* EvalContextImpl::recycler() { return mRecycler; } 198 199 void EvalContextImpl::receiveError(const nsAString& aMsg, nsresult aRes) { 200 mLastError = aRes; 201 // forward aMsg to console service? 202 } 203 204 const txXPathNode& EvalContextImpl::getContextNode() { return mContextNode; } 205 206 uint32_t EvalContextImpl::size() { return mContextSize; } 207 208 uint32_t EvalContextImpl::position() { return mContextPosition; } 209 210 } // namespace mozilla::dom