OLD | NEW |
1 #define IN_LIBEXSLT | 1 #define IN_LIBEXSLT |
2 #include "libexslt/libexslt.h" | 2 #include "libexslt/libexslt.h" |
3 | 3 |
4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) | 4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) |
5 #include <win32config.h> | 5 #include <win32config.h> |
6 #else | 6 #else |
7 #include "config.h" | 7 #include "config.h" |
8 #endif | 8 #endif |
9 | 9 |
10 #include <libxml/tree.h> | 10 #include <libxml/tree.h> |
11 #include <libxml/xpath.h> | 11 #include <libxml/xpath.h> |
12 #include <libxml/xpathInternals.h> | 12 #include <libxml/xpathInternals.h> |
13 #include <libxml/parser.h> | 13 #include <libxml/parser.h> |
14 #include <libxml/encoding.h> | 14 #include <libxml/encoding.h> |
15 #include <libxml/uri.h> | 15 #include <libxml/uri.h> |
16 | 16 |
17 #include <libxslt/xsltconfig.h> | 17 #include <libxslt/xsltconfig.h> |
18 #include <libxslt/xsltutils.h> | 18 #include <libxslt/xsltutils.h> |
19 #include <libxslt/xsltInternals.h> | 19 #include <libxslt/xsltInternals.h> |
20 #include <libxslt/extensions.h> | 20 #include <libxslt/extensions.h> |
21 | 21 |
22 #include "exslt.h" | 22 #include "exslt.h" |
23 | 23 |
24 /** | 24 /** |
25 * exsltStrTokenizeFunction: | 25 * exsltStrTokenizeFunction: |
26 * @ctxt: an XPath parser context | 26 * @ctxt: an XPath parser context |
27 * @nargs: the number of arguments | 27 * @nargs: the number of arguments |
28 * | 28 * |
29 * Splits up a string on the characters of the delimiter string and returns a | 29 * Splits up a string on the characters of the delimiter string and returns a |
30 * node set of token elements, each containing one token from the string. | 30 * node set of token elements, each containing one token from the string. |
31 */ | 31 */ |
32 static void | 32 static void |
33 exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) | 33 exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) |
34 { | 34 { |
35 xsltTransformContextPtr tctxt; | 35 xsltTransformContextPtr tctxt; |
36 xmlChar *str, *delimiters, *cur; | 36 xmlChar *str, *delimiters, *cur; |
37 const xmlChar *token, *delimiter; | 37 const xmlChar *token, *delimiter; |
38 xmlNodePtr node; | 38 xmlNodePtr node; |
39 xmlDocPtr container; | 39 xmlDocPtr container; |
40 xmlXPathObjectPtr ret = NULL; | 40 xmlXPathObjectPtr ret = NULL; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 (const xmlChar *) "token", token); | 99 (const xmlChar *) "token", token); |
100 xmlAddChild((xmlNodePtr) container, node); | 100 xmlAddChild((xmlNodePtr) container, node); |
101 xmlXPathNodeSetAddUnique(ret->nodesetval, node); | 101 xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
102 *cur = *delimiter; /* restore the changed byte */ | 102 *cur = *delimiter; /* restore the changed byte */ |
103 token = cur + clen; | 103 token = cur + clen; |
104 break; | 104 break; |
105 } | 105 } |
106 } | 106 } |
107 } | 107 } |
108 if (token != cur) { | 108 if (token != cur) { |
109 » » node = xmlNewDocRawNode(container, NULL, | 109 » » node = xmlNewDocRawNode(container, NULL, |
110 (const xmlChar *) "token", token); | 110 (const xmlChar *) "token", token); |
111 xmlAddChild((xmlNodePtr) container, node); | 111 xmlAddChild((xmlNodePtr) container, node); |
112 xmlXPathNodeSetAddUnique(ret->nodesetval, node); | 112 xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
113 } | 113 } |
114 /* | 114 /* |
115 * Mark it as a function result in order to avoid garbage | 115 * Mark it as a function result in order to avoid garbage |
116 * collecting of tree fragments | 116 * collecting of tree fragments |
117 */ | 117 */ |
118 xsltExtensionInstructionResultRegister(tctxt, ret); | 118 xsltExtensionInstructionResultRegister(tctxt, ret); |
119 } | 119 } |
120 } | 120 } |
121 | 121 |
122 fail: | 122 fail: |
123 if (str != NULL) | 123 if (str != NULL) |
124 xmlFree(str); | 124 xmlFree(str); |
125 if (delimiters != NULL) | 125 if (delimiters != NULL) |
126 xmlFree(delimiters); | 126 xmlFree(delimiters); |
127 if (ret != NULL) | 127 if (ret != NULL) |
128 valuePush(ctxt, ret); | 128 valuePush(ctxt, ret); |
129 else | 129 else |
130 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); | 130 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); |
131 } | 131 } |
132 | 132 |
133 /** | 133 /** |
134 * exsltStrSplitFunction: | 134 * exsltStrSplitFunction: |
135 * @ctxt: an XPath parser context | 135 * @ctxt: an XPath parser context |
136 * @nargs: the number of arguments | 136 * @nargs: the number of arguments |
137 * | 137 * |
138 * Splits up a string on a delimiting string and returns a node set of token | 138 * Splits up a string on a delimiting string and returns a node set of token |
139 * elements, each containing one token from the string. | 139 * elements, each containing one token from the string. |
140 */ | 140 */ |
141 static void | 141 static void |
142 exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 142 exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { |
143 xsltTransformContextPtr tctxt; | 143 xsltTransformContextPtr tctxt; |
144 xmlChar *str, *delimiter, *cur; | 144 xmlChar *str, *delimiter, *cur; |
145 const xmlChar *token; | 145 const xmlChar *token; |
146 xmlNodePtr node; | 146 xmlNodePtr node; |
147 xmlDocPtr container; | 147 xmlDocPtr container; |
148 xmlXPathObjectPtr ret = NULL; | 148 xmlXPathObjectPtr ret = NULL; |
149 int delimiterLength; | 149 int delimiterLength; |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 | 328 |
329 ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL); | 329 ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL); |
330 if (!xmlCheckUTF8(ret)) { | 330 if (!xmlCheckUTF8(ret)) { |
331 /* FIXME: instead of throwing away the whole URI, we should | 331 /* FIXME: instead of throwing away the whole URI, we should |
332 only discard the invalid sequence(s). How to do that? */ | 332 only discard the invalid sequence(s). How to do that? */ |
333 xmlXPathReturnEmptyString(ctxt); | 333 xmlXPathReturnEmptyString(ctxt); |
334 xmlFree(str); | 334 xmlFree(str); |
335 xmlFree(ret); | 335 xmlFree(ret); |
336 return; | 336 return; |
337 } | 337 } |
338 | 338 |
339 xmlXPathReturnString(ctxt, ret); | 339 xmlXPathReturnString(ctxt, ret); |
340 | 340 |
341 if (str != NULL) | 341 if (str != NULL) |
342 xmlFree(str); | 342 xmlFree(str); |
343 } | 343 } |
344 | 344 |
345 /** | 345 /** |
346 * exsltStrPaddingFunction: | 346 * exsltStrPaddingFunction: |
347 * @ctxt: an XPath parser context | 347 * @ctxt: an XPath parser context |
348 * @nargs: the number of arguments | 348 * @nargs: the number of arguments |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 | 498 |
499 xmlFree(tmp); | 499 xmlFree(tmp); |
500 } | 500 } |
501 | 501 |
502 xmlXPathFreeObject (obj); | 502 xmlXPathFreeObject (obj); |
503 | 503 |
504 xmlXPathReturnString(ctxt, ret); | 504 xmlXPathReturnString(ctxt, ret); |
505 } | 505 } |
506 | 506 |
507 /** | 507 /** |
508 * exsltStrReplaceInternal: | 508 * exsltStrReturnString: |
509 * @str: string to modify | 509 * @ctxt: an XPath parser context |
510 * @searchStr: string to find | 510 * @str: a string |
511 * @replaceStr: string to replace occurrences of searchStr | 511 * @len: length of string |
512 * | 512 * |
513 * Search and replace string function used by exsltStrReplaceFunction | 513 * Returns a string as a node set. |
514 */ | 514 */ |
515 static xmlChar* | 515 static int |
516 exsltStrReplaceInternal(const xmlChar* str, const xmlChar* searchStr, | 516 exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str, |
517 const xmlChar* replaceStr) | 517 int len) |
518 { | 518 { |
519 const xmlChar *curr, *next; | 519 xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); |
520 xmlChar *ret = NULL; | 520 xmlDocPtr container; |
521 int searchStrSize; | 521 xmlNodePtr text_node; |
522 | 522 xmlXPathObjectPtr ret; |
523 curr = str; | 523 |
524 searchStrSize = xmlStrlen(searchStr); | 524 container = xsltCreateRVT(tctxt); |
525 | 525 if (container == NULL) { |
526 do { | 526 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
527 next = xmlStrstr(curr, searchStr); | 527 return(-1); |
528 if (next == NULL) { | 528 } |
529 ret = xmlStrcat (ret, curr); | 529 xsltRegisterLocalRVT(tctxt, container); |
530 break; | 530 |
531 } | 531 text_node = xmlNewTextLen(str, len); |
532 | 532 if (text_node == NULL) { |
533 ret = xmlStrncat (ret, curr, next - curr); | 533 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
534 ret = xmlStrcat (ret, replaceStr); | 534 return(-1); |
535 curr = next + searchStrSize; | 535 } |
536 } while (*curr != 0); | 536 xmlAddChild((xmlNodePtr) container, text_node); |
537 | 537 |
538 return ret; | 538 ret = xmlXPathNewNodeSet(text_node); |
| 539 if (ret == NULL) { |
| 540 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| 541 return(-1); |
| 542 } |
| 543 |
| 544 xsltExtensionInstructionResultRegister(tctxt, ret); |
| 545 valuePush(ctxt, ret); |
| 546 |
| 547 return(0); |
539 } | 548 } |
| 549 |
540 /** | 550 /** |
541 * exsltStrReplaceFunction: | 551 * exsltStrReplaceFunction: |
542 * @ctxt: an XPath parser context | 552 * @ctxt: an XPath parser context |
543 * @nargs: the number of arguments | 553 * @nargs: the number of arguments |
544 * | 554 * |
545 * Takes a string, and two node sets and returns the string with all strings in | 555 * Takes a string, and two node sets and returns the string with all strings in |
546 * the first node set replaced by all strings in the second node set. | 556 * the first node set replaced by all strings in the second node set. |
547 */ | 557 */ |
548 static void | 558 static void |
549 exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) { | 559 exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
550 xmlChar *str = NULL, *searchStr = NULL, *replaceStr = NULL; | 560 int i, i_empty, n, slen0, rlen0, *slen, *rlen; |
551 xmlNodeSetPtr replaceSet = NULL, searchSet = NULL; | 561 void *mem = NULL; |
552 xmlChar *ret = NULL, *retSwap = NULL; | 562 const xmlChar *src, *start; |
553 int i; | 563 xmlChar *string, *search_str = NULL, *replace_str = NULL; |
| 564 xmlChar **search, **replace; |
| 565 xmlNodeSetPtr search_set = NULL, replace_set = NULL; |
| 566 xmlBufferPtr buf; |
554 | 567 |
555 if (nargs != 3) { | 568 if (nargs != 3) { |
556 xmlXPathSetArityError(ctxt); | 569 xmlXPathSetArityError(ctxt); |
557 return; | 570 return; |
558 } | 571 } |
559 | 572 |
560 /* pull out replace argument */ | 573 /* get replace argument */ |
| 574 |
| 575 if (!xmlXPathStackIsNodeSet(ctxt)) |
| 576 replace_str = xmlXPathPopString(ctxt); |
| 577 else |
| 578 replace_set = xmlXPathPopNodeSet(ctxt); |
| 579 |
| 580 if (xmlXPathCheckError(ctxt)) |
| 581 goto fail_replace; |
| 582 |
| 583 /* get search argument */ |
| 584 |
561 if (!xmlXPathStackIsNodeSet(ctxt)) { | 585 if (!xmlXPathStackIsNodeSet(ctxt)) { |
562 replaceStr = xmlXPathPopString(ctxt); | 586 search_str = xmlXPathPopString(ctxt); |
563 } | 587 n = 1; |
564 » » else { | 588 } |
565 replaceSet = xmlXPathPopNodeSet(ctxt); | 589 else { |
566 if (xmlXPathCheckError(ctxt)) { | 590 search_set = xmlXPathPopNodeSet(ctxt); |
567 xmlXPathSetTypeError(ctxt); | 591 n = search_set != NULL ? search_set->nodeNr : 0; |
568 goto fail; | 592 } |
569 } | 593 |
570 } | 594 if (xmlXPathCheckError(ctxt)) |
571 | 595 goto fail_search; |
572 /* behavior driven by search argument from here on */ | 596 |
573 if (!xmlXPathStackIsNodeSet(ctxt)) { | 597 /* get string argument */ |
574 searchStr = xmlXPathPopString(ctxt); | 598 |
575 str = xmlXPathPopString(ctxt); | 599 string = xmlXPathPopString(ctxt); |
576 | 600 if (xmlXPathCheckError(ctxt)) |
577 if (replaceStr == NULL) { | 601 goto fail_string; |
578 xmlXPathSetTypeError(ctxt); | 602 |
579 goto fail; | 603 /* check for empty search node list */ |
580 } | 604 |
581 | 605 if (n <= 0) { |
582 ret = exsltStrReplaceInternal(str, searchStr, replaceStr); | 606 exsltStrReturnString(ctxt, string, xmlStrlen(string)); |
583 } | 607 goto done_empty_search; |
584 » » else { | 608 } |
585 searchSet = xmlXPathPopNodeSet(ctxt); | 609 |
586 if (searchSet == NULL || xmlXPathCheckError(ctxt)) { | 610 /* allocate memory for string pointer and length arrays */ |
587 xmlXPathSetTypeError(ctxt); | 611 |
588 goto fail; | 612 if (n == 1) { |
589 } | 613 search = &search_str; |
590 | 614 replace = &replace_str; |
591 str = xmlXPathPopString(ctxt); | 615 slen = &slen0; |
592 ret = xmlStrdup(str); | 616 rlen = &rlen0; |
593 | 617 } |
594 for (i = 0; i < searchSet->nodeNr; i++) { | 618 else { |
595 » searchStr = xmlXPathCastNodeToString(searchSet->nodeTab[i]); | 619 mem = xmlMalloc(2 * n * (sizeof(const xmlChar *) + sizeof(int))); |
596 | 620 if (mem == NULL) { |
597 if (replaceSet != NULL) { | 621 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
598 replaceStr = NULL; | 622 goto fail_malloc; |
599 if (i < replaceSet->nodeNr) { | 623 } |
600 replaceStr = xmlXPathCastNodeToString(replaceSet->nodeTab[i]); | 624 search = (xmlChar **) mem; |
601 } | 625 replace = search + n; |
602 | 626 slen = (int *) (replace + n); |
603 retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr); | 627 rlen = slen + n; |
604 | 628 } |
605 if (replaceStr != NULL) { | 629 |
606 xmlFree(replaceStr); | 630 /* process arguments */ |
607 replaceStr = NULL; | 631 |
608 } | 632 i_empty = -1; |
| 633 |
| 634 for (i=0; i<n; ++i) { |
| 635 if (search_set != NULL) { |
| 636 search[i] = xmlXPathCastNodeToString(search_set->nodeTab[i]); |
| 637 if (search[i] == NULL) { |
| 638 n = i; |
| 639 goto fail_process_args; |
| 640 } |
| 641 } |
| 642 |
| 643 slen[i] = xmlStrlen(search[i]); |
| 644 if (i_empty < 0 && slen[i] == 0) |
| 645 i_empty = i; |
| 646 |
| 647 if (replace_set != NULL) { |
| 648 if (i < replace_set->nodeNr) { |
| 649 replace[i] = xmlXPathCastNodeToString(replace_set->nodeTab[i]); |
| 650 if (replace[i] == NULL) { |
| 651 n = i + 1; |
| 652 goto fail_process_args; |
| 653 } |
| 654 } |
| 655 else |
| 656 replace[i] = NULL; |
609 } | 657 } |
610 else { | 658 else { |
611 retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr); | 659 if (i == 0) |
612 } | 660 replace[i] = replace_str; |
613 | 661 else |
614 » » » » xmlFree(ret); | 662 replace[i] = NULL; |
615 if (searchStr != NULL) { | 663 } |
616 xmlFree(searchStr); | 664 |
617 searchStr = NULL; | 665 if (replace[i] == NULL) |
618 } | 666 rlen[i] = 0; |
619 | 667 else |
620 » » » » ret = retSwap; | 668 rlen[i] = xmlStrlen(replace[i]); |
621 » » » } | 669 } |
622 | 670 |
623 if (replaceSet != NULL) | 671 if (i_empty >= 0 && rlen[i_empty] == 0) |
624 xmlXPathFreeNodeSet(replaceSet); | 672 i_empty = -1; |
625 | 673 |
626 if (searchSet != NULL) | 674 /* replace operation */ |
627 xmlXPathFreeNodeSet(searchSet); | 675 |
628 » » } | 676 buf = xmlBufferCreate(); |
629 | 677 if (buf == NULL) { |
630 xmlXPathReturnString(ctxt, ret); | 678 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
631 | 679 goto fail_buffer; |
632 fail: | 680 } |
633 if (replaceStr != NULL) | 681 src = string; |
634 xmlFree(replaceStr); | 682 start = string; |
635 | 683 |
636 if (searchStr != NULL) | 684 while (*src != 0) { |
637 xmlFree(searchStr); | 685 int max_len = 0, i_match = 0; |
638 | 686 |
639 if (str != NULL) | 687 for (i=0; i<n; ++i) { |
640 xmlFree(str); | 688 if (*src == search[i][0] && |
| 689 slen[i] > max_len && |
| 690 xmlStrncmp(src, search[i], slen[i]) == 0) |
| 691 { |
| 692 i_match = i; |
| 693 max_len = slen[i]; |
| 694 } |
| 695 } |
| 696 |
| 697 if (max_len == 0) { |
| 698 if (i_empty >= 0 && start < src) { |
| 699 if (xmlBufferAdd(buf, start, src - start) || |
| 700 xmlBufferAdd(buf, replace[i_empty], rlen[i_empty])) |
| 701 { |
| 702 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| 703 goto fail_buffer_add; |
| 704 } |
| 705 start = src; |
| 706 } |
| 707 |
| 708 src += xmlUTF8Size(src); |
| 709 } |
| 710 else { |
| 711 if ((start < src && |
| 712 xmlBufferAdd(buf, start, src - start)) || |
| 713 (rlen[i_match] && |
| 714 xmlBufferAdd(buf, replace[i_match], rlen[i_match]))) |
| 715 { |
| 716 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| 717 goto fail_buffer_add; |
| 718 } |
| 719 |
| 720 src += slen[i_match]; |
| 721 start = src; |
| 722 } |
| 723 } |
| 724 |
| 725 if (start < src && xmlBufferAdd(buf, start, src - start)) { |
| 726 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
| 727 goto fail_buffer_add; |
| 728 } |
| 729 |
| 730 /* create result node set */ |
| 731 |
| 732 exsltStrReturnString(ctxt, xmlBufferContent(buf), xmlBufferLength(buf)); |
| 733 |
| 734 /* clean up */ |
| 735 |
| 736 fail_buffer_add: |
| 737 xmlBufferFree(buf); |
| 738 |
| 739 fail_buffer: |
| 740 fail_process_args: |
| 741 if (search_set != NULL) { |
| 742 for (i=0; i<n; ++i) |
| 743 xmlFree(search[i]); |
| 744 } |
| 745 if (replace_set != NULL) { |
| 746 for (i=0; i<n; ++i) { |
| 747 if (replace[i] != NULL) |
| 748 xmlFree(replace[i]); |
| 749 } |
| 750 } |
| 751 |
| 752 if (mem != NULL) |
| 753 xmlFree(mem); |
| 754 |
| 755 fail_malloc: |
| 756 done_empty_search: |
| 757 xmlFree(string); |
| 758 |
| 759 fail_string: |
| 760 if (search_set != NULL) |
| 761 xmlXPathFreeNodeSet(search_set); |
| 762 else |
| 763 xmlFree(search_str); |
| 764 |
| 765 fail_search: |
| 766 if (replace_set != NULL) |
| 767 xmlXPathFreeNodeSet(replace_set); |
| 768 else |
| 769 xmlFree(replace_str); |
| 770 |
| 771 fail_replace: |
| 772 return; |
641 } | 773 } |
642 | 774 |
643 /** | 775 /** |
644 * exsltStrRegister: | 776 * exsltStrRegister: |
645 * | 777 * |
646 * Registers the EXSLT - Strings module | 778 * Registers the EXSLT - Strings module |
647 */ | 779 */ |
648 | 780 |
649 void | 781 void |
650 exsltStrRegister (void) { | 782 exsltStrRegister (void) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
708 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, | 840 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, |
709 exsltStrConcatFunction) | 841 exsltStrConcatFunction) |
710 && !xmlXPathRegisterFuncNS(ctxt, | 842 && !xmlXPathRegisterFuncNS(ctxt, |
711 (const xmlChar *) "replace", | 843 (const xmlChar *) "replace", |
712 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, | 844 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, |
713 exsltStrReplaceFunction)) { | 845 exsltStrReplaceFunction)) { |
714 return 0; | 846 return 0; |
715 } | 847 } |
716 return -1; | 848 return -1; |
717 } | 849 } |
OLD | NEW |