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