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/dom/XPathEvaluator.h"
7 : #include "mozilla/Move.h"
8 : #include "nsCOMPtr.h"
9 : #include "nsIAtom.h"
10 : #include "mozilla/dom/XPathExpression.h"
11 : #include "XPathResult.h"
12 : #include "nsContentCID.h"
13 : #include "txExpr.h"
14 : #include "txExprParser.h"
15 : #include "nsError.h"
16 : #include "txURIUtils.h"
17 : #include "nsIDocument.h"
18 : #include "nsIDOMDocument.h"
19 : #include "nsDOMString.h"
20 : #include "nsNameSpaceManager.h"
21 : #include "nsContentUtils.h"
22 : #include "txIXPathContext.h"
23 : #include "mozilla/dom/XPathEvaluatorBinding.h"
24 : #include "mozilla/dom/BindingUtils.h"
25 : #include "mozilla/dom/XPathNSResolverBinding.h"
26 :
27 : extern nsresult
28 : TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID,
29 : nsIAtom *aName, nsISupports *aState,
30 : FunctionCall **aFunction);
31 :
32 : namespace mozilla {
33 : namespace dom {
34 :
35 : // txIParseContext implementation
36 0 : class XPathEvaluatorParseContext : public txIParseContext
37 : {
38 : public:
39 0 : XPathEvaluatorParseContext(XPathNSResolver* aResolver,
40 : bool aIsCaseSensitive)
41 0 : : mResolver(aResolver),
42 : mResolverNode(nullptr),
43 : mLastError(NS_OK),
44 0 : mIsCaseSensitive(aIsCaseSensitive)
45 : {
46 0 : }
47 0 : XPathEvaluatorParseContext(nsINode* aResolver,
48 : bool aIsCaseSensitive)
49 0 : : mResolver(nullptr),
50 : mResolverNode(aResolver),
51 : mLastError(NS_OK),
52 0 : mIsCaseSensitive(aIsCaseSensitive)
53 : {
54 0 : }
55 :
56 : nsresult getError()
57 : {
58 : return mLastError;
59 : }
60 :
61 : nsresult resolveNamespacePrefix(nsIAtom* aPrefix, int32_t& aID);
62 : nsresult resolveFunctionCall(nsIAtom* aName, int32_t aID,
63 : FunctionCall** aFunction);
64 : bool caseInsensitiveNameTests();
65 : void SetErrorOffset(uint32_t aOffset);
66 :
67 : private:
68 : XPathNSResolver* mResolver;
69 : nsINode* mResolverNode;
70 : nsresult mLastError;
71 : bool mIsCaseSensitive;
72 : };
73 :
74 0 : NS_IMPL_ISUPPORTS(XPathEvaluator, nsIDOMXPathEvaluator)
75 :
76 0 : XPathEvaluator::XPathEvaluator(nsIDocument* aDocument)
77 0 : : mDocument(do_GetWeakReference(aDocument))
78 : {
79 0 : }
80 :
81 0 : XPathEvaluator::~XPathEvaluator()
82 : {
83 0 : }
84 :
85 : NS_IMETHODIMP
86 0 : XPathEvaluator::Evaluate(const nsAString & aExpression,
87 : nsIDOMNode *aContextNode,
88 : nsIDOMNode *aResolver,
89 : uint16_t aType,
90 : nsISupports *aInResult,
91 : nsISupports **aResult)
92 : {
93 0 : nsCOMPtr<nsINode> resolver = do_QueryInterface(aResolver);
94 0 : ErrorResult rv;
95 : nsAutoPtr<XPathExpression> expression(CreateExpression(aExpression,
96 0 : resolver, rv));
97 0 : if (rv.Failed()) {
98 0 : return rv.StealNSResult();
99 : }
100 :
101 0 : nsCOMPtr<nsINode> node = do_QueryInterface(aContextNode);
102 0 : if (!node) {
103 0 : return NS_ERROR_FAILURE;
104 : }
105 :
106 0 : nsCOMPtr<nsIXPathResult> inResult = do_QueryInterface(aInResult);
107 : RefPtr<XPathResult> result =
108 0 : expression->Evaluate(*node, aType,
109 0 : static_cast<XPathResult*>(inResult.get()), rv);
110 0 : if (rv.Failed()) {
111 0 : return rv.StealNSResult();
112 : }
113 :
114 0 : *aResult = ToSupports(result.forget().take());
115 :
116 0 : return NS_OK;
117 : }
118 :
119 : XPathExpression*
120 0 : XPathEvaluator::CreateExpression(const nsAString& aExpression,
121 : XPathNSResolver* aResolver, ErrorResult& aRv)
122 : {
123 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
124 : XPathEvaluatorParseContext pContext(aResolver,
125 0 : !(doc && doc->IsHTMLDocument()));
126 0 : return CreateExpression(aExpression, &pContext, doc, aRv);
127 : }
128 :
129 : XPathExpression*
130 0 : XPathEvaluator::CreateExpression(const nsAString& aExpression,
131 : nsINode* aResolver, ErrorResult& aRv)
132 : {
133 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
134 : XPathEvaluatorParseContext pContext(aResolver,
135 0 : !(doc && doc->IsHTMLDocument()));
136 0 : return CreateExpression(aExpression, &pContext, doc, aRv);
137 : }
138 :
139 : XPathExpression*
140 0 : XPathEvaluator::CreateExpression(const nsAString & aExpression,
141 : txIParseContext* aContext,
142 : nsIDocument* aDocument,
143 : ErrorResult& aRv)
144 : {
145 0 : if (!mRecycler) {
146 0 : mRecycler = new txResultRecycler;
147 : }
148 :
149 0 : nsAutoPtr<Expr> expression;
150 0 : aRv = txExprParser::createExpr(PromiseFlatString(aExpression), aContext,
151 0 : getter_Transfers(expression));
152 0 : if (aRv.Failed()) {
153 0 : if (!aRv.ErrorCodeIs(NS_ERROR_DOM_NAMESPACE_ERR)) {
154 0 : aRv.SuppressException();
155 0 : aRv.Throw(NS_ERROR_DOM_INVALID_EXPRESSION_ERR);
156 : }
157 :
158 0 : return nullptr;
159 : }
160 :
161 0 : return new XPathExpression(Move(expression), mRecycler, aDocument);
162 : }
163 :
164 : bool
165 0 : XPathEvaluator::WrapObject(JSContext* aCx,
166 : JS::Handle<JSObject*> aGivenProto,
167 : JS::MutableHandle<JSObject*> aReflector)
168 : {
169 0 : return dom::XPathEvaluatorBinding::Wrap(aCx, this, aGivenProto, aReflector);
170 : }
171 :
172 : /* static */
173 : already_AddRefed<XPathEvaluator>
174 0 : XPathEvaluator::Constructor(const GlobalObject& aGlobal,
175 : ErrorResult& rv)
176 : {
177 0 : RefPtr<XPathEvaluator> newObj = new XPathEvaluator(nullptr);
178 0 : return newObj.forget();
179 : }
180 :
181 : already_AddRefed<XPathResult>
182 0 : XPathEvaluator::Evaluate(JSContext* aCx, const nsAString& aExpression,
183 : nsINode& aContextNode, XPathNSResolver* aResolver,
184 : uint16_t aType, JS::Handle<JSObject*> aResult,
185 : ErrorResult& rv)
186 : {
187 : nsAutoPtr<XPathExpression> expression(CreateExpression(aExpression,
188 0 : aResolver, rv));
189 0 : if (rv.Failed()) {
190 0 : return nullptr;
191 : }
192 0 : return expression->Evaluate(aCx, aContextNode, aType, aResult, rv);
193 : }
194 :
195 :
196 : /*
197 : * Implementation of txIParseContext private to XPathEvaluator, based on a
198 : * XPathNSResolver
199 : */
200 :
201 0 : nsresult XPathEvaluatorParseContext::resolveNamespacePrefix
202 : (nsIAtom* aPrefix, int32_t& aID)
203 : {
204 0 : aID = kNameSpaceID_Unknown;
205 :
206 0 : if (!mResolver && !mResolverNode) {
207 0 : return NS_ERROR_DOM_NAMESPACE_ERR;
208 : }
209 :
210 0 : nsAutoString prefix;
211 0 : if (aPrefix) {
212 0 : aPrefix->ToString(prefix);
213 : }
214 :
215 0 : nsVoidableString ns;
216 0 : if (mResolver) {
217 0 : ErrorResult rv;
218 0 : mResolver->LookupNamespaceURI(prefix, ns, rv);
219 0 : if (rv.Failed()) {
220 0 : return rv.StealNSResult();
221 : }
222 : } else {
223 0 : if (aPrefix == nsGkAtoms::xml) {
224 0 : ns.AssignLiteral("http://www.w3.org/XML/1998/namespace");
225 : } else {
226 0 : mResolverNode->LookupNamespaceURI(prefix, ns);
227 : }
228 : }
229 :
230 0 : if (DOMStringIsNull(ns)) {
231 0 : return NS_ERROR_DOM_NAMESPACE_ERR;
232 : }
233 :
234 0 : if (ns.IsEmpty()) {
235 0 : aID = kNameSpaceID_None;
236 :
237 0 : return NS_OK;
238 : }
239 :
240 : // get the namespaceID for the URI
241 0 : return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID);
242 : }
243 :
244 : nsresult
245 0 : XPathEvaluatorParseContext::resolveFunctionCall(nsIAtom* aName,
246 : int32_t aID,
247 : FunctionCall** aFn)
248 : {
249 0 : return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
250 : }
251 :
252 0 : bool XPathEvaluatorParseContext::caseInsensitiveNameTests()
253 : {
254 0 : return !mIsCaseSensitive;
255 : }
256 :
257 : void
258 0 : XPathEvaluatorParseContext::SetErrorOffset(uint32_t aOffset)
259 : {
260 0 : }
261 :
262 : } // namespace dom
263 : } // namespace mozilla
|