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/ArrayUtils.h"
7 : #include "mozilla/FloatingPoint.h"
8 :
9 : #include "txExpr.h"
10 : #include "nsAutoPtr.h"
11 : #include "txNodeSet.h"
12 : #include "nsGkAtoms.h"
13 : #include "txIXPathContext.h"
14 : #include "nsWhitespaceTokenizer.h"
15 : #include "txXPathTreeWalker.h"
16 : #include <math.h>
17 : #include "txStringUtils.h"
18 : #include "txXMLUtils.h"
19 :
20 : using namespace mozilla;
21 :
22 : struct txCoreFunctionDescriptor
23 : {
24 : int8_t mMinParams;
25 : int8_t mMaxParams;
26 : Expr::ResultType mReturnType;
27 : nsIAtom** mName;
28 : };
29 :
30 : // This must be ordered in the same order as txCoreFunctionCall::eType.
31 : // If you change one, change the other.
32 : static const txCoreFunctionDescriptor descriptTable[] =
33 : {
34 : { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::count }, // COUNT
35 : { 1, 1, Expr::NODESET_RESULT, &nsGkAtoms::id }, // ID
36 : { 0, 0, Expr::NUMBER_RESULT, &nsGkAtoms::last }, // LAST
37 : { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::localName }, // LOCAL_NAME
38 : { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::namespaceUri }, // NAMESPACE_URI
39 : { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::name }, // NAME
40 : { 0, 0, Expr::NUMBER_RESULT, &nsGkAtoms::position }, // POSITION
41 :
42 : { 2, -1, Expr::STRING_RESULT, &nsGkAtoms::concat }, // CONCAT
43 : { 2, 2, Expr::BOOLEAN_RESULT, &nsGkAtoms::contains }, // CONTAINS
44 : { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::normalizeSpace }, // NORMALIZE_SPACE
45 : { 2, 2, Expr::BOOLEAN_RESULT, &nsGkAtoms::startsWith }, // STARTS_WITH
46 : { 0, 1, Expr::STRING_RESULT, &nsGkAtoms::string }, // STRING
47 : { 0, 1, Expr::NUMBER_RESULT, &nsGkAtoms::stringLength }, // STRING_LENGTH
48 : { 2, 3, Expr::STRING_RESULT, &nsGkAtoms::substring }, // SUBSTRING
49 : { 2, 2, Expr::STRING_RESULT, &nsGkAtoms::substringAfter }, // SUBSTRING_AFTER
50 : { 2, 2, Expr::STRING_RESULT, &nsGkAtoms::substringBefore }, // SUBSTRING_BEFORE
51 : { 3, 3, Expr::STRING_RESULT, &nsGkAtoms::translate }, // TRANSLATE
52 :
53 : { 0, 1, Expr::NUMBER_RESULT, &nsGkAtoms::number }, // NUMBER
54 : { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::round }, // ROUND
55 : { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::floor }, // FLOOR
56 : { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::ceiling }, // CEILING
57 : { 1, 1, Expr::NUMBER_RESULT, &nsGkAtoms::sum }, // SUM
58 :
59 : { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::boolean }, // BOOLEAN
60 : { 0, 0, Expr::BOOLEAN_RESULT, &nsGkAtoms::_false }, // _FALSE
61 : { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::lang }, // LANG
62 : { 1, 1, Expr::BOOLEAN_RESULT, &nsGkAtoms::_not }, // _NOT
63 : { 0, 0, Expr::BOOLEAN_RESULT, &nsGkAtoms::_true } // _TRUE
64 : };
65 :
66 :
67 : /*
68 : * Evaluates this Expr based on the given context node and processor state
69 : * @param context the context node for evaluation of this Expr
70 : * @param ps the ContextState containing the stack information needed
71 : * for evaluation
72 : * @return the result of the evaluation
73 : */
74 : nsresult
75 0 : txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
76 : {
77 0 : *aResult = nullptr;
78 :
79 0 : if (!requireParams(descriptTable[mType].mMinParams,
80 0 : descriptTable[mType].mMaxParams,
81 0 : aContext)) {
82 0 : return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
83 : }
84 :
85 0 : nsresult rv = NS_OK;
86 0 : switch (mType) {
87 : case COUNT:
88 : {
89 0 : RefPtr<txNodeSet> nodes;
90 0 : rv = evaluateToNodeSet(mParams[0], aContext,
91 0 : getter_AddRefs(nodes));
92 0 : NS_ENSURE_SUCCESS(rv, rv);
93 :
94 0 : return aContext->recycler()->getNumberResult(nodes->size(),
95 0 : aResult);
96 : }
97 : case ID:
98 : {
99 0 : RefPtr<txAExprResult> exprResult;
100 0 : rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
101 0 : NS_ENSURE_SUCCESS(rv, rv);
102 :
103 0 : RefPtr<txNodeSet> resultSet;
104 0 : rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
105 0 : NS_ENSURE_SUCCESS(rv, rv);
106 :
107 0 : txXPathTreeWalker walker(aContext->getContextNode());
108 :
109 0 : if (exprResult->getResultType() == txAExprResult::NODESET) {
110 : txNodeSet* nodes = static_cast<txNodeSet*>
111 : (static_cast<txAExprResult*>
112 0 : (exprResult));
113 : int32_t i;
114 0 : for (i = 0; i < nodes->size(); ++i) {
115 0 : nsAutoString idList;
116 0 : txXPathNodeUtils::appendNodeValue(nodes->get(i), idList);
117 0 : nsWhitespaceTokenizer tokenizer(idList);
118 0 : while (tokenizer.hasMoreTokens()) {
119 0 : if (walker.moveToElementById(tokenizer.nextToken())) {
120 0 : resultSet->add(walker.getCurrentPosition());
121 : }
122 : }
123 : }
124 : }
125 : else {
126 0 : nsAutoString idList;
127 0 : exprResult->stringValue(idList);
128 0 : nsWhitespaceTokenizer tokenizer(idList);
129 0 : while (tokenizer.hasMoreTokens()) {
130 0 : if (walker.moveToElementById(tokenizer.nextToken())) {
131 0 : resultSet->add(walker.getCurrentPosition());
132 : }
133 : }
134 : }
135 :
136 0 : *aResult = resultSet;
137 0 : NS_ADDREF(*aResult);
138 :
139 0 : return NS_OK;
140 : }
141 : case LAST:
142 : {
143 0 : return aContext->recycler()->getNumberResult(aContext->size(),
144 0 : aResult);
145 : }
146 : case LOCAL_NAME:
147 : case NAME:
148 : case NAMESPACE_URI:
149 : {
150 : // Check for optional arg
151 0 : RefPtr<txNodeSet> nodes;
152 0 : if (!mParams.IsEmpty()) {
153 0 : rv = evaluateToNodeSet(mParams[0], aContext,
154 0 : getter_AddRefs(nodes));
155 0 : NS_ENSURE_SUCCESS(rv, rv);
156 :
157 0 : if (nodes->isEmpty()) {
158 0 : aContext->recycler()->getEmptyStringResult(aResult);
159 :
160 0 : return NS_OK;
161 : }
162 : }
163 :
164 0 : const txXPathNode& node = nodes ? nodes->get(0) :
165 0 : aContext->getContextNode();
166 0 : switch (mType) {
167 : case LOCAL_NAME:
168 : {
169 0 : StringResult* strRes = nullptr;
170 0 : rv = aContext->recycler()->getStringResult(&strRes);
171 0 : NS_ENSURE_SUCCESS(rv, rv);
172 :
173 0 : *aResult = strRes;
174 0 : txXPathNodeUtils::getLocalName(node, strRes->mValue);
175 :
176 0 : return NS_OK;
177 : }
178 : case NAMESPACE_URI:
179 : {
180 0 : StringResult* strRes = nullptr;
181 0 : rv = aContext->recycler()->getStringResult(&strRes);
182 0 : NS_ENSURE_SUCCESS(rv, rv);
183 :
184 0 : *aResult = strRes;
185 0 : txXPathNodeUtils::getNamespaceURI(node, strRes->mValue);
186 :
187 0 : return NS_OK;
188 : }
189 : case NAME:
190 : {
191 : // XXX Namespace: namespaces have a name
192 0 : if (txXPathNodeUtils::isAttribute(node) ||
193 0 : txXPathNodeUtils::isElement(node) ||
194 0 : txXPathNodeUtils::isProcessingInstruction(node)) {
195 0 : StringResult* strRes = nullptr;
196 0 : rv = aContext->recycler()->getStringResult(&strRes);
197 0 : NS_ENSURE_SUCCESS(rv, rv);
198 :
199 0 : *aResult = strRes;
200 0 : txXPathNodeUtils::getNodeName(node, strRes->mValue);
201 : }
202 : else {
203 0 : aContext->recycler()->getEmptyStringResult(aResult);
204 : }
205 :
206 0 : return NS_OK;
207 : }
208 : default:
209 : {
210 0 : MOZ_CRASH("Unexpected mType?!");
211 : }
212 : }
213 : MOZ_CRASH("Inner mType switch should have returned!");
214 : }
215 : case POSITION:
216 : {
217 0 : return aContext->recycler()->getNumberResult(aContext->position(),
218 0 : aResult);
219 : }
220 :
221 : // String functions
222 :
223 : case CONCAT:
224 : {
225 0 : RefPtr<StringResult> strRes;
226 0 : rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
227 0 : NS_ENSURE_SUCCESS(rv, rv);
228 :
229 0 : uint32_t i, len = mParams.Length();
230 0 : for (i = 0; i < len; ++i) {
231 0 : rv = mParams[i]->evaluateToString(aContext, strRes->mValue);
232 0 : NS_ENSURE_SUCCESS(rv, rv);
233 : }
234 :
235 0 : NS_ADDREF(*aResult = strRes);
236 :
237 0 : return NS_OK;
238 : }
239 : case CONTAINS:
240 : {
241 0 : nsAutoString arg2;
242 0 : rv = mParams[1]->evaluateToString(aContext, arg2);
243 0 : NS_ENSURE_SUCCESS(rv, rv);
244 :
245 0 : if (arg2.IsEmpty()) {
246 0 : aContext->recycler()->getBoolResult(true, aResult);
247 : }
248 : else {
249 0 : nsAutoString arg1;
250 0 : rv = mParams[0]->evaluateToString(aContext, arg1);
251 0 : NS_ENSURE_SUCCESS(rv, rv);
252 :
253 0 : aContext->recycler()->getBoolResult(FindInReadable(arg2, arg1),
254 0 : aResult);
255 : }
256 :
257 0 : return NS_OK;
258 : }
259 : case NORMALIZE_SPACE:
260 : {
261 0 : nsAutoString resultStr;
262 0 : if (!mParams.IsEmpty()) {
263 0 : rv = mParams[0]->evaluateToString(aContext, resultStr);
264 0 : NS_ENSURE_SUCCESS(rv, rv);
265 : }
266 : else {
267 0 : txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
268 0 : resultStr);
269 : }
270 :
271 0 : RefPtr<StringResult> strRes;
272 0 : rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
273 0 : NS_ENSURE_SUCCESS(rv, rv);
274 :
275 0 : bool addSpace = false;
276 0 : bool first = true;
277 0 : strRes->mValue.SetCapacity(resultStr.Length());
278 : char16_t c;
279 : uint32_t src;
280 0 : for (src = 0; src < resultStr.Length(); src++) {
281 0 : c = resultStr.CharAt(src);
282 0 : if (XMLUtils::isWhitespace(c)) {
283 0 : addSpace = true;
284 : }
285 : else {
286 0 : if (addSpace && !first)
287 0 : strRes->mValue.Append(char16_t(' '));
288 :
289 0 : strRes->mValue.Append(c);
290 0 : addSpace = false;
291 0 : first = false;
292 : }
293 : }
294 0 : *aResult = strRes;
295 0 : NS_ADDREF(*aResult);
296 :
297 0 : return NS_OK;
298 : }
299 : case STARTS_WITH:
300 : {
301 0 : nsAutoString arg2;
302 0 : rv = mParams[1]->evaluateToString(aContext, arg2);
303 0 : NS_ENSURE_SUCCESS(rv, rv);
304 :
305 0 : bool result = false;
306 0 : if (arg2.IsEmpty()) {
307 0 : result = true;
308 : }
309 : else {
310 0 : nsAutoString arg1;
311 0 : rv = mParams[0]->evaluateToString(aContext, arg1);
312 0 : NS_ENSURE_SUCCESS(rv, rv);
313 :
314 0 : result = StringBeginsWith(arg1, arg2);
315 : }
316 :
317 0 : aContext->recycler()->getBoolResult(result, aResult);
318 :
319 0 : return NS_OK;
320 : }
321 : case STRING:
322 : {
323 0 : RefPtr<StringResult> strRes;
324 0 : rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
325 0 : NS_ENSURE_SUCCESS(rv, rv);
326 :
327 0 : if (!mParams.IsEmpty()) {
328 0 : rv = mParams[0]->evaluateToString(aContext, strRes->mValue);
329 0 : NS_ENSURE_SUCCESS(rv, rv);
330 : }
331 : else {
332 0 : txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
333 0 : strRes->mValue);
334 : }
335 :
336 0 : NS_ADDREF(*aResult = strRes);
337 :
338 0 : return NS_OK;
339 : }
340 : case STRING_LENGTH:
341 : {
342 0 : nsAutoString resultStr;
343 0 : if (!mParams.IsEmpty()) {
344 0 : rv = mParams[0]->evaluateToString(aContext, resultStr);
345 0 : NS_ENSURE_SUCCESS(rv, rv);
346 : }
347 : else {
348 0 : txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
349 0 : resultStr);
350 : }
351 0 : rv = aContext->recycler()->getNumberResult(resultStr.Length(),
352 0 : aResult);
353 0 : NS_ENSURE_SUCCESS(rv, rv);
354 :
355 0 : return NS_OK;
356 : }
357 : case SUBSTRING:
358 : {
359 0 : nsAutoString src;
360 0 : rv = mParams[0]->evaluateToString(aContext, src);
361 0 : NS_ENSURE_SUCCESS(rv, rv);
362 :
363 : double start;
364 0 : rv = evaluateToNumber(mParams[1], aContext, &start);
365 0 : NS_ENSURE_SUCCESS(rv, rv);
366 :
367 : // check for NaN or +/-Inf
368 0 : if (mozilla::IsNaN(start) ||
369 0 : mozilla::IsInfinite(start) ||
370 0 : start >= src.Length() + 0.5) {
371 0 : aContext->recycler()->getEmptyStringResult(aResult);
372 :
373 0 : return NS_OK;
374 : }
375 :
376 0 : start = floor(start + 0.5) - 1;
377 :
378 : double end;
379 0 : if (mParams.Length() == 3) {
380 0 : rv = evaluateToNumber(mParams[2], aContext, &end);
381 0 : NS_ENSURE_SUCCESS(rv, rv);
382 :
383 0 : end += start;
384 0 : if (mozilla::IsNaN(end) || end < 0) {
385 0 : aContext->recycler()->getEmptyStringResult(aResult);
386 :
387 0 : return NS_OK;
388 : }
389 :
390 0 : if (end > src.Length())
391 0 : end = src.Length();
392 : else
393 0 : end = floor(end + 0.5);
394 : }
395 : else {
396 0 : end = src.Length();
397 : }
398 :
399 0 : if (start < 0)
400 0 : start = 0;
401 :
402 0 : if (start > end) {
403 0 : aContext->recycler()->getEmptyStringResult(aResult);
404 :
405 0 : return NS_OK;
406 : }
407 :
408 0 : return aContext->recycler()->getStringResult(
409 0 : Substring(src, (uint32_t)start, (uint32_t)(end - start)),
410 0 : aResult);
411 : }
412 : case SUBSTRING_AFTER:
413 : {
414 0 : nsAutoString arg1;
415 0 : rv = mParams[0]->evaluateToString(aContext, arg1);
416 0 : NS_ENSURE_SUCCESS(rv, rv);
417 :
418 0 : nsAutoString arg2;
419 0 : rv = mParams[1]->evaluateToString(aContext, arg2);
420 0 : NS_ENSURE_SUCCESS(rv, rv);
421 :
422 0 : if (arg2.IsEmpty()) {
423 0 : return aContext->recycler()->getStringResult(arg1, aResult);
424 : }
425 :
426 0 : int32_t idx = arg1.Find(arg2);
427 0 : if (idx == kNotFound) {
428 0 : aContext->recycler()->getEmptyStringResult(aResult);
429 :
430 0 : return NS_OK;
431 : }
432 :
433 0 : const nsAString& result = Substring(arg1, idx + arg2.Length());
434 0 : return aContext->recycler()->getStringResult(result, aResult);
435 : }
436 : case SUBSTRING_BEFORE:
437 : {
438 0 : nsAutoString arg2;
439 0 : rv = mParams[1]->evaluateToString(aContext, arg2);
440 0 : NS_ENSURE_SUCCESS(rv, rv);
441 :
442 0 : if (arg2.IsEmpty()) {
443 0 : aContext->recycler()->getEmptyStringResult(aResult);
444 :
445 0 : return NS_OK;
446 : }
447 :
448 0 : nsAutoString arg1;
449 0 : rv = mParams[0]->evaluateToString(aContext, arg1);
450 0 : NS_ENSURE_SUCCESS(rv, rv);
451 :
452 0 : int32_t idx = arg1.Find(arg2);
453 0 : if (idx == kNotFound) {
454 0 : aContext->recycler()->getEmptyStringResult(aResult);
455 :
456 0 : return NS_OK;
457 : }
458 :
459 0 : return aContext->recycler()->getStringResult(StringHead(arg1, idx),
460 0 : aResult);
461 : }
462 : case TRANSLATE:
463 : {
464 0 : nsAutoString src;
465 0 : rv = mParams[0]->evaluateToString(aContext, src);
466 0 : NS_ENSURE_SUCCESS(rv, rv);
467 :
468 0 : if (src.IsEmpty()) {
469 0 : aContext->recycler()->getEmptyStringResult(aResult);
470 :
471 0 : return NS_OK;
472 : }
473 :
474 0 : RefPtr<StringResult> strRes;
475 0 : rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
476 0 : NS_ENSURE_SUCCESS(rv, rv);
477 :
478 0 : strRes->mValue.SetCapacity(src.Length());
479 :
480 0 : nsAutoString oldChars, newChars;
481 0 : rv = mParams[1]->evaluateToString(aContext, oldChars);
482 0 : NS_ENSURE_SUCCESS(rv, rv);
483 :
484 0 : rv = mParams[2]->evaluateToString(aContext, newChars);
485 0 : NS_ENSURE_SUCCESS(rv, rv);
486 :
487 : uint32_t i;
488 0 : int32_t newCharsLength = (int32_t)newChars.Length();
489 0 : for (i = 0; i < src.Length(); i++) {
490 0 : int32_t idx = oldChars.FindChar(src.CharAt(i));
491 0 : if (idx != kNotFound) {
492 0 : if (idx < newCharsLength)
493 0 : strRes->mValue.Append(newChars.CharAt((uint32_t)idx));
494 : }
495 : else {
496 0 : strRes->mValue.Append(src.CharAt(i));
497 : }
498 : }
499 :
500 0 : NS_ADDREF(*aResult = strRes);
501 :
502 0 : return NS_OK;
503 : }
504 :
505 : // Number functions
506 :
507 : case NUMBER:
508 : {
509 : double res;
510 0 : if (!mParams.IsEmpty()) {
511 0 : rv = evaluateToNumber(mParams[0], aContext, &res);
512 0 : NS_ENSURE_SUCCESS(rv, rv);
513 : }
514 : else {
515 0 : nsAutoString resultStr;
516 0 : txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
517 0 : resultStr);
518 0 : res = txDouble::toDouble(resultStr);
519 : }
520 0 : return aContext->recycler()->getNumberResult(res, aResult);
521 : }
522 : case ROUND:
523 : {
524 : double dbl;
525 0 : rv = evaluateToNumber(mParams[0], aContext, &dbl);
526 0 : NS_ENSURE_SUCCESS(rv, rv);
527 :
528 0 : if (mozilla::IsFinite(dbl)) {
529 0 : if (mozilla::IsNegative(dbl) && dbl >= -0.5) {
530 0 : dbl *= 0;
531 : }
532 : else {
533 0 : dbl = floor(dbl + 0.5);
534 : }
535 : }
536 :
537 0 : return aContext->recycler()->getNumberResult(dbl, aResult);
538 : }
539 : case FLOOR:
540 : {
541 : double dbl;
542 0 : rv = evaluateToNumber(mParams[0], aContext, &dbl);
543 0 : NS_ENSURE_SUCCESS(rv, rv);
544 :
545 0 : if (mozilla::IsFinite(dbl) && !mozilla::IsNegativeZero(dbl))
546 0 : dbl = floor(dbl);
547 :
548 0 : return aContext->recycler()->getNumberResult(dbl, aResult);
549 : }
550 : case CEILING:
551 : {
552 : double dbl;
553 0 : rv = evaluateToNumber(mParams[0], aContext, &dbl);
554 0 : NS_ENSURE_SUCCESS(rv, rv);
555 :
556 0 : if (mozilla::IsFinite(dbl)) {
557 0 : if (mozilla::IsNegative(dbl) && dbl > -1)
558 0 : dbl *= 0;
559 : else
560 0 : dbl = ceil(dbl);
561 : }
562 :
563 0 : return aContext->recycler()->getNumberResult(dbl, aResult);
564 : }
565 : case SUM:
566 : {
567 0 : RefPtr<txNodeSet> nodes;
568 0 : nsresult rv = evaluateToNodeSet(mParams[0], aContext,
569 0 : getter_AddRefs(nodes));
570 0 : NS_ENSURE_SUCCESS(rv, rv);
571 :
572 0 : double res = 0;
573 : int32_t i;
574 0 : for (i = 0; i < nodes->size(); ++i) {
575 0 : nsAutoString resultStr;
576 0 : txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
577 0 : res += txDouble::toDouble(resultStr);
578 : }
579 0 : return aContext->recycler()->getNumberResult(res, aResult);
580 : }
581 :
582 : // Boolean functions
583 :
584 : case BOOLEAN:
585 : {
586 : bool result;
587 0 : nsresult rv = mParams[0]->evaluateToBool(aContext, result);
588 0 : NS_ENSURE_SUCCESS(rv, rv);
589 :
590 0 : aContext->recycler()->getBoolResult(result, aResult);
591 :
592 0 : return NS_OK;
593 : }
594 : case _FALSE:
595 : {
596 0 : aContext->recycler()->getBoolResult(false, aResult);
597 :
598 0 : return NS_OK;
599 : }
600 : case LANG:
601 : {
602 0 : txXPathTreeWalker walker(aContext->getContextNode());
603 :
604 0 : nsAutoString lang;
605 : bool found;
606 0 : do {
607 0 : found = walker.getAttr(nsGkAtoms::lang, kNameSpaceID_XML,
608 0 : lang);
609 0 : } while (!found && walker.moveToParent());
610 :
611 0 : if (!found) {
612 0 : aContext->recycler()->getBoolResult(false, aResult);
613 :
614 0 : return NS_OK;
615 : }
616 :
617 0 : nsAutoString arg;
618 0 : rv = mParams[0]->evaluateToString(aContext, arg);
619 0 : NS_ENSURE_SUCCESS(rv, rv);
620 :
621 : bool result =
622 0 : StringBeginsWith(lang, arg,
623 0 : txCaseInsensitiveStringComparator()) &&
624 0 : (lang.Length() == arg.Length() ||
625 0 : lang.CharAt(arg.Length()) == '-');
626 :
627 0 : aContext->recycler()->getBoolResult(result, aResult);
628 :
629 0 : return NS_OK;
630 : }
631 : case _NOT:
632 : {
633 : bool result;
634 0 : rv = mParams[0]->evaluateToBool(aContext, result);
635 0 : NS_ENSURE_SUCCESS(rv, rv);
636 :
637 0 : aContext->recycler()->getBoolResult(!result, aResult);
638 :
639 0 : return NS_OK;
640 : }
641 : case _TRUE:
642 : {
643 0 : aContext->recycler()->getBoolResult(true, aResult);
644 :
645 0 : return NS_OK;
646 : }
647 : }
648 :
649 0 : aContext->receiveError(NS_LITERAL_STRING("Internal error"),
650 0 : NS_ERROR_UNEXPECTED);
651 0 : return NS_ERROR_UNEXPECTED;
652 : }
653 :
654 : Expr::ResultType
655 0 : txCoreFunctionCall::getReturnType()
656 : {
657 0 : return descriptTable[mType].mReturnType;
658 : }
659 :
660 : bool
661 0 : txCoreFunctionCall::isSensitiveTo(ContextSensitivity aContext)
662 : {
663 0 : switch (mType) {
664 : case COUNT:
665 : case CONCAT:
666 : case CONTAINS:
667 : case STARTS_WITH:
668 : case SUBSTRING:
669 : case SUBSTRING_AFTER:
670 : case SUBSTRING_BEFORE:
671 : case TRANSLATE:
672 : case ROUND:
673 : case FLOOR:
674 : case CEILING:
675 : case SUM:
676 : case BOOLEAN:
677 : case _NOT:
678 : case _FALSE:
679 : case _TRUE:
680 : {
681 0 : return argsSensitiveTo(aContext);
682 : }
683 : case ID:
684 : {
685 0 : return (aContext & NODE_CONTEXT) ||
686 0 : argsSensitiveTo(aContext);
687 : }
688 : case LAST:
689 : {
690 0 : return !!(aContext & SIZE_CONTEXT);
691 : }
692 : case LOCAL_NAME:
693 : case NAME:
694 : case NAMESPACE_URI:
695 : case NORMALIZE_SPACE:
696 : case STRING:
697 : case STRING_LENGTH:
698 : case NUMBER:
699 : {
700 0 : if (mParams.IsEmpty()) {
701 0 : return !!(aContext & NODE_CONTEXT);
702 : }
703 0 : return argsSensitiveTo(aContext);
704 : }
705 : case POSITION:
706 : {
707 0 : return !!(aContext & POSITION_CONTEXT);
708 : }
709 : case LANG:
710 : {
711 0 : return (aContext & NODE_CONTEXT) ||
712 0 : argsSensitiveTo(aContext);
713 : }
714 : }
715 :
716 0 : NS_NOTREACHED("how'd we get here?");
717 0 : return true;
718 : }
719 :
720 : // static
721 : bool
722 0 : txCoreFunctionCall::getTypeFromAtom(nsIAtom* aName, eType& aType)
723 : {
724 : uint32_t i;
725 0 : for (i = 0; i < ArrayLength(descriptTable); ++i) {
726 0 : if (aName == *descriptTable[i].mName) {
727 0 : aType = static_cast<eType>(i);
728 :
729 0 : return true;
730 : }
731 : }
732 :
733 0 : return false;
734 : }
735 :
736 : #ifdef TX_TO_STRING
737 : nsresult
738 0 : txCoreFunctionCall::getNameAtom(nsIAtom** aAtom)
739 : {
740 0 : NS_ADDREF(*aAtom = *descriptTable[mType].mName);
741 0 : return NS_OK;
742 : }
743 : #endif
|