Index: third_party/libxslt/libexslt/strings.c |
diff --git a/third_party/libxslt/libexslt/strings.c b/third_party/libxslt/libexslt/strings.c |
index 1a11976c51b8f947b1a2928edcd5f5cd8b5f6428..045cc14b63e7a23d687d9dcf2e2530f4970de974 100644 |
--- a/third_party/libxslt/libexslt/strings.c |
+++ b/third_party/libxslt/libexslt/strings.c |
@@ -27,7 +27,7 @@ |
* @nargs: the number of arguments |
* |
* Splits up a string on the characters of the delimiter string and returns a |
- * node set of token elements, each containing one token from the string. |
+ * node set of token elements, each containing one token from the string. |
*/ |
static void |
exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) |
@@ -106,7 +106,7 @@ exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) |
} |
} |
if (token != cur) { |
- node = xmlNewDocRawNode(container, NULL, |
+ node = xmlNewDocRawNode(container, NULL, |
(const xmlChar *) "token", token); |
xmlAddChild((xmlNodePtr) container, node); |
xmlXPathNodeSetAddUnique(ret->nodesetval, node); |
@@ -136,7 +136,7 @@ fail: |
* @nargs: the number of arguments |
* |
* Splits up a string on a delimiting string and returns a node set of token |
- * elements, each containing one token from the string. |
+ * elements, each containing one token from the string. |
*/ |
static void |
exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { |
@@ -335,7 +335,7 @@ exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
xmlFree(ret); |
return; |
} |
- |
+ |
xmlXPathReturnString(ctxt, ret); |
if (str != NULL) |
@@ -505,139 +505,271 @@ exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
} |
/** |
- * exsltStrReplaceInternal: |
- * @str: string to modify |
- * @searchStr: string to find |
- * @replaceStr: string to replace occurrences of searchStr |
+ * exsltStrReturnString: |
+ * @ctxt: an XPath parser context |
+ * @str: a string |
+ * @len: length of string |
* |
- * Search and replace string function used by exsltStrReplaceFunction |
+ * Returns a string as a node set. |
*/ |
-static xmlChar* |
-exsltStrReplaceInternal(const xmlChar* str, const xmlChar* searchStr, |
- const xmlChar* replaceStr) |
+static int |
+exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str, |
+ int len) |
{ |
- const xmlChar *curr, *next; |
- xmlChar *ret = NULL; |
- int searchStrSize; |
+ xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); |
+ xmlDocPtr container; |
+ xmlNodePtr text_node; |
+ xmlXPathObjectPtr ret; |
- curr = str; |
- searchStrSize = xmlStrlen(searchStr); |
+ container = xsltCreateRVT(tctxt); |
+ if (container == NULL) { |
+ xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
+ return(-1); |
+ } |
+ xsltRegisterLocalRVT(tctxt, container); |
+ |
+ text_node = xmlNewTextLen(str, len); |
+ if (text_node == NULL) { |
+ xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
+ return(-1); |
+ } |
+ xmlAddChild((xmlNodePtr) container, text_node); |
- do { |
- next = xmlStrstr(curr, searchStr); |
- if (next == NULL) { |
- ret = xmlStrcat (ret, curr); |
- break; |
- } |
+ ret = xmlXPathNewNodeSet(text_node); |
+ if (ret == NULL) { |
+ xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
+ return(-1); |
+ } |
- ret = xmlStrncat (ret, curr, next - curr); |
- ret = xmlStrcat (ret, replaceStr); |
- curr = next + searchStrSize; |
- } while (*curr != 0); |
+ xsltExtensionInstructionResultRegister(tctxt, ret); |
+ valuePush(ctxt, ret); |
- return ret; |
+ return(0); |
} |
+ |
/** |
* exsltStrReplaceFunction: |
* @ctxt: an XPath parser context |
* @nargs: the number of arguments |
* |
- * Takes a string, and two node sets and returns the string with all strings in |
+ * Takes a string, and two node sets and returns the string with all strings in |
* the first node set replaced by all strings in the second node set. |
*/ |
static void |
exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) { |
- xmlChar *str = NULL, *searchStr = NULL, *replaceStr = NULL; |
- xmlNodeSetPtr replaceSet = NULL, searchSet = NULL; |
- xmlChar *ret = NULL, *retSwap = NULL; |
- int i; |
+ int i, i_empty, n, slen0, rlen0, *slen, *rlen; |
+ void *mem = NULL; |
+ const xmlChar *src, *start; |
+ xmlChar *string, *search_str = NULL, *replace_str = NULL; |
+ xmlChar **search, **replace; |
+ xmlNodeSetPtr search_set = NULL, replace_set = NULL; |
+ xmlBufferPtr buf; |
if (nargs != 3) { |
- xmlXPathSetArityError(ctxt); |
- return; |
+ xmlXPathSetArityError(ctxt); |
+ return; |
} |
- /* pull out replace argument */ |
+ /* get replace argument */ |
+ |
+ if (!xmlXPathStackIsNodeSet(ctxt)) |
+ replace_str = xmlXPathPopString(ctxt); |
+ else |
+ replace_set = xmlXPathPopNodeSet(ctxt); |
+ |
+ if (xmlXPathCheckError(ctxt)) |
+ goto fail_replace; |
+ |
+ /* get search argument */ |
+ |
if (!xmlXPathStackIsNodeSet(ctxt)) { |
- replaceStr = xmlXPathPopString(ctxt); |
+ search_str = xmlXPathPopString(ctxt); |
+ n = 1; |
} |
- else { |
- replaceSet = xmlXPathPopNodeSet(ctxt); |
- if (xmlXPathCheckError(ctxt)) { |
- xmlXPathSetTypeError(ctxt); |
- goto fail; |
- } |
+ else { |
+ search_set = xmlXPathPopNodeSet(ctxt); |
+ n = search_set != NULL ? search_set->nodeNr : 0; |
} |
- /* behavior driven by search argument from here on */ |
- if (!xmlXPathStackIsNodeSet(ctxt)) { |
- searchStr = xmlXPathPopString(ctxt); |
- str = xmlXPathPopString(ctxt); |
- |
- if (replaceStr == NULL) { |
- xmlXPathSetTypeError(ctxt); |
- goto fail; |
- } |
- |
- ret = exsltStrReplaceInternal(str, searchStr, replaceStr); |
- } |
- else { |
- searchSet = xmlXPathPopNodeSet(ctxt); |
- if (searchSet == NULL || xmlXPathCheckError(ctxt)) { |
- xmlXPathSetTypeError(ctxt); |
- goto fail; |
- } |
- |
- str = xmlXPathPopString(ctxt); |
- ret = xmlStrdup(str); |
- |
- for (i = 0; i < searchSet->nodeNr; i++) { |
- searchStr = xmlXPathCastNodeToString(searchSet->nodeTab[i]); |
- |
- if (replaceSet != NULL) { |
- replaceStr = NULL; |
- if (i < replaceSet->nodeNr) { |
- replaceStr = xmlXPathCastNodeToString(replaceSet->nodeTab[i]); |
- } |
- |
- retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr); |
- |
- if (replaceStr != NULL) { |
- xmlFree(replaceStr); |
- replaceStr = NULL; |
- } |
+ if (xmlXPathCheckError(ctxt)) |
+ goto fail_search; |
+ |
+ /* get string argument */ |
+ |
+ string = xmlXPathPopString(ctxt); |
+ if (xmlXPathCheckError(ctxt)) |
+ goto fail_string; |
+ |
+ /* check for empty search node list */ |
+ |
+ if (n <= 0) { |
+ exsltStrReturnString(ctxt, string, xmlStrlen(string)); |
+ goto done_empty_search; |
+ } |
+ |
+ /* allocate memory for string pointer and length arrays */ |
+ |
+ if (n == 1) { |
+ search = &search_str; |
+ replace = &replace_str; |
+ slen = &slen0; |
+ rlen = &rlen0; |
+ } |
+ else { |
+ mem = xmlMalloc(2 * n * (sizeof(const xmlChar *) + sizeof(int))); |
+ if (mem == NULL) { |
+ xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
+ goto fail_malloc; |
+ } |
+ search = (xmlChar **) mem; |
+ replace = search + n; |
+ slen = (int *) (replace + n); |
+ rlen = slen + n; |
+ } |
+ |
+ /* process arguments */ |
+ |
+ i_empty = -1; |
+ |
+ for (i=0; i<n; ++i) { |
+ if (search_set != NULL) { |
+ search[i] = xmlXPathCastNodeToString(search_set->nodeTab[i]); |
+ if (search[i] == NULL) { |
+ n = i; |
+ goto fail_process_args; |
+ } |
+ } |
+ |
+ slen[i] = xmlStrlen(search[i]); |
+ if (i_empty < 0 && slen[i] == 0) |
+ i_empty = i; |
+ |
+ if (replace_set != NULL) { |
+ if (i < replace_set->nodeNr) { |
+ replace[i] = xmlXPathCastNodeToString(replace_set->nodeTab[i]); |
+ if (replace[i] == NULL) { |
+ n = i + 1; |
+ goto fail_process_args; |
+ } |
+ } |
+ else |
+ replace[i] = NULL; |
} |
else { |
- retSwap = exsltStrReplaceInternal(ret, searchStr, replaceStr); |
+ if (i == 0) |
+ replace[i] = replace_str; |
+ else |
+ replace[i] = NULL; |
} |
- xmlFree(ret); |
- if (searchStr != NULL) { |
- xmlFree(searchStr); |
- searchStr = NULL; |
+ if (replace[i] == NULL) |
+ rlen[i] = 0; |
+ else |
+ rlen[i] = xmlStrlen(replace[i]); |
+ } |
+ |
+ if (i_empty >= 0 && rlen[i_empty] == 0) |
+ i_empty = -1; |
+ |
+ /* replace operation */ |
+ |
+ buf = xmlBufferCreate(); |
+ if (buf == NULL) { |
+ xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
+ goto fail_buffer; |
+ } |
+ src = string; |
+ start = string; |
+ |
+ while (*src != 0) { |
+ int max_len = 0, i_match = 0; |
+ |
+ for (i=0; i<n; ++i) { |
+ if (*src == search[i][0] && |
+ slen[i] > max_len && |
+ xmlStrncmp(src, search[i], slen[i]) == 0) |
+ { |
+ i_match = i; |
+ max_len = slen[i]; |
+ } |
} |
- ret = retSwap; |
- } |
+ if (max_len == 0) { |
+ if (i_empty >= 0 && start < src) { |
+ if (xmlBufferAdd(buf, start, src - start) || |
+ xmlBufferAdd(buf, replace[i_empty], rlen[i_empty])) |
+ { |
+ xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
+ goto fail_buffer_add; |
+ } |
+ start = src; |
+ } |
- if (replaceSet != NULL) |
- xmlXPathFreeNodeSet(replaceSet); |
+ src += xmlUTF8Size(src); |
+ } |
+ else { |
+ if ((start < src && |
+ xmlBufferAdd(buf, start, src - start)) || |
+ (rlen[i_match] && |
+ xmlBufferAdd(buf, replace[i_match], rlen[i_match]))) |
+ { |
+ xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
+ goto fail_buffer_add; |
+ } |
- if (searchSet != NULL) |
- xmlXPathFreeNodeSet(searchSet); |
- } |
+ src += slen[i_match]; |
+ start = src; |
+ } |
+ } |
- xmlXPathReturnString(ctxt, ret); |
+ if (start < src && xmlBufferAdd(buf, start, src - start)) { |
+ xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); |
+ goto fail_buffer_add; |
+ } |
- fail: |
- if (replaceStr != NULL) |
- xmlFree(replaceStr); |
+ /* create result node set */ |
- if (searchStr != NULL) |
- xmlFree(searchStr); |
+ exsltStrReturnString(ctxt, xmlBufferContent(buf), xmlBufferLength(buf)); |
- if (str != NULL) |
- xmlFree(str); |
+ /* clean up */ |
+ |
+fail_buffer_add: |
+ xmlBufferFree(buf); |
+ |
+fail_buffer: |
+fail_process_args: |
+ if (search_set != NULL) { |
+ for (i=0; i<n; ++i) |
+ xmlFree(search[i]); |
+ } |
+ if (replace_set != NULL) { |
+ for (i=0; i<n; ++i) { |
+ if (replace[i] != NULL) |
+ xmlFree(replace[i]); |
+ } |
+ } |
+ |
+ if (mem != NULL) |
+ xmlFree(mem); |
+ |
+fail_malloc: |
+done_empty_search: |
+ xmlFree(string); |
+ |
+fail_string: |
+ if (search_set != NULL) |
+ xmlXPathFreeNodeSet(search_set); |
+ else |
+ xmlFree(search_str); |
+ |
+fail_search: |
+ if (replace_set != NULL) |
+ xmlXPathFreeNodeSet(replace_set); |
+ else |
+ xmlFree(replace_str); |
+ |
+fail_replace: |
+ return; |
} |
/** |