VirtualBox

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

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

Added vboxconfig.h for linux builds.

  • 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#elif defined(VBOX)
7#include "vboxconfig.h"
8#else
9#include "config.h"
10#endif
11
12#include <libxml/tree.h>
13#include <libxml/xpath.h>
14#include <libxml/xpathInternals.h>
15#include <libxml/parser.h>
16#include <libxml/encoding.h>
17#include <libxml/uri.h>
18
19#include <libxslt/xsltconfig.h>
20#include <libxslt/xsltutils.h>
21#include <libxslt/xsltInternals.h>
22#include <libxslt/extensions.h>
23
24#include "exslt.h"
25
26/**
27 * exsltStrTokenizeFunction:
28 * @ctxt: an XPath parser context
29 * @nargs: the number of arguments
30 *
31 * Splits up a string on the characters of the delimiter string and returns a
32 * node set of token elements, each containing one token from the string.
33 */
34static void
35exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs)
36{
37 xsltTransformContextPtr tctxt;
38 xmlChar *str, *delimiters, *cur;
39 const xmlChar *token, *delimiter;
40 xmlNodePtr node;
41 xmlDocPtr container;
42 xmlXPathObjectPtr ret = NULL;
43 int clen;
44
45 if ((nargs < 1) || (nargs > 2)) {
46 xmlXPathSetArityError(ctxt);
47 return;
48 }
49
50 if (nargs == 2) {
51 delimiters = xmlXPathPopString(ctxt);
52 if (xmlXPathCheckError(ctxt))
53 return;
54 } else {
55 delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");
56 }
57 if (delimiters == NULL)
58 return;
59
60 str = xmlXPathPopString(ctxt);
61 if (xmlXPathCheckError(ctxt) || (str == NULL)) {
62 xmlFree(delimiters);
63 return;
64 }
65
66 /* Return a result tree fragment */
67 tctxt = xsltXPathGetTransformContext(ctxt);
68 if (tctxt == NULL) {
69 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
70 "exslt:tokenize : internal error tctxt == NULL\n");
71 goto fail;
72 }
73
74 container = xsltCreateRVT(tctxt);
75 if (container != NULL) {
76 xsltRegisterLocalRVT(tctxt, container);
77 ret = xmlXPathNewNodeSet(NULL);
78 if (ret != NULL) {
79 for (cur = str, token = str; *cur != 0; cur += clen) {
80 clen = xmlUTF8Size(cur);
81 if (*delimiters == 0) { /* empty string case */
82 xmlChar ctmp;
83 ctmp = *(cur+clen);
84 *(cur+clen) = 0;
85 node = xmlNewDocRawNode(container, NULL,
86 (const xmlChar *) "token", cur);
87 xmlAddChild((xmlNodePtr) container, node);
88 xmlXPathNodeSetAddUnique(ret->nodesetval, node);
89 *(cur+clen) = ctmp; /* restore the changed byte */
90 token = cur + clen;
91 } else for (delimiter = delimiters; *delimiter != 0;
92 delimiter += xmlUTF8Size(delimiter)) {
93 if (!xmlUTF8Charcmp(cur, delimiter)) {
94 if (cur == token) {
95 /* discard empty tokens */
96 token = cur + clen;
97 break;
98 }
99 *cur = 0; /* terminate the token */
100 node = xmlNewDocRawNode(container, NULL,
101 (const xmlChar *) "token", token);
102 xmlAddChild((xmlNodePtr) container, node);
103 xmlXPathNodeSetAddUnique(ret->nodesetval, node);
104 *cur = *delimiter; /* restore the changed byte */
105 token = cur + clen;
106 break;
107 }
108 }
109 }
110 if (token != cur) {
111 node = xmlNewDocRawNode(container, NULL,
112 (const xmlChar *) "token", token);
113 xmlAddChild((xmlNodePtr) container, node);
114 xmlXPathNodeSetAddUnique(ret->nodesetval, node);
115 }
116 }
117 }
118
119fail:
120 if (str != NULL)
121 xmlFree(str);
122 if (delimiters != NULL)
123 xmlFree(delimiters);
124 if (ret != NULL)
125 valuePush(ctxt, ret);
126 else
127 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
128}
129
130/**
131 * exsltStrSplitFunction:
132 * @ctxt: an XPath parser context
133 * @nargs: the number of arguments
134 *
135 * Splits up a string on a delimiting string and returns a node set of token
136 * elements, each containing one token from the string.
137 */
138static void
139exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) {
140 xsltTransformContextPtr tctxt;
141 xmlChar *str, *delimiter, *cur;
142 const xmlChar *token;
143 xmlNodePtr node;
144 xmlDocPtr container;
145 xmlXPathObjectPtr ret = NULL;
146 int delimiterLength;
147
148 if ((nargs < 1) || (nargs > 2)) {
149 xmlXPathSetArityError(ctxt);
150 return;
151 }
152
153 if (nargs == 2) {
154 delimiter = xmlXPathPopString(ctxt);
155 if (xmlXPathCheckError(ctxt))
156 return;
157 } else {
158 delimiter = xmlStrdup((const xmlChar *) " ");
159 }
160 if (delimiter == NULL)
161 return;
162 delimiterLength = xmlStrlen (delimiter);
163
164 str = xmlXPathPopString(ctxt);
165 if (xmlXPathCheckError(ctxt) || (str == NULL)) {
166 xmlFree(delimiter);
167 return;
168 }
169
170 /* Return a result tree fragment */
171 tctxt = xsltXPathGetTransformContext(ctxt);
172 if (tctxt == NULL) {
173 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
174 "exslt:tokenize : internal error tctxt == NULL\n");
175 goto fail;
176 }
177
178 /*
179 * OPTIMIZE TODO: We are creating an xmlDoc for every split!
180 */
181 container = xsltCreateRVT(tctxt);
182 if (container != NULL) {
183 xsltRegisterLocalRVT(tctxt, container);
184 ret = xmlXPathNewNodeSet(NULL);
185 if (ret != NULL) {
186 for (cur = str, token = str; *cur != 0; cur++) {
187 if (delimiterLength == 0) {
188 if (cur != token) {
189 xmlChar tmp = *cur;
190 *cur = 0;
191 node = xmlNewDocRawNode(container, NULL,
192 (const xmlChar *) "token", token);
193 xmlAddChild((xmlNodePtr) container, node);
194 xmlXPathNodeSetAddUnique(ret->nodesetval, node);
195 *cur = tmp;
196 token++;
197 }
198 }
199 else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) {
200 if (cur == token) {
201 /* discard empty tokens */
202 cur = cur + delimiterLength - 1;
203 token = cur + 1;
204 continue;
205 }
206 *cur = 0;
207 node = xmlNewDocRawNode(container, NULL,
208 (const xmlChar *) "token", token);
209 xmlAddChild((xmlNodePtr) container, node);
210 xmlXPathNodeSetAddUnique(ret->nodesetval, node);
211 *cur = *delimiter;
212 cur = cur + delimiterLength - 1;
213 token = cur + 1;
214 }
215 }
216 if (token != cur) {
217 node = xmlNewDocRawNode(container, NULL,
218 (const xmlChar *) "token", token);
219 xmlAddChild((xmlNodePtr) container, node);
220 xmlXPathNodeSetAddUnique(ret->nodesetval, node);
221 }
222 }
223 }
224
225fail:
226 if (str != NULL)
227 xmlFree(str);
228 if (delimiter != NULL)
229 xmlFree(delimiter);
230 if (ret != NULL)
231 valuePush(ctxt, ret);
232 else
233 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
234}
235
236/**
237 * exsltStrEncodeUriFunction:
238 * @ctxt: an XPath parser context
239 * @nargs: the number of arguments
240 *
241 * URI-Escapes a string
242 */
243static void
244exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
245 int escape_all = 1, str_len = 0;
246 xmlChar *str = NULL, *ret = NULL, *tmp;
247
248 if ((nargs < 2) || (nargs > 3)) {
249 xmlXPathSetArityError(ctxt);
250 return;
251 }
252
253 if (nargs >= 3) {
254 /* check for UTF-8 if encoding was explicitly given;
255 we don't support anything else yet */
256 tmp = xmlXPathPopString(ctxt);
257 if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
258 xmlXPathReturnEmptyString(ctxt);
259 xmlFree(tmp);
260 return;
261 }
262 xmlFree(tmp);
263 }
264
265 escape_all = xmlXPathPopBoolean(ctxt);
266
267 str = xmlXPathPopString(ctxt);
268 str_len = xmlUTF8Strlen(str);
269
270 if (str_len == 0) {
271 xmlXPathReturnEmptyString(ctxt);
272 xmlFree(str);
273 return;
274 }
275
276 ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]"));
277 xmlXPathReturnString(ctxt, ret);
278
279 if (str != NULL)
280 xmlFree(str);
281}
282
283/**
284 * exsltStrDecodeUriFunction:
285 * @ctxt: an XPath parser context
286 * @nargs: the number of arguments
287 *
288 * reverses URI-Escaping of a string
289 */
290static void
291exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) {
292 int str_len = 0;
293 xmlChar *str = NULL, *ret = NULL, *tmp;
294
295 if ((nargs < 1) || (nargs > 2)) {
296 xmlXPathSetArityError(ctxt);
297 return;
298 }
299
300 if (nargs >= 2) {
301 /* check for UTF-8 if encoding was explicitly given;
302 we don't support anything else yet */
303 tmp = xmlXPathPopString(ctxt);
304 if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) {
305 xmlXPathReturnEmptyString(ctxt);
306 xmlFree(tmp);
307 return;
308 }
309 xmlFree(tmp);
310 }
311
312 str = xmlXPathPopString(ctxt);
313 str_len = xmlUTF8Strlen(str);
314
315 if (str_len == 0) {
316 xmlXPathReturnEmptyString(ctxt);
317 xmlFree(str);
318 return;
319 }
320
321 ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL);
322 if (!xmlCheckUTF8(ret)) {
323 /* FIXME: instead of throwing away the whole URI, we should
324 only discard the invalid sequence(s). How to do that? */
325 xmlXPathReturnEmptyString(ctxt);
326 xmlFree(str);
327 xmlFree(ret);
328 return;
329 }
330
331 xmlXPathReturnString(ctxt, ret);
332
333 if (str != NULL)
334 xmlFree(str);
335}
336
337/**
338 * exsltStrPaddingFunction:
339 * @ctxt: an XPath parser context
340 * @nargs: the number of arguments
341 *
342 * Creates a padding string of a certain length.
343 */
344static void
345exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
346 int number, str_len = 0;
347 xmlChar *str = NULL, *ret = NULL, *tmp;
348
349 if ((nargs < 1) || (nargs > 2)) {
350 xmlXPathSetArityError(ctxt);
351 return;
352 }
353
354 if (nargs == 2) {
355 str = xmlXPathPopString(ctxt);
356 str_len = xmlUTF8Strlen(str);
357 }
358 if (str_len == 0) {
359 if (str != NULL) xmlFree(str);
360 str = xmlStrdup((const xmlChar *) " ");
361 str_len = 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_len);
374 number -= str_len;
375 }
376 tmp = xmlUTF8Strndup (str, number);
377 ret = xmlStrcat(ret, tmp);
378 if (tmp != NULL)
379 xmlFree (tmp);
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 */
394static void
395exsltStrAlignFunction (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 = xmlStrlen (str);
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 */
462static void
463exsltStrConcatFunction (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 * exsltStrReplaceInternal:
501 * @str: string to modify
502 * @searchStr: string to find
503 * @replaceStr: string to replace occurrences of searchStr
504 *
505 * Search and replace string function used by exsltStrReplaceFunction
506 */
507static xmlChar*
508exsltStrReplaceInternal(const xmlChar* str, const xmlChar* searchStr,
509 const xmlChar* replaceStr)
510{
511 const xmlChar *curr, *next;
512 xmlChar *ret = NULL;
513 int searchStrSize;
514
515 curr = str;
516 searchStrSize = xmlStrlen(searchStr);
517
518 do {
519 next = xmlStrstr(curr, searchStr);
520 if (next == NULL) {
521 ret = xmlStrcat (ret, curr);
522 break;
523 }
524
525 ret = xmlStrncat (ret, curr, next - curr);
526 ret = xmlStrcat (ret, replaceStr);
527 curr = next + searchStrSize;
528 } while (*curr != 0);
529
530 return ret;
531}
532/**
533 * exsltStrReplaceFunction:
534 * @ctxt: an XPath parser context
535 * @nargs: the number of arguments
536 *
537 * Takes a string, and two node sets and returns the string with all strings in
538 * the first node set replaced by all strings in the second node set.
539 */
540static void
541exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) {
542 xmlChar *str = NULL, *searchStr = NULL, *replaceStr = NULL;
543 xmlNodeSetPtr replaceSet = NULL, searchSet = NULL;
544 xmlChar *ret = NULL, *retSwap = NULL;
545 int i;
546
547 if (nargs != 3) {
548 xmlXPathSetArityError(ctxt);
549 return;
550 }
551
552 /* pull out replace argument */
553 if (!xmlXPathStackIsNodeSet(ctxt)) {
554 replaceStr = xmlXPathPopString(ctxt);
555 }
556 else {
557 replaceSet = xmlXPathPopNodeSet(ctxt);
558 if (xmlXPathCheckError(ctxt)) {
559 xmlXPathSetTypeError(ctxt);
560 goto fail;
561 }
562 }
563
564 /* behavior driven by search argument from here on */
565 if (!xmlXPathStackIsNodeSet(ctxt)) {
566 searchStr = xmlXPathPopString(ctxt);
567 str = xmlXPathPopString(ctxt);
568
569 if (replaceStr == NULL) {
570 xmlXPathSetTypeError(ctxt);
571 goto fail;
572 }
573
574 ret = exsltStrReplaceInternal(str, searchStr, replaceStr);
575 }
576 else {
577 searchSet = xmlXPathPopNodeSet(ctxt);
578 if (searchSet == NULL || xmlXPathCheckError(ctxt)) {
579 xmlXPathSetTypeError(ctxt);
580 goto fail;
581 }
582
583 str = xmlXPathPopString(ctxt);
584 ret = xmlStrdup(str);
585
586 for (i = 0; i < searchSet->nodeNr; i++) {
587
588 searchStr = xmlXPathCastNodeToString(searchSet->nodeTab[i]);
589
590 if (replaceSet != NULL) {
591 replaceStr = NULL;
592 if (i <= replaceSet->nodeNr) {
593 replaceStr = xmlXPathCastNodeToString(replaceSet->nodeTab[i]);
594 }
595
596 retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr);
597
598 if (replaceStr != NULL) {
599 xmlFree(replaceStr);
600 replaceStr = NULL;
601 }
602 }
603 else {
604 retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr);
605 }
606
607 xmlFree(ret);
608 if (searchStr != NULL) {
609 xmlFree(searchStr);
610 searchStr = NULL;
611 }
612
613 ret = retSwap;
614 }
615
616 if (replaceSet != NULL)
617 xmlXPathFreeNodeSet(replaceSet);
618
619 if (searchSet != NULL)
620 xmlXPathFreeNodeSet(searchSet);
621 }
622
623 xmlXPathReturnString(ctxt, ret);
624
625 fail:
626 if (replaceStr != NULL)
627 xmlFree(replaceStr);
628
629 if (searchStr != NULL)
630 xmlFree(searchStr);
631
632 if (str != NULL)
633 xmlFree(str);
634}
635
636/**
637 * exsltStrRegister:
638 *
639 * Registers the EXSLT - Strings module
640 */
641
642void
643exsltStrRegister (void) {
644 xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
645 EXSLT_STRINGS_NAMESPACE,
646 exsltStrTokenizeFunction);
647 xsltRegisterExtModuleFunction ((const xmlChar *) "split",
648 EXSLT_STRINGS_NAMESPACE,
649 exsltStrSplitFunction);
650 xsltRegisterExtModuleFunction ((const xmlChar *) "encode-uri",
651 EXSLT_STRINGS_NAMESPACE,
652 exsltStrEncodeUriFunction);
653 xsltRegisterExtModuleFunction ((const xmlChar *) "decode-uri",
654 EXSLT_STRINGS_NAMESPACE,
655 exsltStrDecodeUriFunction);
656 xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
657 EXSLT_STRINGS_NAMESPACE,
658 exsltStrPaddingFunction);
659 xsltRegisterExtModuleFunction ((const xmlChar *) "align",
660 EXSLT_STRINGS_NAMESPACE,
661 exsltStrAlignFunction);
662 xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
663 EXSLT_STRINGS_NAMESPACE,
664 exsltStrConcatFunction);
665 xsltRegisterExtModuleFunction ((const xmlChar *) "replace",
666 EXSLT_STRINGS_NAMESPACE,
667 exsltStrReplaceFunction);
668}
Note: See TracBrowser for help on using the repository browser.

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