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