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/. */
6 #include "XPathExpression.h"
10 #include "XPathResult.h"
11 #include "mozilla/dom/BindingUtils.h"
12 #include "mozilla/dom/Text.h"
13 #include "mozilla/dom/XPathResultBinding.h"
17 #include "txExprResult.h"
18 #include "txIXPathContext.h"
19 #include "txURIUtils.h"
20 #include "txXPathTreeWalker.h"
22 namespace mozilla::dom
{
24 class EvalContextImpl
: public txIEvalContext
{
26 EvalContextImpl(const txXPathNode
& aContextNode
, uint32_t aContextPosition
,
27 uint32_t aContextSize
, txResultRecycler
* aRecycler
)
28 : mContextNode(aContextNode
),
29 mContextPosition(aContextPosition
),
30 mContextSize(aContextSize
),
32 mRecycler(aRecycler
) {}
34 nsresult
getError() { return mLastError
; }
39 const txXPathNode
& mContextNode
;
40 uint32_t mContextPosition
;
41 uint32_t mContextSize
;
43 RefPtr
<txResultRecycler
> mRecycler
;
46 XPathExpression::XPathExpression(UniquePtr
<Expr
>&& aExpression
,
47 txResultRecycler
* aRecycler
,
49 : mExpression(std::move(aExpression
)),
51 mDocument(do_GetWeakReference(aDocument
)),
52 mCheckDocument(aDocument
!= nullptr) {}
54 XPathExpression::~XPathExpression() = default;
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
,
60 RefPtr
<XPathResult
> inResult
;
62 nsresult rv
= UNWRAP_OBJECT(XPathResult
, aInResult
, inResult
);
63 if (NS_FAILED(rv
) && rv
!= NS_ERROR_XPC_BAD_CONVERT_JS
) {
69 return EvaluateWithContext(aContextNode
, aContextPosition
, aContextSize
,
70 aType
, inResult
, aRv
);
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
);
81 if (aType
> XPathResult_Binding::FIRST_ORDERED_NODE_TYPE
) {
82 aRv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
86 if (!nsContentUtils::LegacyIsCallerNativeCode() &&
87 !nsContentUtils::CanCallerAccess(&aContextNode
)) {
88 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
93 nsCOMPtr
<Document
> doc
= do_QueryReferent(mDocument
);
94 if (doc
!= aContextNode
.OwnerDoc()) {
95 aRv
.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR
);
100 uint16_t nodeType
= aContextNode
.NodeType();
102 if (nodeType
== nsINode::TEXT_NODE
||
103 nodeType
== nsINode::CDATA_SECTION_NODE
) {
104 Text
* textNode
= aContextNode
.GetAsText();
105 MOZ_ASSERT(textNode
);
107 uint32_t textLength
= textNode
->Length();
108 if (textLength
== 0) {
109 aRv
.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR
);
113 // XXX Need to get logical XPath text node for CDATASection
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
);
124 UniquePtr
<txXPathNode
> contextNode(
125 txXPathNativeNode::createXPathNode(&aContextNode
));
127 aRv
.Throw(NS_ERROR_FAILURE
);
131 EvalContextImpl
eContext(*contextNode
, aContextPosition
, aContextSize
,
133 RefPtr
<txAExprResult
> exprResult
;
134 aRv
= mExpression
->evaluate(&eContext
, getter_AddRefs(exprResult
));
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
;
146 case txAExprResult::STRING
:
147 resultType
= XPathResult::STRING_TYPE
;
149 case txAExprResult::BOOLEAN
:
150 resultType
= XPathResult::BOOLEAN_TYPE
;
152 case txAExprResult::NODESET
:
153 resultType
= XPathResult::UNORDERED_NODE_ITERATOR_TYPE
;
155 case txAExprResult::RESULT_TREE_FRAGMENT
:
156 aRv
.Throw(NS_ERROR_FAILURE
);
161 RefPtr
<XPathResult
> xpathResult
= aInResult
;
163 xpathResult
= new XPathResult(&aContextNode
);
166 xpathResult
->SetExprResult(exprResult
, resultType
, &aContextNode
, aRv
);
171 return xpathResult
.forget();
175 * Implementation of the txIEvalContext private to XPathExpression
176 * EvalContextImpl bases on only one context node and no variables
179 nsresult
EvalContextImpl::getVariable(int32_t aNamespace
, nsAtom
* aLName
,
180 txAExprResult
*& aResult
) {
182 return NS_ERROR_INVALID_ARG
;
185 nsresult
EvalContextImpl::isStripSpaceAllowed(const txXPathNode
& aNode
,
192 void* EvalContextImpl::getPrivateContext() {
193 // we don't have a private context here.
197 txResultRecycler
* EvalContextImpl::recycler() { return mRecycler
; }
199 void EvalContextImpl::receiveError(const nsAString
& aMsg
, nsresult aRes
) {
201 // forward aMsg to console service?
204 const txXPathNode
& EvalContextImpl::getContextNode() { return mContextNode
; }
206 uint32_t EvalContextImpl::size() { return mContextSize
; }
208 uint32_t EvalContextImpl::position() { return mContextPosition
; }
210 } // namespace mozilla::dom