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