1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is TransforMiiX XSLT processor code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2001
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Peter Van der Beken <peterv@propagandism.org>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsXPathEvaluator.h"
40 : #include "nsCOMPtr.h"
41 : #include "nsIAtom.h"
42 : #include "nsDOMClassInfoID.h"
43 : #include "nsXPathExpression.h"
44 : #include "nsXPathNSResolver.h"
45 : #include "nsXPathResult.h"
46 : #include "nsContentCID.h"
47 : #include "txExpr.h"
48 : #include "txExprParser.h"
49 : #include "nsDOMError.h"
50 : #include "txURIUtils.h"
51 : #include "nsIDocument.h"
52 : #include "nsIDOMDocument.h"
53 : #include "nsDOMString.h"
54 : #include "nsINameSpaceManager.h"
55 : #include "txError.h"
56 : #include "nsContentUtils.h"
57 :
58 : // txIParseContext implementation
59 : class nsXPathEvaluatorParseContext : public txIParseContext
60 84 : {
61 : public:
62 42 : nsXPathEvaluatorParseContext(nsXPathEvaluator &aEvaluator,
63 : nsIDOMXPathNSResolver* aResolver,
64 : nsTArray<PRInt32> *aNamespaceIDs,
65 : nsTArray<nsCString> *aContractIDs,
66 : nsCOMArray<nsISupports> *aState,
67 : bool aIsCaseSensitive)
68 : : mEvaluator(aEvaluator),
69 : mResolver(aResolver),
70 : mNamespaceIDs(aNamespaceIDs),
71 : mContractIDs(aContractIDs),
72 : mState(aState),
73 : mLastError(NS_OK),
74 42 : mIsCaseSensitive(aIsCaseSensitive)
75 : {
76 42 : NS_ASSERTION(mContractIDs ||
77 : (!mNamespaceIDs || mNamespaceIDs->Length() == 0),
78 : "Need contract IDs if there are namespaces.");
79 42 : }
80 :
81 : nsresult getError()
82 : {
83 : return mLastError;
84 : }
85 :
86 : nsresult resolveNamespacePrefix(nsIAtom* aPrefix, PRInt32& aID);
87 : nsresult resolveFunctionCall(nsIAtom* aName, PRInt32 aID,
88 : FunctionCall** aFunction);
89 : bool caseInsensitiveNameTests();
90 : void SetErrorOffset(PRUint32 aOffset);
91 :
92 : private:
93 : nsXPathEvaluator &mEvaluator;
94 : nsIDOMXPathNSResolver* mResolver;
95 : nsTArray<PRInt32> *mNamespaceIDs;
96 : nsTArray<nsCString> *mContractIDs;
97 : nsCOMArray<nsISupports> *mState;
98 : nsresult mLastError;
99 : bool mIsCaseSensitive;
100 : };
101 :
102 : DOMCI_DATA(XPathEvaluator, nsXPathEvaluator)
103 :
104 140 : NS_IMPL_AGGREGATED(nsXPathEvaluator)
105 46 : NS_INTERFACE_MAP_BEGIN_AGGREGATED(nsXPathEvaluator)
106 44 : NS_INTERFACE_MAP_ENTRY(nsIDOMXPathEvaluator)
107 2 : NS_INTERFACE_MAP_ENTRY(nsIXPathEvaluatorInternal)
108 2 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XPathEvaluator)
109 2 : NS_INTERFACE_MAP_END
110 :
111 2 : nsXPathEvaluator::nsXPathEvaluator(nsISupports *aOuter)
112 : {
113 2 : NS_INIT_AGGREGATED(aOuter);
114 2 : }
115 :
116 : nsresult
117 2 : nsXPathEvaluator::Init()
118 : {
119 4 : nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(fOuter);
120 :
121 2 : return document ? SetDocument(document) : NS_OK;
122 : }
123 :
124 : NS_IMETHODIMP
125 42 : nsXPathEvaluator::CreateExpression(const nsAString & aExpression,
126 : nsIDOMXPathNSResolver *aResolver,
127 : nsIDOMXPathExpression **aResult)
128 : {
129 : return CreateExpression(aExpression, aResolver, (nsTArray<PRInt32>*)nsnull,
130 42 : nsnull, nsnull, aResult);
131 : }
132 :
133 : NS_IMETHODIMP
134 0 : nsXPathEvaluator::CreateNSResolver(nsIDOMNode *aNodeResolver,
135 : nsIDOMXPathNSResolver **aResult)
136 : {
137 0 : NS_ENSURE_ARG(aNodeResolver);
138 0 : if (!nsContentUtils::CanCallerAccess(aNodeResolver))
139 0 : return NS_ERROR_DOM_SECURITY_ERR;
140 :
141 0 : *aResult = new nsXPathNSResolver(aNodeResolver);
142 0 : NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
143 :
144 0 : NS_ADDREF(*aResult);
145 0 : return NS_OK;
146 : }
147 :
148 : NS_IMETHODIMP
149 0 : nsXPathEvaluator::Evaluate(const nsAString & aExpression,
150 : nsIDOMNode *aContextNode,
151 : nsIDOMXPathNSResolver *aResolver,
152 : PRUint16 aType,
153 : nsISupports *aInResult,
154 : nsISupports **aResult)
155 : {
156 0 : nsCOMPtr<nsIDOMXPathExpression> expression;
157 : nsresult rv = CreateExpression(aExpression, aResolver,
158 0 : getter_AddRefs(expression));
159 0 : NS_ENSURE_SUCCESS(rv, rv);
160 :
161 0 : return expression->Evaluate(aContextNode, aType, aInResult, aResult);
162 : }
163 :
164 :
165 : NS_IMETHODIMP
166 2 : nsXPathEvaluator::SetDocument(nsIDOMDocument* aDocument)
167 : {
168 2 : mDocument = do_GetWeakReference(aDocument);
169 2 : return NS_OK;
170 : }
171 :
172 : NS_IMETHODIMP
173 0 : nsXPathEvaluator::CreateExpression(const nsAString & aExpression,
174 : nsIDOMXPathNSResolver *aResolver,
175 : nsTArray<nsString> *aNamespaceURIs,
176 : nsTArray<nsCString> *aContractIDs,
177 : nsCOMArray<nsISupports> *aState,
178 : nsIDOMXPathExpression **aResult)
179 : {
180 0 : nsTArray<PRInt32> namespaceIDs;
181 0 : if (aNamespaceURIs) {
182 0 : PRUint32 count = aNamespaceURIs->Length();
183 :
184 0 : if (!aContractIDs || aContractIDs->Length() != count) {
185 0 : return NS_ERROR_FAILURE;
186 : }
187 :
188 0 : if (!namespaceIDs.SetLength(count)) {
189 0 : return NS_ERROR_OUT_OF_MEMORY;
190 : }
191 :
192 : PRUint32 i;
193 0 : for (i = 0; i < count; ++i) {
194 0 : if (aContractIDs->ElementAt(i).IsEmpty()) {
195 0 : return NS_ERROR_FAILURE;
196 : }
197 :
198 0 : nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURIs->ElementAt(i), namespaceIDs[i]);
199 : }
200 : }
201 :
202 :
203 : return CreateExpression(aExpression, aResolver, &namespaceIDs, aContractIDs,
204 0 : aState, aResult);
205 : }
206 :
207 : nsresult
208 42 : nsXPathEvaluator::CreateExpression(const nsAString & aExpression,
209 : nsIDOMXPathNSResolver *aResolver,
210 : nsTArray<PRInt32> *aNamespaceIDs,
211 : nsTArray<nsCString> *aContractIDs,
212 : nsCOMArray<nsISupports> *aState,
213 : nsIDOMXPathExpression **aResult)
214 : {
215 : nsresult rv;
216 42 : if (!mRecycler) {
217 4 : nsRefPtr<txResultRecycler> recycler = new txResultRecycler;
218 2 : NS_ENSURE_TRUE(recycler, NS_ERROR_OUT_OF_MEMORY);
219 :
220 2 : rv = recycler->init();
221 2 : NS_ENSURE_SUCCESS(rv, rv);
222 :
223 4 : mRecycler = recycler;
224 : }
225 :
226 84 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
227 : nsXPathEvaluatorParseContext pContext(*this, aResolver, aNamespaceIDs,
228 : aContractIDs, aState,
229 84 : !(doc && doc->IsHTML()));
230 :
231 84 : nsAutoPtr<Expr> expression;
232 42 : rv = txExprParser::createExpr(PromiseFlatString(aExpression), &pContext,
233 42 : getter_Transfers(expression));
234 42 : if (NS_FAILED(rv)) {
235 0 : if (rv == NS_ERROR_DOM_NAMESPACE_ERR) {
236 0 : return NS_ERROR_DOM_NAMESPACE_ERR;
237 : }
238 :
239 0 : return NS_ERROR_DOM_INVALID_EXPRESSION_ERR;
240 : }
241 :
242 84 : nsCOMPtr<nsIDOMDocument> document = do_QueryReferent(mDocument);
243 :
244 84 : *aResult = new nsXPathExpression(expression, mRecycler, document);
245 42 : if (!*aResult) {
246 0 : return NS_ERROR_OUT_OF_MEMORY;
247 : }
248 :
249 42 : NS_ADDREF(*aResult);
250 42 : return NS_OK;
251 : }
252 :
253 : /*
254 : * Implementation of txIParseContext private to nsXPathEvaluator, based on a
255 : * nsIDOMXPathNSResolver
256 : */
257 :
258 0 : nsresult nsXPathEvaluatorParseContext::resolveNamespacePrefix
259 : (nsIAtom* aPrefix, PRInt32& aID)
260 : {
261 0 : aID = kNameSpaceID_Unknown;
262 :
263 0 : if (!mResolver) {
264 0 : return NS_ERROR_DOM_NAMESPACE_ERR;
265 : }
266 :
267 0 : nsAutoString prefix;
268 0 : if (aPrefix) {
269 0 : aPrefix->ToString(prefix);
270 : }
271 :
272 0 : nsVoidableString ns;
273 0 : nsresult rv = mResolver->LookupNamespaceURI(prefix, ns);
274 0 : NS_ENSURE_SUCCESS(rv, rv);
275 :
276 0 : if (DOMStringIsNull(ns)) {
277 0 : return NS_ERROR_DOM_NAMESPACE_ERR;
278 : }
279 :
280 0 : if (ns.IsEmpty()) {
281 0 : aID = kNameSpaceID_None;
282 :
283 0 : return NS_OK;
284 : }
285 :
286 : // get the namespaceID for the URI
287 0 : return nsContentUtils::NameSpaceManager()->RegisterNameSpace(ns, aID);
288 : }
289 :
290 : extern nsresult
291 : TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, PRInt32 aNamespaceID,
292 : nsIAtom *aName, nsISupports *aState,
293 : FunctionCall **aFunction);
294 :
295 : nsresult
296 0 : nsXPathEvaluatorParseContext::resolveFunctionCall(nsIAtom* aName,
297 : PRInt32 aID,
298 : FunctionCall** aFn)
299 : {
300 0 : nsresult rv = NS_ERROR_XPATH_UNKNOWN_FUNCTION;
301 :
302 0 : PRUint32 i, count = mNamespaceIDs ? mNamespaceIDs->Length() : 0;
303 0 : for (i = 0; i < count; ++i) {
304 0 : if (mNamespaceIDs->ElementAt(i) == aID) {
305 0 : nsISupports *state = mState ? mState->SafeObjectAt(i) : nsnull;
306 0 : rv = TX_ResolveFunctionCallXPCOM(mContractIDs->ElementAt(i), aID,
307 0 : aName, state, aFn);
308 0 : if (NS_SUCCEEDED(rv)) {
309 0 : break;
310 : }
311 : }
312 : }
313 :
314 0 : return rv;
315 : }
316 :
317 0 : bool nsXPathEvaluatorParseContext::caseInsensitiveNameTests()
318 : {
319 0 : return !mIsCaseSensitive;
320 : }
321 :
322 : void
323 0 : nsXPathEvaluatorParseContext::SetErrorOffset(PRUint32 aOffset)
324 : {
325 0 : }
|