Coverage Report

Created: 2024-08-21 15:16

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