1 /* 2 * Copyright (C) 2005 Frerich Raabe <raabe (at) kde.org> 3 * Copyright (C) 2006, 2009 Apple Inc. 4 * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "config.h" 29 #include "core/xml/XPathFunctions.h" 30 31 #include "core/XMLNames.h" 32 #include "core/dom/Attr.h" 33 #include "core/dom/Element.h" 34 #include "core/dom/ProcessingInstruction.h" 35 #include "core/dom/TreeScope.h" 36 #include "core/xml/XPathUtil.h" 37 #include "core/xml/XPathValue.h" 38 #include "wtf/MathExtras.h" 39 #include "wtf/text/StringBuilder.h" 40 41 namespace blink { 42 namespace XPath { 43 44 static inline bool isWhitespace(UChar c) 45 { 46 return c == ' ' || c == '\n' || c == '\r' || c == '\t'; 47 } 48 49 50 #define DEFINE_FUNCTION_CREATOR(Class) static Function* create##Class() { return new Class; } 51 52 class Interval { 53 public: 54 static const int Inf = -1; 55 56 Interval(); 57 Interval(int value); 58 Interval(int min, int max); 59 60 bool contains(int value) const; 61 62 private: 63 int m_min; 64 int m_max; 65 }; 66 67 struct FunctionRec { 68 typedef Function *(*FactoryFn)(); 69 FactoryFn factoryFn; 70 Interval args; 71 }; 72 73 static HashMap<String, FunctionRec>* functionMap; 74 75 class FunLast FINAL : public Function { 76 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 77 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 78 public: 79 FunLast() { setIsContextSizeSensitive(true); } 80 }; 81 82 class FunPosition FINAL : public Function { 83 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 84 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 85 public: 86 FunPosition() { setIsContextPositionSensitive(true); } 87 }; 88 89 class FunCount FINAL : public Function { 90 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 91 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 92 }; 93 94 class FunId FINAL : public Function { 95 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 96 virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; } 97 }; 98 99 class FunLocalName FINAL : public Function { 100 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 101 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 102 public: 103 FunLocalName() { setIsContextNodeSensitive(true); } // local-name() with no arguments uses context node. 104 }; 105 106 class FunNamespaceURI FINAL : public Function { 107 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 108 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 109 public: 110 FunNamespaceURI() { setIsContextNodeSensitive(true); } // namespace-uri() with no arguments uses context node. 111 }; 112 113 class FunName FINAL : public Function { 114 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 115 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 116 public: 117 FunName() { setIsContextNodeSensitive(true); } // name() with no arguments uses context node. 118 }; 119 120 class FunString FINAL : public Function { 121 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 122 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 123 public: 124 FunString() { setIsContextNodeSensitive(true); } // string() with no arguments uses context node. 125 }; 126 127 class FunConcat FINAL : public Function { 128 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 129 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 130 }; 131 132 class FunStartsWith FINAL : public Function { 133 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 134 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; } 135 }; 136 137 class FunContains FINAL : public Function { 138 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 139 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; } 140 }; 141 142 class FunSubstringBefore FINAL : public Function { 143 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 144 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 145 }; 146 147 class FunSubstringAfter FINAL : public Function { 148 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 149 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 150 }; 151 152 class FunSubstring FINAL : public Function { 153 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 154 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 155 }; 156 157 class FunStringLength FINAL : public Function { 158 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 159 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 160 public: 161 FunStringLength() { setIsContextNodeSensitive(true); } // string-length() with no arguments uses context node. 162 }; 163 164 class FunNormalizeSpace FINAL : public Function { 165 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 166 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 167 public: 168 FunNormalizeSpace() { setIsContextNodeSensitive(true); } // normalize-space() with no arguments uses context node. 169 }; 170 171 class FunTranslate FINAL : public Function { 172 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 173 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; } 174 }; 175 176 class FunBoolean FINAL : public Function { 177 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 178 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; } 179 }; 180 181 class FunNot FINAL : public Function { 182 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 183 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; } 184 }; 185 186 class FunTrue FINAL : public Function { 187 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 188 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; } 189 }; 190 191 class FunFalse FINAL : public Function { 192 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 193 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; } 194 }; 195 196 class FunLang FINAL : public Function { 197 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 198 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; } 199 public: 200 FunLang() { setIsContextNodeSensitive(true); } // lang() always works on context node. 201 }; 202 203 class FunNumber FINAL : public Function { 204 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 205 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 206 public: 207 FunNumber() { setIsContextNodeSensitive(true); } // number() with no arguments uses context node. 208 }; 209 210 class FunSum FINAL : public Function { 211 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 212 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 213 }; 214 215 class FunFloor FINAL : public Function { 216 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 217 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 218 }; 219 220 class FunCeiling FINAL : public Function { 221 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 222 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 223 }; 224 225 class FunRound FINAL : public Function { 226 virtual Value evaluate(EvaluationContext&) const OVERRIDE; 227 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; } 228 public: 229 static double round(double); 230 }; 231 232 DEFINE_FUNCTION_CREATOR(FunLast) 233 DEFINE_FUNCTION_CREATOR(FunPosition) 234 DEFINE_FUNCTION_CREATOR(FunCount) 235 DEFINE_FUNCTION_CREATOR(FunId) 236 DEFINE_FUNCTION_CREATOR(FunLocalName) 237 DEFINE_FUNCTION_CREATOR(FunNamespaceURI) 238 DEFINE_FUNCTION_CREATOR(FunName) 239 240 DEFINE_FUNCTION_CREATOR(FunString) 241 DEFINE_FUNCTION_CREATOR(FunConcat) 242 DEFINE_FUNCTION_CREATOR(FunStartsWith) 243 DEFINE_FUNCTION_CREATOR(FunContains) 244 DEFINE_FUNCTION_CREATOR(FunSubstringBefore) 245 DEFINE_FUNCTION_CREATOR(FunSubstringAfter) 246 DEFINE_FUNCTION_CREATOR(FunSubstring) 247 DEFINE_FUNCTION_CREATOR(FunStringLength) 248 DEFINE_FUNCTION_CREATOR(FunNormalizeSpace) 249 DEFINE_FUNCTION_CREATOR(FunTranslate) 250 251 DEFINE_FUNCTION_CREATOR(FunBoolean) 252 DEFINE_FUNCTION_CREATOR(FunNot) 253 DEFINE_FUNCTION_CREATOR(FunTrue) 254 DEFINE_FUNCTION_CREATOR(FunFalse) 255 DEFINE_FUNCTION_CREATOR(FunLang) 256 257 DEFINE_FUNCTION_CREATOR(FunNumber) 258 DEFINE_FUNCTION_CREATOR(FunSum) 259 DEFINE_FUNCTION_CREATOR(FunFloor) 260 DEFINE_FUNCTION_CREATOR(FunCeiling) 261 DEFINE_FUNCTION_CREATOR(FunRound) 262 263 #undef DEFINE_FUNCTION_CREATOR 264 265 inline Interval::Interval() 266 : m_min(Inf), m_max(Inf) 267 { 268 } 269 270 inline Interval::Interval(int value) 271 : m_min(value), m_max(value) 272 { 273 } 274 275 inline Interval::Interval(int min, int max) 276 : m_min(min), m_max(max) 277 { 278 } 279 280 inline bool Interval::contains(int value) const 281 { 282 if (m_min == Inf && m_max == Inf) 283 return true; 284 285 if (m_min == Inf) 286 return value <= m_max; 287 288 if (m_max == Inf) 289 return value >= m_min; 290 291 return value >= m_min && value <= m_max; 292 } 293 294 void Function::setArguments(WillBeHeapVector<OwnPtrWillBeMember<Expression> >& args) 295 { 296 ASSERT(!subExprCount()); 297 298 // Some functions use context node as implicit argument, so when explicit arguments are added, they may no longer be context node sensitive. 299 if (m_name != "lang" && !args.isEmpty()) 300 setIsContextNodeSensitive(false); 301 302 WillBeHeapVector<OwnPtrWillBeMember<Expression> >::iterator end = args.end(); 303 for (WillBeHeapVector<OwnPtrWillBeMember<Expression> >::iterator it = args.begin(); it != end; ++it) 304 addSubExpression(it->release()); 305 } 306 307 Value FunLast::evaluate(EvaluationContext& context) const 308 { 309 return context.size; 310 } 311 312 Value FunPosition::evaluate(EvaluationContext& context) const 313 { 314 return context.position; 315 } 316 317 Value FunId::evaluate(EvaluationContext& context) const 318 { 319 Value a = arg(0)->evaluate(context); 320 StringBuilder idList; // A whitespace-separated list of IDs 321 322 if (a.isNodeSet()) { 323 const NodeSet& nodes = a.toNodeSet(&context); 324 for (size_t i = 0; i < nodes.size(); ++i) { 325 String str = stringValue(nodes[i]); 326 idList.append(str); 327 idList.append(' '); 328 } 329 } else { 330 String str = a.toString(); 331 idList.append(str); 332 } 333 334 TreeScope& contextScope = context.node->treeScope(); 335 OwnPtrWillBeRawPtr<NodeSet> result(NodeSet::create()); 336 WillBeHeapHashSet<RawPtrWillBeMember<Node> > resultSet; 337 338 unsigned startPos = 0; 339 unsigned length = idList.length(); 340 while (true) { 341 while (startPos < length && isWhitespace(idList[startPos])) 342 ++startPos; 343 344 if (startPos == length) 345 break; 346 347 size_t endPos = startPos; 348 while (endPos < length && !isWhitespace(idList[endPos])) 349 ++endPos; 350 351 // If there are several nodes with the same id, id() should return the first one. 352 // In WebKit, getElementById behaves so, too, although its behavior in this case is formally undefined. 353 Node* node = contextScope.getElementById(AtomicString(idList.substring(startPos, endPos - startPos))); 354 if (node && resultSet.add(node).isNewEntry) 355 result->append(node); 356 357 startPos = endPos; 358 } 359 360 result->markSorted(false); 361 362 return Value(result.release(), Value::adopt); 363 } 364 365 static inline String expandedNameLocalPart(Node* node) 366 { 367 // The local part of an XPath expanded-name matches DOM local name for most node types, except for namespace nodes and processing instruction nodes. 368 // But note that Blink does not support namespace nodes. 369 if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) 370 return toProcessingInstruction(node)->target(); 371 return node->localName().string(); 372 } 373 374 static inline String expandedName(Node* node) 375 { 376 AtomicString prefix; 377 378 switch (node->nodeType()) { 379 case Node::ELEMENT_NODE: 380 prefix = toElement(node)->prefix(); 381 break; 382 case Node::ATTRIBUTE_NODE: 383 prefix = toAttr(node)->prefix(); 384 break; 385 default: 386 break; 387 } 388 389 return prefix.isEmpty() ? expandedNameLocalPart(node) : prefix + ":" + expandedNameLocalPart(node); 390 } 391 392 Value FunLocalName::evaluate(EvaluationContext& context) const 393 { 394 if (argCount() > 0) { 395 Value a = arg(0)->evaluate(context); 396 if (!a.isNodeSet()) 397 return ""; 398 399 Node* node = a.toNodeSet(&context).firstNode(); 400 return node ? expandedNameLocalPart(node) : ""; 401 } 402 403 return expandedNameLocalPart(context.node.get()); 404 } 405 406 Value FunNamespaceURI::evaluate(EvaluationContext& context) const 407 { 408 if (argCount() > 0) { 409 Value a = arg(0)->evaluate(context); 410 if (!a.isNodeSet()) 411 return ""; 412 413 Node* node = a.toNodeSet(&context).firstNode(); 414 return node ? node->namespaceURI().string() : ""; 415 } 416 417 return context.node->namespaceURI().string(); 418 } 419 420 Value FunName::evaluate(EvaluationContext& context) const 421 { 422 if (argCount() > 0) { 423 Value a = arg(0)->evaluate(context); 424 if (!a.isNodeSet()) 425 return ""; 426 427 Node* node = a.toNodeSet(&context).firstNode(); 428 return node ? expandedName(node) : ""; 429 } 430 431 return expandedName(context.node.get()); 432 } 433 434 Value FunCount::evaluate(EvaluationContext& context) const 435 { 436 Value a = arg(0)->evaluate(context); 437 438 return double(a.toNodeSet(&context).size()); 439 } 440 441 Value FunString::evaluate(EvaluationContext& context) const 442 { 443 if (!argCount()) 444 return Value(context.node.get()).toString(); 445 return arg(0)->evaluate(context).toString(); 446 } 447 448 Value FunConcat::evaluate(EvaluationContext& context) const 449 { 450 StringBuilder result; 451 result.reserveCapacity(1024); 452 453 unsigned count = argCount(); 454 for (unsigned i = 0; i < count; ++i) { 455 String str(arg(i)->evaluate(context).toString()); 456 result.append(str); 457 } 458 459 return result.toString(); 460 } 461 462 Value FunStartsWith::evaluate(EvaluationContext& context) const 463 { 464 String s1 = arg(0)->evaluate(context).toString(); 465 String s2 = arg(1)->evaluate(context).toString(); 466 467 if (s2.isEmpty()) 468 return true; 469 470 return s1.startsWith(s2); 471 } 472 473 Value FunContains::evaluate(EvaluationContext& context) const 474 { 475 String s1 = arg(0)->evaluate(context).toString(); 476 String s2 = arg(1)->evaluate(context).toString(); 477 478 if (s2.isEmpty()) 479 return true; 480 481 return s1.contains(s2) != 0; 482 } 483 484 Value FunSubstringBefore::evaluate(EvaluationContext& context) const 485 { 486 String s1 = arg(0)->evaluate(context).toString(); 487 String s2 = arg(1)->evaluate(context).toString(); 488 489 if (s2.isEmpty()) 490 return ""; 491 492 size_t i = s1.find(s2); 493 494 if (i == kNotFound) 495 return ""; 496 497 return s1.left(i); 498 } 499 500 Value FunSubstringAfter::evaluate(EvaluationContext& context) const 501 { 502 String s1 = arg(0)->evaluate(context).toString(); 503 String s2 = arg(1)->evaluate(context).toString(); 504 505 size_t i = s1.find(s2); 506 if (i == kNotFound) 507 return ""; 508 509 return s1.substring(i + s2.length()); 510 } 511 512 Value FunSubstring::evaluate(EvaluationContext& context) const 513 { 514 String s = arg(0)->evaluate(context).toString(); 515 double doublePos = arg(1)->evaluate(context).toNumber(); 516 if (std::isnan(doublePos)) 517 return ""; 518 long pos = static_cast<long>(FunRound::round(doublePos)); 519 bool haveLength = argCount() == 3; 520 long len = -1; 521 if (haveLength) { 522 double doubleLen = arg(2)->evaluate(context).toNumber(); 523 if (std::isnan(doubleLen)) 524 return ""; 525 len = static_cast<long>(FunRound::round(doubleLen)); 526 } 527 528 if (pos > long(s.length())) 529 return ""; 530 531 if (pos < 1) { 532 if (haveLength) { 533 len -= 1 - pos; 534 if (len < 1) 535 return ""; 536 } 537 pos = 1; 538 } 539 540 return s.substring(pos - 1, len); 541 } 542 543 Value FunStringLength::evaluate(EvaluationContext& context) const 544 { 545 if (!argCount()) 546 return Value(context.node.get()).toString().length(); 547 return arg(0)->evaluate(context).toString().length(); 548 } 549 550 Value FunNormalizeSpace::evaluate(EvaluationContext& context) const 551 { 552 if (!argCount()) { 553 String s = Value(context.node.get()).toString(); 554 return s.simplifyWhiteSpace(); 555 } 556 557 String s = arg(0)->evaluate(context).toString(); 558 return s.simplifyWhiteSpace(); 559 } 560 561 Value FunTranslate::evaluate(EvaluationContext& context) const 562 { 563 String s1 = arg(0)->evaluate(context).toString(); 564 String s2 = arg(1)->evaluate(context).toString(); 565 String s3 = arg(2)->evaluate(context).toString(); 566 StringBuilder result; 567 568 for (unsigned i1 = 0; i1 < s1.length(); ++i1) { 569 UChar ch = s1[i1]; 570 size_t i2 = s2.find(ch); 571 572 if (i2 == kNotFound) 573 result.append(ch); 574 else if (i2 < s3.length()) 575 result.append(s3[i2]); 576 } 577 578 return result.toString(); 579 } 580 581 Value FunBoolean::evaluate(EvaluationContext& context) const 582 { 583 return arg(0)->evaluate(context).toBoolean(); 584 } 585 586 Value FunNot::evaluate(EvaluationContext& context) const 587 { 588 return !arg(0)->evaluate(context).toBoolean(); 589 } 590 591 Value FunTrue::evaluate(EvaluationContext&) const 592 { 593 return true; 594 } 595 596 Value FunLang::evaluate(EvaluationContext& context) const 597 { 598 String lang = arg(0)->evaluate(context).toString(); 599 600 const Attribute* languageAttribute = 0; 601 Node* node = context.node.get(); 602 while (node) { 603 if (node->isElementNode()) { 604 Element* element = toElement(node); 605 languageAttribute = element->attributes().find(XMLNames::langAttr); 606 } 607 if (languageAttribute) 608 break; 609 node = node->parentNode(); 610 } 611 612 if (!languageAttribute) 613 return false; 614 615 String langValue = languageAttribute->value(); 616 while (true) { 617 if (equalIgnoringCase(langValue, lang)) 618 return true; 619 620 // Remove suffixes one by one. 621 size_t index = langValue.reverseFind('-'); 622 if (index == kNotFound) 623 break; 624 langValue = langValue.left(index); 625 } 626 627 return false; 628 } 629 630 Value FunFalse::evaluate(EvaluationContext&) const 631 { 632 return false; 633 } 634 635 Value FunNumber::evaluate(EvaluationContext& context) const 636 { 637 if (!argCount()) 638 return Value(context.node.get()).toNumber(); 639 return arg(0)->evaluate(context).toNumber(); 640 } 641 642 Value FunSum::evaluate(EvaluationContext& context) const 643 { 644 Value a = arg(0)->evaluate(context); 645 if (!a.isNodeSet()) 646 return 0.0; 647 648 double sum = 0.0; 649 const NodeSet& nodes = a.toNodeSet(&context); 650 // To be really compliant, we should sort the node-set, as floating point addition is not associative. 651 // However, this is unlikely to ever become a practical issue, and sorting is slow. 652 653 for (unsigned i = 0; i < nodes.size(); i++) 654 sum += Value(stringValue(nodes[i])).toNumber(); 655 656 return sum; 657 } 658 659 Value FunFloor::evaluate(EvaluationContext& context) const 660 { 661 return floor(arg(0)->evaluate(context).toNumber()); 662 } 663 664 Value FunCeiling::evaluate(EvaluationContext& context) const 665 { 666 return ceil(arg(0)->evaluate(context).toNumber()); 667 } 668 669 double FunRound::round(double val) 670 { 671 if (!std::isnan(val) && !std::isinf(val)) { 672 if (std::signbit(val) && val >= -0.5) 673 val *= 0; // negative zero 674 else 675 val = floor(val + 0.5); 676 } 677 return val; 678 } 679 680 Value FunRound::evaluate(EvaluationContext& context) const 681 { 682 return round(arg(0)->evaluate(context).toNumber()); 683 } 684 685 struct FunctionMapping { 686 const char* name; 687 FunctionRec function; 688 }; 689 690 static void createFunctionMap() 691 { 692 static const FunctionMapping functions[] = { 693 { "boolean", { &createFunBoolean, 1 } }, 694 { "ceiling", { &createFunCeiling, 1 } }, 695 { "concat", { &createFunConcat, Interval(2, Interval::Inf) } }, 696 { "contains", { &createFunContains, 2 } }, 697 { "count", { &createFunCount, 1 } }, 698 { "false", { &createFunFalse, 0 } }, 699 { "floor", { &createFunFloor, 1 } }, 700 { "id", { &createFunId, 1 } }, 701 { "lang", { &createFunLang, 1 } }, 702 { "last", { &createFunLast, 0 } }, 703 { "local-name", { &createFunLocalName, Interval(0, 1) } }, 704 { "name", { &createFunName, Interval(0, 1) } }, 705 { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } }, 706 { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } }, 707 { "not", { &createFunNot, 1 } }, 708 { "number", { &createFunNumber, Interval(0, 1) } }, 709 { "position", { &createFunPosition, 0 } }, 710 { "round", { &createFunRound, 1 } }, 711 { "starts-with", { &createFunStartsWith, 2 } }, 712 { "string", { &createFunString, Interval(0, 1) } }, 713 { "string-length", { &createFunStringLength, Interval(0, 1) } }, 714 { "substring", { &createFunSubstring, Interval(2, 3) } }, 715 { "substring-after", { &createFunSubstringAfter, 2 } }, 716 { "substring-before", { &createFunSubstringBefore, 2 } }, 717 { "sum", { &createFunSum, 1 } }, 718 { "translate", { &createFunTranslate, 3 } }, 719 { "true", { &createFunTrue, 0 } }, 720 }; 721 722 functionMap = new HashMap<String, FunctionRec>; 723 for (size_t i = 0; i < WTF_ARRAY_LENGTH(functions); ++i) 724 functionMap->set(functions[i].name, functions[i].function); 725 } 726 727 728 Function* createFunction(const String& name) 729 { 730 WillBeHeapVector<OwnPtrWillBeMember<Expression> > args; 731 return createFunction(name, args); 732 } 733 734 Function* createFunction(const String& name, WillBeHeapVector<OwnPtrWillBeMember<Expression> >& args) 735 { 736 if (!functionMap) 737 createFunctionMap(); 738 739 HashMap<String, FunctionRec>::iterator functionMapIter = functionMap->find(name); 740 FunctionRec* functionRec = 0; 741 742 if (functionMapIter == functionMap->end() || !(functionRec = &functionMapIter->value)->args.contains(args.size())) 743 return 0; 744 745 Function* function = functionRec->factoryFn(); 746 function->setArguments(args); 747 function->setName(name); 748 return function; 749 } 750 751 } 752 } 753