VirtualBox

source: vbox/trunk/src/libs/libxslt-1.1.22/libexslt/strings.c@ 7296

Last change on this file since 7296 was 7296, checked in by vboxsync, 17 years ago

Added libxslt-1.1.22 sources.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 16.9 KB
Line 
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 */
32static void
33exsltStrTokenizeFunction(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
117fail:
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 */
136static void
137exsltStrSplitFunction(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
223fail:
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 */
241static void
242exsltStrEncodeUriFunction (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 */
288static void
289exsltStrDecodeUriFunction (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 */
342static void
343exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
344 int number, str_len = 0;
345 xmlChar *str = NULL, *ret = NULL, *tmp;
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 }
356 if (str_len == 0) {
357 if (str != NULL) xmlFree(str);
358 str = xmlStrdup((const xmlChar *) " ");
359 str_len = 1;
360 }
361
362 number = (int) xmlXPathPopNumber(ctxt);
363
364 if (number <= 0) {
365 xmlXPathReturnEmptyString(ctxt);
366 xmlFree(str);
367 return;
368 }
369
370 while (number >= str_len) {
371 ret = xmlStrncat(ret, str, str_len);
372 number -= str_len;
373 }
374 tmp = xmlUTF8Strndup (str, number);
375 ret = xmlStrcat(ret, tmp);
376 if (tmp != NULL)
377 xmlFree (tmp);
378
379 xmlXPathReturnString(ctxt, ret);
380
381 if (str != NULL)
382 xmlFree(str);
383}
384
385/**
386 * exsltStrAlignFunction:
387 * @ctxt: an XPath parser context
388 * @nargs: the number of arguments
389 *
390 * Aligns a string within another string.
391 */
392static void
393exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {
394 xmlChar *str, *padding, *alignment, *ret;
395 int str_l, padding_l;
396
397 if ((nargs < 2) || (nargs > 3)) {
398 xmlXPathSetArityError(ctxt);
399 return;
400 }
401
402 if (nargs == 3)
403 alignment = xmlXPathPopString(ctxt);
404 else
405 alignment = NULL;
406
407 padding = xmlXPathPopString(ctxt);
408 str = xmlXPathPopString(ctxt);
409
410 str_l = xmlUTF8Strlen (str);
411 padding_l = xmlUTF8Strlen (padding);
412
413 if (str_l == padding_l) {
414 xmlXPathReturnString (ctxt, str);
415 xmlFree(padding);
416 xmlFree(alignment);
417 return;
418 }
419
420 if (str_l > padding_l) {
421 ret = xmlUTF8Strndup (str, padding_l);
422 } else {
423 if (xmlStrEqual(alignment, (const xmlChar *) "right")) {
424 ret = xmlUTF8Strndup (padding, padding_l - str_l);
425 ret = xmlStrcat (ret, str);
426 } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {
427 int left = (padding_l - str_l) / 2;
428 int right_start;
429
430 ret = xmlUTF8Strndup (padding, left);
431 ret = xmlStrcat (ret, str);
432
433 right_start = xmlUTF8Strsize (padding, left + str_l);
434 ret = xmlStrcat (ret, padding + right_start);
435 } else {
436 int str_s;
437
438 str_s = xmlStrlen (str);
439 ret = xmlStrdup (str);
440 ret = xmlStrcat (ret, padding + str_s);
441 }
442 }
443
444 xmlXPathReturnString (ctxt, ret);
445
446 xmlFree(str);
447 xmlFree(padding);
448 xmlFree(alignment);
449}
450
451/**
452 * exsltStrConcatFunction:
453 * @ctxt: an XPath parser context
454 * @nargs: the number of arguments
455 *
456 * Takes a node set and returns the concatenation of the string values
457 * of the nodes in that node set. If the node set is empty, it
458 * returns an empty string.
459 */
460static void
461exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {
462 xmlXPathObjectPtr obj;
463 xmlChar *ret = NULL;
464 int i;
465
466 if (nargs != 1) {
467 xmlXPathSetArityError(ctxt);
468 return;
469 }
470
471 if (!xmlXPathStackIsNodeSet(ctxt)) {
472 xmlXPathSetTypeError(ctxt);
473 return;
474 }
475
476 obj = valuePop (ctxt);
477
478 if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
479 xmlXPathReturnEmptyString(ctxt);
480 return;
481 }
482
483 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
484 xmlChar *tmp;
485 tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
486
487 ret = xmlStrcat (ret, tmp);
488
489 xmlFree(tmp);
490 }
491
492 xmlXPathFreeObject (obj);
493
494 xmlXPathReturnString(ctxt, ret);
495}
496
497/**
498 * exsltStrReplaceInternal:
499 * @str: string to modify
500 * @searchStr: string to find
501 * @replaceStr: string to replace occurrences of searchStr
502 *
503 * Search and replace string function used by exsltStrReplaceFunction
504 */
505static xmlChar*
506exsltStrReplaceInternal(const xmlChar* str, const xmlChar* searchStr,
507 const xmlChar* replaceStr)
508{
509 const xmlChar *curr, *next;
510 xmlChar *ret = NULL;
511 int searchStrSize;
512
513 curr = str;
514 searchStrSize = xmlStrlen(searchStr);
515
516 do {
517 next = xmlStrstr(curr, searchStr);
518 if (next == NULL) {
519 ret = xmlStrcat (ret, curr);
520 break;
521 }
522
523 ret = xmlStrncat (ret, curr, next - curr);
524 ret = xmlStrcat (ret, replaceStr);
525 curr = next + searchStrSize;
526 } while (*curr != 0);
527
528 return ret;
529}
530/**
531 * exsltStrReplaceFunction:
532 * @ctxt: an XPath parser context
533 * @nargs: the number of arguments
534 *
535 * Takes a string, and two node sets and returns the string with all strings in
536 * the first node set replaced by all strings in the second node set.
537 */
538static void
539exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) {
540 xmlChar *str = NULL, *searchStr = NULL, *replaceStr = NULL;
541 xmlNodeSetPtr replaceSet = NULL, searchSet = NULL;
542 xmlChar *ret = NULL, *retSwap = NULL;
543 int i;
544
545 if (nargs != 3) {
546 xmlXPathSetArityError(ctxt);
547 return;
548 }
549
550 /* pull out replace argument */
551 if (!xmlXPathStackIsNodeSet(ctxt)) {
552 replaceStr = xmlXPathPopString(ctxt);
553 }
554 else {
555 replaceSet = xmlXPathPopNodeSet(ctxt);
556 if (xmlXPathCheckError(ctxt)) {
557 xmlXPathSetTypeError(ctxt);
558 goto fail;
559 }
560 }
561
562 /* behavior driven by search argument from here on */
563 if (!xmlXPathStackIsNodeSet(ctxt)) {
564 searchStr = xmlXPathPopString(ctxt);
565 str = xmlXPathPopString(ctxt);
566
567 if (replaceStr == NULL) {
568 xmlXPathSetTypeError(ctxt);
569 goto fail;
570 }
571
572 ret = exsltStrReplaceInternal(str, searchStr, replaceStr);
573 }
574 else {
575 searchSet = xmlXPathPopNodeSet(ctxt);
576 if (searchSet == NULL || xmlXPathCheckError(ctxt)) {
577 xmlXPathSetTypeError(ctxt);
578 goto fail;
579 }
580
581 str = xmlXPathPopString(ctxt);
582 ret = xmlStrdup(str);
583
584 for (i = 0; i < searchSet->nodeNr; i++) {
585
586 searchStr = xmlXPathCastNodeToString(searchSet->nodeTab[i]);
587
588 if (replaceSet != NULL) {
589 replaceStr = NULL;
590 if (i <= replaceSet->nodeNr) {
591 replaceStr = xmlXPathCastNodeToString(replaceSet->nodeTab[i]);
592 }
593
594 retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr);
595
596 if (replaceStr != NULL) {
597 xmlFree(replaceStr);
598 replaceStr = NULL;
599 }
600 }
601 else {
602 retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr);
603 }
604
605 xmlFree(ret);
606 if (searchStr != NULL) {
607 xmlFree(searchStr);
608 searchStr = NULL;
609 }
610
611 ret = retSwap;
612 }
613
614 if (replaceSet != NULL)
615 xmlXPathFreeNodeSet(replaceSet);
616
617 if (searchSet != NULL)
618 xmlXPathFreeNodeSet(searchSet);
619 }
620
621 xmlXPathReturnString(ctxt, ret);
622
623 fail:
624 if (replaceStr != NULL)
625 xmlFree(replaceStr);
626
627 if (searchStr != NULL)
628 xmlFree(searchStr);
629
630 if (str != NULL)
631 xmlFree(str);
632}
633
634/**
635 * exsltStrRegister:
636 *
637 * Registers the EXSLT - Strings module
638 */
639
640void
641exsltStrRegister (void) {
642 xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
643 EXSLT_STRINGS_NAMESPACE,
644 exsltStrTokenizeFunction);
645 xsltRegisterExtModuleFunction ((const xmlChar *) "split",
646 EXSLT_STRINGS_NAMESPACE,
647 exsltStrSplitFunction);
648 xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri",
649 EXSLT_STRINGS_NAMESPACE,
650 exsltStrEncodeUriFunction);
651 xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri",
652 EXSLT_STRINGS_NAMESPACE,
653 exsltStrDecodeUriFunction);
654 xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
655 EXSLT_STRINGS_NAMESPACE,
656 exsltStrPaddingFunction);
657 xsltRegisterExtModuleFunction ((const xmlChar *) "align",
658 EXSLT_STRINGS_NAMESPACE,
659 exsltStrAlignFunction);
660 xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
661 EXSLT_STRINGS_NAMESPACE,
662 exsltStrConcatFunction);
663 xsltRegisterExtModuleFunction ((const xmlChar *) "replace",
664 EXSLT_STRINGS_NAMESPACE,
665 exsltStrReplaceFunction);
666}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette