| 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 |