OLD | NEW |
| (Empty) |
1 #define IN_LIBEXSLT | |
2 #include "libexslt/libexslt.h" | |
3 | |
4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__) | |
5 #include <win32config.h> | |
6 #else | |
7 #include "config.h" | |
8 #endif | |
9 | |
10 #include <libxml/tree.h> | |
11 #include <libxml/xpath.h> | |
12 #include <libxml/xpathInternals.h> | |
13 #include <libxml/parser.h> | |
14 #include <libxml/encoding.h> | |
15 #include <libxml/uri.h> | |
16 | |
17 #include <libxslt/xsltconfig.h> | |
18 #include <libxslt/xsltutils.h> | |
19 #include <libxslt/xsltInternals.h> | |
20 #include <libxslt/extensions.h> | |
21 | |
22 #include "exslt.h" | |
23 | |
24 /** | |
25 * exsltStrTokenizeFunction: | |
26 * @ctxt: an XPath parser context | |
27 * @nargs: the number of arguments | |
28 * | |
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. | |
31 */ | |
32 static void | |
33 exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) | |
34 { | |
35 xsltTransformContextPtr tctxt; | |
36 xmlChar *str, *delimiters, *cur; | |
37 const xmlChar *token, *delimiter; | |
38 xmlNodePtr node; | |
39 xmlDocPtr container; | |
40 xmlXPathObjectPtr ret = NULL; | |
41 int clen; | |
42 | |
43 if ((nargs < 1) || (nargs > 2)) { | |
44 xmlXPathSetArityError(ctxt); | |
45 return; | |
46 } | |
47 | |
48 if (nargs == 2) { | |
49 delimiters = xmlXPathPopString(ctxt); | |
50 if (xmlXPathCheckError(ctxt)) | |
51 return; | |
52 } else { | |
53 delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); | |
54 } | |
55 if (delimiters == NULL) | |
56 return; | |
57 | |
58 str = xmlXPathPopString(ctxt); | |
59 if (xmlXPathCheckError(ctxt) || (str == NULL)) { | |
60 xmlFree(delimiters); | |
61 return; | |
62 } | |
63 | |
64 /* Return a result tree fragment */ | |
65 tctxt = xsltXPathGetTransformContext(ctxt); | |
66 if (tctxt == NULL) { | |
67 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
68 "exslt:tokenize : internal error tctxt == NULL\n"); | |
69 goto fail; | |
70 } | |
71 | |
72 container = xsltCreateRVT(tctxt); | |
73 if (container != NULL) { | |
74 xsltRegisterLocalRVT(tctxt, container); | |
75 ret = xmlXPathNewNodeSet(NULL); | |
76 if (ret != NULL) { | |
77 for (cur = str, token = str; *cur != 0; cur += clen) { | |
78 clen = xmlUTF8Size(cur); | |
79 if (*delimiters == 0) { /* empty string case */ | |
80 xmlChar ctmp; | |
81 ctmp = *(cur+clen); | |
82 *(cur+clen) = 0; | |
83 node = xmlNewDocRawNode(container, NULL, | |
84 (const xmlChar *) "token", cur); | |
85 xmlAddChild((xmlNodePtr) container, node); | |
86 xmlXPathNodeSetAddUnique(ret->nodesetval, node); | |
87 *(cur+clen) = ctmp; /* restore the changed byte */ | |
88 token = cur + clen; | |
89 } else for (delimiter = delimiters; *delimiter != 0; | |
90 delimiter += xmlUTF8Size(delimiter)) { | |
91 if (!xmlUTF8Charcmp(cur, delimiter)) { | |
92 if (cur == token) { | |
93 /* discard empty tokens */ | |
94 token = cur + clen; | |
95 break; | |
96 } | |
97 *cur = 0; /* terminate the token */ | |
98 node = xmlNewDocRawNode(container, NULL, | |
99 (const xmlChar *) "token", token); | |
100 xmlAddChild((xmlNodePtr) container, node); | |
101 xmlXPathNodeSetAddUnique(ret->nodesetval, node); | |
102 *cur = *delimiter; /* restore the changed byte */ | |
103 token = cur + clen; | |
104 break; | |
105 } | |
106 } | |
107 } | |
108 if (token != cur) { | |
109 node = xmlNewDocRawNode(container, NULL, | |
110 (const xmlChar *) "token", token); | |
111 xmlAddChild((xmlNodePtr) container, node); | |
112 xmlXPathNodeSetAddUnique(ret->nodesetval, node); | |
113 } | |
114 } | |
115 } | |
116 | |
117 fail: | |
118 if (str != NULL) | |
119 xmlFree(str); | |
120 if (delimiters != NULL) | |
121 xmlFree(delimiters); | |
122 if (ret != NULL) | |
123 valuePush(ctxt, ret); | |
124 else | |
125 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); | |
126 } | |
127 | |
128 /** | |
129 * exsltStrSplitFunction: | |
130 * @ctxt: an XPath parser context | |
131 * @nargs: the number of arguments | |
132 * | |
133 * Splits up a string on a delimiting string and returns a node set of token | |
134 * elements, each containing one token from the string. | |
135 */ | |
136 static void | |
137 exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { | |
138 xsltTransformContextPtr tctxt; | |
139 xmlChar *str, *delimiter, *cur; | |
140 const xmlChar *token; | |
141 xmlNodePtr node; | |
142 xmlDocPtr container; | |
143 xmlXPathObjectPtr ret = NULL; | |
144 int delimiterLength; | |
145 | |
146 if ((nargs < 1) || (nargs > 2)) { | |
147 xmlXPathSetArityError(ctxt); | |
148 return; | |
149 } | |
150 | |
151 if (nargs == 2) { | |
152 delimiter = xmlXPathPopString(ctxt); | |
153 if (xmlXPathCheckError(ctxt)) | |
154 return; | |
155 } else { | |
156 delimiter = xmlStrdup((const xmlChar *) " "); | |
157 } | |
158 if (delimiter == NULL) | |
159 return; | |
160 delimiterLength = xmlStrlen (delimiter); | |
161 | |
162 str = xmlXPathPopString(ctxt); | |
163 if (xmlXPathCheckError(ctxt) || (str == NULL)) { | |
164 xmlFree(delimiter); | |
165 return; | |
166 } | |
167 | |
168 /* Return a result tree fragment */ | |
169 tctxt = xsltXPathGetTransformContext(ctxt); | |
170 if (tctxt == NULL) { | |
171 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, | |
172 "exslt:tokenize : internal error tctxt == NULL\n"); | |
173 goto fail; | |
174 } | |
175 | |
176 /* | |
177 * OPTIMIZE TODO: We are creating an xmlDoc for every split! | |
178 */ | |
179 container = xsltCreateRVT(tctxt); | |
180 if (container != NULL) { | |
181 xsltRegisterLocalRVT(tctxt, container); | |
182 ret = xmlXPathNewNodeSet(NULL); | |
183 if (ret != NULL) { | |
184 for (cur = str, token = str; *cur != 0; cur++) { | |
185 if (delimiterLength == 0) { | |
186 if (cur != token) { | |
187 xmlChar tmp = *cur; | |
188 *cur = 0; | |
189 node = xmlNewDocRawNode(container, NULL, | |
190 (const xmlChar *) "token", token); | |
191 xmlAddChild((xmlNodePtr) container, node); | |
192 xmlXPathNodeSetAddUnique(ret->nodesetval, node); | |
193 *cur = tmp; | |
194 token++; | |
195 } | |
196 } | |
197 else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) { | |
198 if (cur == token) { | |
199 /* discard empty tokens */ | |
200 cur = cur + delimiterLength - 1; | |
201 token = cur + 1; | |
202 continue; | |
203 } | |
204 *cur = 0; | |
205 node = xmlNewDocRawNode(container, NULL, | |
206 (const xmlChar *) "token", token); | |
207 xmlAddChild((xmlNodePtr) container, node); | |
208 xmlXPathNodeSetAddUnique(ret->nodesetval, node); | |
209 *cur = *delimiter; | |
210 cur = cur + delimiterLength - 1; | |
211 token = cur + 1; | |
212 } | |
213 } | |
214 if (token != cur) { | |
215 node = xmlNewDocRawNode(container, NULL, | |
216 (const xmlChar *) "token", token); | |
217 xmlAddChild((xmlNodePtr) container, node); | |
218 xmlXPathNodeSetAddUnique(ret->nodesetval, node); | |
219 } | |
220 } | |
221 } | |
222 | |
223 fail: | |
224 if (str != NULL) | |
225 xmlFree(str); | |
226 if (delimiter != NULL) | |
227 xmlFree(delimiter); | |
228 if (ret != NULL) | |
229 valuePush(ctxt, ret); | |
230 else | |
231 valuePush(ctxt, xmlXPathNewNodeSet(NULL)); | |
232 } | |
233 | |
234 /** | |
235 * exsltStrEncodeUriFunction: | |
236 * @ctxt: an XPath parser context | |
237 * @nargs: the number of arguments | |
238 * | |
239 * URI-Escapes a string | |
240 */ | |
241 static void | |
242 exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
243 int escape_all = 1, str_len = 0; | |
244 xmlChar *str = NULL, *ret = NULL, *tmp; | |
245 | |
246 if ((nargs < 2) || (nargs > 3)) { | |
247 xmlXPathSetArityError(ctxt); | |
248 return; | |
249 } | |
250 | |
251 if (nargs >= 3) { | |
252 /* check for UTF-8 if encoding was explicitly given; | |
253 we don't support anything else yet */ | |
254 tmp = xmlXPathPopString(ctxt); | |
255 if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp))
{ | |
256 xmlXPathReturnEmptyString(ctxt); | |
257 xmlFree(tmp); | |
258 return; | |
259 } | |
260 xmlFree(tmp); | |
261 } | |
262 | |
263 escape_all = xmlXPathPopBoolean(ctxt); | |
264 | |
265 str = xmlXPathPopString(ctxt); | |
266 str_len = xmlUTF8Strlen(str); | |
267 | |
268 if (str_len == 0) { | |
269 xmlXPathReturnEmptyString(ctxt); | |
270 xmlFree(str); | |
271 return; | |
272 } | |
273 | |
274 ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'(
);/?:@&=+$,[]")); | |
275 xmlXPathReturnString(ctxt, ret); | |
276 | |
277 if (str != NULL) | |
278 xmlFree(str); | |
279 } | |
280 | |
281 /** | |
282 * exsltStrDecodeUriFunction: | |
283 * @ctxt: an XPath parser context | |
284 * @nargs: the number of arguments | |
285 * | |
286 * reverses URI-Escaping of a string | |
287 */ | |
288 static void | |
289 exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
290 int str_len = 0; | |
291 xmlChar *str = NULL, *ret = NULL, *tmp; | |
292 | |
293 if ((nargs < 1) || (nargs > 2)) { | |
294 xmlXPathSetArityError(ctxt); | |
295 return; | |
296 } | |
297 | |
298 if (nargs >= 2) { | |
299 /* check for UTF-8 if encoding was explicitly given; | |
300 we don't support anything else yet */ | |
301 tmp = xmlXPathPopString(ctxt); | |
302 if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp))
{ | |
303 xmlXPathReturnEmptyString(ctxt); | |
304 xmlFree(tmp); | |
305 return; | |
306 } | |
307 xmlFree(tmp); | |
308 } | |
309 | |
310 str = xmlXPathPopString(ctxt); | |
311 str_len = xmlUTF8Strlen(str); | |
312 | |
313 if (str_len == 0) { | |
314 xmlXPathReturnEmptyString(ctxt); | |
315 xmlFree(str); | |
316 return; | |
317 } | |
318 | |
319 ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL); | |
320 if (!xmlCheckUTF8(ret)) { | |
321 /* FIXME: instead of throwing away the whole URI, we should | |
322 only discard the invalid sequence(s). How to do that? */ | |
323 xmlXPathReturnEmptyString(ctxt); | |
324 xmlFree(str); | |
325 xmlFree(ret); | |
326 return; | |
327 } | |
328 | |
329 xmlXPathReturnString(ctxt, ret); | |
330 | |
331 if (str != NULL) | |
332 xmlFree(str); | |
333 } | |
334 | |
335 /** | |
336 * exsltStrPaddingFunction: | |
337 * @ctxt: an XPath parser context | |
338 * @nargs: the number of arguments | |
339 * | |
340 * Creates a padding string of a certain length. | |
341 */ | |
342 static void | |
343 exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
344 int number, str_len = 0, str_size = 0; | |
345 xmlChar *str = NULL, *ret = NULL; | |
346 | |
347 if ((nargs < 1) || (nargs > 2)) { | |
348 xmlXPathSetArityError(ctxt); | |
349 return; | |
350 } | |
351 | |
352 if (nargs == 2) { | |
353 str = xmlXPathPopString(ctxt); | |
354 str_len = xmlUTF8Strlen(str); | |
355 str_size = xmlStrlen(str); | |
356 } | |
357 if (str_len == 0) { | |
358 if (str != NULL) xmlFree(str); | |
359 str = xmlStrdup((const xmlChar *) " "); | |
360 str_len = 1; | |
361 str_size = 1; | |
362 } | |
363 | |
364 number = (int) xmlXPathPopNumber(ctxt); | |
365 | |
366 if (number <= 0) { | |
367 xmlXPathReturnEmptyString(ctxt); | |
368 xmlFree(str); | |
369 return; | |
370 } | |
371 | |
372 while (number >= str_len) { | |
373 ret = xmlStrncat(ret, str, str_size); | |
374 number -= str_len; | |
375 } | |
376 if (number > 0) { | |
377 str_size = xmlUTF8Strsize(str, number); | |
378 ret = xmlStrncat(ret, str, str_size); | |
379 } | |
380 | |
381 xmlXPathReturnString(ctxt, ret); | |
382 | |
383 if (str != NULL) | |
384 xmlFree(str); | |
385 } | |
386 | |
387 /** | |
388 * exsltStrAlignFunction: | |
389 * @ctxt: an XPath parser context | |
390 * @nargs: the number of arguments | |
391 * | |
392 * Aligns a string within another string. | |
393 */ | |
394 static void | |
395 exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
396 xmlChar *str, *padding, *alignment, *ret; | |
397 int str_l, padding_l; | |
398 | |
399 if ((nargs < 2) || (nargs > 3)) { | |
400 xmlXPathSetArityError(ctxt); | |
401 return; | |
402 } | |
403 | |
404 if (nargs == 3) | |
405 alignment = xmlXPathPopString(ctxt); | |
406 else | |
407 alignment = NULL; | |
408 | |
409 padding = xmlXPathPopString(ctxt); | |
410 str = xmlXPathPopString(ctxt); | |
411 | |
412 str_l = xmlUTF8Strlen (str); | |
413 padding_l = xmlUTF8Strlen (padding); | |
414 | |
415 if (str_l == padding_l) { | |
416 xmlXPathReturnString (ctxt, str); | |
417 xmlFree(padding); | |
418 xmlFree(alignment); | |
419 return; | |
420 } | |
421 | |
422 if (str_l > padding_l) { | |
423 ret = xmlUTF8Strndup (str, padding_l); | |
424 } else { | |
425 if (xmlStrEqual(alignment, (const xmlChar *) "right")) { | |
426 ret = xmlUTF8Strndup (padding, padding_l - str_l); | |
427 ret = xmlStrcat (ret, str); | |
428 } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) { | |
429 int left = (padding_l - str_l) / 2; | |
430 int right_start; | |
431 | |
432 ret = xmlUTF8Strndup (padding, left); | |
433 ret = xmlStrcat (ret, str); | |
434 | |
435 right_start = xmlUTF8Strsize (padding, left + str_l); | |
436 ret = xmlStrcat (ret, padding + right_start); | |
437 } else { | |
438 int str_s; | |
439 | |
440 str_s = xmlUTF8Strsize(padding, str_l); | |
441 ret = xmlStrdup (str); | |
442 ret = xmlStrcat (ret, padding + str_s); | |
443 } | |
444 } | |
445 | |
446 xmlXPathReturnString (ctxt, ret); | |
447 | |
448 xmlFree(str); | |
449 xmlFree(padding); | |
450 xmlFree(alignment); | |
451 } | |
452 | |
453 /** | |
454 * exsltStrConcatFunction: | |
455 * @ctxt: an XPath parser context | |
456 * @nargs: the number of arguments | |
457 * | |
458 * Takes a node set and returns the concatenation of the string values | |
459 * of the nodes in that node set. If the node set is empty, it | |
460 * returns an empty string. | |
461 */ | |
462 static void | |
463 exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
464 xmlXPathObjectPtr obj; | |
465 xmlChar *ret = NULL; | |
466 int i; | |
467 | |
468 if (nargs != 1) { | |
469 xmlXPathSetArityError(ctxt); | |
470 return; | |
471 } | |
472 | |
473 if (!xmlXPathStackIsNodeSet(ctxt)) { | |
474 xmlXPathSetTypeError(ctxt); | |
475 return; | |
476 } | |
477 | |
478 obj = valuePop (ctxt); | |
479 | |
480 if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) { | |
481 xmlXPathReturnEmptyString(ctxt); | |
482 return; | |
483 } | |
484 | |
485 for (i = 0; i < obj->nodesetval->nodeNr; i++) { | |
486 xmlChar *tmp; | |
487 tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); | |
488 | |
489 ret = xmlStrcat (ret, tmp); | |
490 | |
491 xmlFree(tmp); | |
492 } | |
493 | |
494 xmlXPathFreeObject (obj); | |
495 | |
496 xmlXPathReturnString(ctxt, ret); | |
497 } | |
498 | |
499 /** | |
500 * exsltStrReturnString: | |
501 * @ctxt: an XPath parser context | |
502 * @str: a string | |
503 * @len: length of string | |
504 * | |
505 * Returns a string as a node set. | |
506 */ | |
507 static int | |
508 exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str, | |
509 int len) | |
510 { | |
511 xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); | |
512 xmlDocPtr container; | |
513 xmlNodePtr text_node; | |
514 xmlXPathObjectPtr ret; | |
515 | |
516 container = xsltCreateRVT(tctxt); | |
517 if (container == NULL) { | |
518 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); | |
519 return(-1); | |
520 } | |
521 xsltRegisterLocalRVT(tctxt, container); | |
522 | |
523 text_node = xmlNewTextLen(str, len); | |
524 if (text_node == NULL) { | |
525 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); | |
526 return(-1); | |
527 } | |
528 xmlAddChild((xmlNodePtr) container, text_node); | |
529 | |
530 ret = xmlXPathNewNodeSet(text_node); | |
531 if (ret == NULL) { | |
532 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); | |
533 return(-1); | |
534 } | |
535 | |
536 valuePush(ctxt, ret); | |
537 | |
538 return(0); | |
539 } | |
540 | |
541 /** | |
542 * exsltStrReplaceFunction: | |
543 * @ctxt: an XPath parser context | |
544 * @nargs: the number of arguments | |
545 * | |
546 * Takes a string, and two node sets and returns the string with all strings in | |
547 * the first node set replaced by all strings in the second node set. | |
548 */ | |
549 static void | |
550 exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) { | |
551 int i, i_empty, n, slen0, rlen0, *slen, *rlen; | |
552 void *mem = NULL; | |
553 const xmlChar *src, *start; | |
554 xmlChar *string, *search_str = NULL, *replace_str = NULL; | |
555 xmlChar **search, **replace; | |
556 xmlNodeSetPtr search_set = NULL, replace_set = NULL; | |
557 xmlBufferPtr buf; | |
558 | |
559 if (nargs != 3) { | |
560 xmlXPathSetArityError(ctxt); | |
561 return; | |
562 } | |
563 | |
564 /* get replace argument */ | |
565 | |
566 if (!xmlXPathStackIsNodeSet(ctxt)) | |
567 replace_str = xmlXPathPopString(ctxt); | |
568 else | |
569 replace_set = xmlXPathPopNodeSet(ctxt); | |
570 | |
571 if (xmlXPathCheckError(ctxt)) | |
572 goto fail_replace; | |
573 | |
574 /* get search argument */ | |
575 | |
576 if (!xmlXPathStackIsNodeSet(ctxt)) { | |
577 search_str = xmlXPathPopString(ctxt); | |
578 n = 1; | |
579 } | |
580 else { | |
581 search_set = xmlXPathPopNodeSet(ctxt); | |
582 n = search_set != NULL ? search_set->nodeNr : 0; | |
583 } | |
584 | |
585 if (xmlXPathCheckError(ctxt)) | |
586 goto fail_search; | |
587 | |
588 /* get string argument */ | |
589 | |
590 string = xmlXPathPopString(ctxt); | |
591 if (xmlXPathCheckError(ctxt)) | |
592 goto fail_string; | |
593 | |
594 /* check for empty search node list */ | |
595 | |
596 if (n <= 0) { | |
597 exsltStrReturnString(ctxt, string, xmlStrlen(string)); | |
598 goto done_empty_search; | |
599 } | |
600 | |
601 /* allocate memory for string pointer and length arrays */ | |
602 | |
603 if (n == 1) { | |
604 search = &search_str; | |
605 replace = &replace_str; | |
606 slen = &slen0; | |
607 rlen = &rlen0; | |
608 } | |
609 else { | |
610 mem = xmlMalloc(2 * n * (sizeof(const xmlChar *) + sizeof(int))); | |
611 if (mem == NULL) { | |
612 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); | |
613 goto fail_malloc; | |
614 } | |
615 search = (xmlChar **) mem; | |
616 replace = search + n; | |
617 slen = (int *) (replace + n); | |
618 rlen = slen + n; | |
619 } | |
620 | |
621 /* process arguments */ | |
622 | |
623 i_empty = -1; | |
624 | |
625 for (i=0; i<n; ++i) { | |
626 if (search_set != NULL) { | |
627 search[i] = xmlXPathCastNodeToString(search_set->nodeTab[i]); | |
628 if (search[i] == NULL) { | |
629 n = i; | |
630 goto fail_process_args; | |
631 } | |
632 } | |
633 | |
634 slen[i] = xmlStrlen(search[i]); | |
635 if (i_empty < 0 && slen[i] == 0) | |
636 i_empty = i; | |
637 | |
638 if (replace_set != NULL) { | |
639 if (i < replace_set->nodeNr) { | |
640 replace[i] = xmlXPathCastNodeToString(replace_set->nodeTab[i]); | |
641 if (replace[i] == NULL) { | |
642 n = i + 1; | |
643 goto fail_process_args; | |
644 } | |
645 } | |
646 else | |
647 replace[i] = NULL; | |
648 } | |
649 else { | |
650 if (i == 0) | |
651 replace[i] = replace_str; | |
652 else | |
653 replace[i] = NULL; | |
654 } | |
655 | |
656 if (replace[i] == NULL) | |
657 rlen[i] = 0; | |
658 else | |
659 rlen[i] = xmlStrlen(replace[i]); | |
660 } | |
661 | |
662 if (i_empty >= 0 && rlen[i_empty] == 0) | |
663 i_empty = -1; | |
664 | |
665 /* replace operation */ | |
666 | |
667 buf = xmlBufferCreate(); | |
668 if (buf == NULL) { | |
669 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); | |
670 goto fail_buffer; | |
671 } | |
672 src = string; | |
673 start = string; | |
674 | |
675 while (*src != 0) { | |
676 int max_len = 0, i_match = 0; | |
677 | |
678 for (i=0; i<n; ++i) { | |
679 if (*src == search[i][0] && | |
680 slen[i] > max_len && | |
681 xmlStrncmp(src, search[i], slen[i]) == 0) | |
682 { | |
683 i_match = i; | |
684 max_len = slen[i]; | |
685 } | |
686 } | |
687 | |
688 if (max_len == 0) { | |
689 if (i_empty >= 0 && start < src) { | |
690 if (xmlBufferAdd(buf, start, src - start) || | |
691 xmlBufferAdd(buf, replace[i_empty], rlen[i_empty])) | |
692 { | |
693 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); | |
694 goto fail_buffer_add; | |
695 } | |
696 start = src; | |
697 } | |
698 | |
699 src += xmlUTF8Size(src); | |
700 } | |
701 else { | |
702 if ((start < src && | |
703 xmlBufferAdd(buf, start, src - start)) || | |
704 (rlen[i_match] && | |
705 xmlBufferAdd(buf, replace[i_match], rlen[i_match]))) | |
706 { | |
707 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); | |
708 goto fail_buffer_add; | |
709 } | |
710 | |
711 src += slen[i_match]; | |
712 start = src; | |
713 } | |
714 } | |
715 | |
716 if (start < src && xmlBufferAdd(buf, start, src - start)) { | |
717 xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); | |
718 goto fail_buffer_add; | |
719 } | |
720 | |
721 /* create result node set */ | |
722 | |
723 exsltStrReturnString(ctxt, xmlBufferContent(buf), xmlBufferLength(buf)); | |
724 | |
725 /* clean up */ | |
726 | |
727 fail_buffer_add: | |
728 xmlBufferFree(buf); | |
729 | |
730 fail_buffer: | |
731 fail_process_args: | |
732 if (search_set != NULL) { | |
733 for (i=0; i<n; ++i) | |
734 xmlFree(search[i]); | |
735 } | |
736 if (replace_set != NULL) { | |
737 for (i=0; i<n; ++i) { | |
738 if (replace[i] != NULL) | |
739 xmlFree(replace[i]); | |
740 } | |
741 } | |
742 | |
743 if (mem != NULL) | |
744 xmlFree(mem); | |
745 | |
746 fail_malloc: | |
747 done_empty_search: | |
748 xmlFree(string); | |
749 | |
750 fail_string: | |
751 if (search_set != NULL) | |
752 xmlXPathFreeNodeSet(search_set); | |
753 else | |
754 xmlFree(search_str); | |
755 | |
756 fail_search: | |
757 if (replace_set != NULL) | |
758 xmlXPathFreeNodeSet(replace_set); | |
759 else | |
760 xmlFree(replace_str); | |
761 | |
762 fail_replace: | |
763 return; | |
764 } | |
765 | |
766 /** | |
767 * exsltStrRegister: | |
768 * | |
769 * Registers the EXSLT - Strings module | |
770 */ | |
771 | |
772 void | |
773 exsltStrRegister (void) { | |
774 xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize", | |
775 EXSLT_STRINGS_NAMESPACE, | |
776 exsltStrTokenizeFunction); | |
777 xsltRegisterExtModuleFunction ((const xmlChar *) "split", | |
778 EXSLT_STRINGS_NAMESPACE, | |
779 exsltStrSplitFunction); | |
780 xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri", | |
781 EXSLT_STRINGS_NAMESPACE, | |
782 exsltStrEncodeUriFunction); | |
783 xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri", | |
784 EXSLT_STRINGS_NAMESPACE, | |
785 exsltStrDecodeUriFunction); | |
786 xsltRegisterExtModuleFunction ((const xmlChar *) "padding", | |
787 EXSLT_STRINGS_NAMESPACE, | |
788 exsltStrPaddingFunction); | |
789 xsltRegisterExtModuleFunction ((const xmlChar *) "align", | |
790 EXSLT_STRINGS_NAMESPACE, | |
791 exsltStrAlignFunction); | |
792 xsltRegisterExtModuleFunction ((const xmlChar *) "concat", | |
793 EXSLT_STRINGS_NAMESPACE, | |
794 exsltStrConcatFunction); | |
795 xsltRegisterExtModuleFunction ((const xmlChar *) "replace", | |
796 EXSLT_STRINGS_NAMESPACE, | |
797 exsltStrReplaceFunction); | |
798 } | |
799 | |
800 /** | |
801 * exsltStrXpathCtxtRegister: | |
802 * | |
803 * Registers the EXSLT - Strings module for use outside XSLT | |
804 */ | |
805 int | |
806 exsltStrXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix) | |
807 { | |
808 if (ctxt | |
809 && prefix | |
810 && !xmlXPathRegisterNs(ctxt, | |
811 prefix, | |
812 (const xmlChar *) EXSLT_STRINGS_NAMESPACE) | |
813 && !xmlXPathRegisterFuncNS(ctxt, | |
814 (const xmlChar *) "encode-uri", | |
815 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, | |
816 exsltStrEncodeUriFunction) | |
817 && !xmlXPathRegisterFuncNS(ctxt, | |
818 (const xmlChar *) "decode-uri", | |
819 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, | |
820 exsltStrDecodeUriFunction) | |
821 && !xmlXPathRegisterFuncNS(ctxt, | |
822 (const xmlChar *) "padding", | |
823 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, | |
824 exsltStrPaddingFunction) | |
825 && !xmlXPathRegisterFuncNS(ctxt, | |
826 (const xmlChar *) "align", | |
827 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, | |
828 exsltStrAlignFunction) | |
829 && !xmlXPathRegisterFuncNS(ctxt, | |
830 (const xmlChar *) "concat", | |
831 (const xmlChar *) EXSLT_STRINGS_NAMESPACE, | |
832 exsltStrConcatFunction)) { | |
833 return 0; | |
834 } | |
835 return -1; | |
836 } | |
OLD | NEW |