Index: third_party/libxslt/libxslt/transform.c |
diff --git a/third_party/libxslt/libxslt/transform.c b/third_party/libxslt/libxslt/transform.c |
index a4ca41df380ee2686b852b14713bd82958728c64..35701deabb6eb3546461223687521b5f1b928be7 100644 |
--- a/third_party/libxslt/libxslt/transform.c |
+++ b/third_party/libxslt/libxslt/transform.c |
@@ -20,6 +20,7 @@ |
#include "libxslt.h" |
#include <string.h> |
+#include <stdio.h> |
#include <libxml/xmlmemory.h> |
#include <libxml/parser.h> |
@@ -64,6 +65,7 @@ static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, |
#endif |
int xsltMaxDepth = 3000; |
+int xsltMaxVars = 15000; |
/* |
* Useful macros |
@@ -125,7 +127,7 @@ templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value) |
return (0); |
} |
} |
- if (ctxt->templNr >= ctxt->templMax) { |
+ else if (ctxt->templNr >= ctxt->templMax) { |
ctxt->templMax *= 2; |
ctxt->templTab = |
(xsltTemplatePtr *) xmlRealloc(ctxt->templTab, |
@@ -249,7 +251,7 @@ profPush(xsltTransformContextPtr ctxt, long value) |
return (0); |
} |
} |
- if (ctxt->profNr >= ctxt->profMax) { |
+ else if (ctxt->profNr >= ctxt->profMax) { |
ctxt->profMax *= 2; |
ctxt->profTab = |
(long *) xmlRealloc(ctxt->profTab, |
@@ -288,6 +290,54 @@ profPop(xsltTransformContextPtr ctxt) |
return (ret); |
} |
+static void |
+profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent) |
+{ |
+ int i; |
+ |
+ if (templ->templMax == 0) { |
+ templ->templMax = 4; |
+ templ->templCalledTab = |
+ (xsltTemplatePtr *) xmlMalloc(templ->templMax * |
+ sizeof(templ->templCalledTab[0])); |
+ templ->templCountTab = |
+ (int *) xmlMalloc(templ->templMax * |
+ sizeof(templ->templCountTab[0])); |
+ if (templ->templCalledTab == NULL || templ->templCountTab == NULL) { |
+ xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); |
+ return; |
+ } |
+ } |
+ else if (templ->templNr >= templ->templMax) { |
+ templ->templMax *= 2; |
+ templ->templCalledTab = |
+ (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab, |
+ templ->templMax * |
+ sizeof(templ->templCalledTab[0])); |
+ templ->templCountTab = |
+ (int *) xmlRealloc(templ->templCountTab, |
+ templ->templMax * |
+ sizeof(templ->templCountTab[0])); |
+ if (templ->templCalledTab == NULL || templ->templCountTab == NULL) { |
+ xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); |
+ return; |
+ } |
+ } |
+ |
+ for (i = 0; i < templ->templNr; i++) { |
+ if (templ->templCalledTab[i] == parent) { |
+ templ->templCountTab[i]++; |
+ break; |
+ } |
+ } |
+ if (i == templ->templNr) { |
+ /* not found, add new one */ |
+ templ->templCalledTab[templ->templNr] = parent; |
+ templ->templCountTab[templ->templNr] = 1; |
+ templ->templNr++; |
+ } |
+} |
+ |
/************************************************************************ |
* * |
* XInclude default settings * |
@@ -456,6 +506,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { |
cur->templNr = 0; |
cur->templMax = 5; |
cur->templ = NULL; |
+ cur->maxTemplateDepth = xsltMaxDepth; |
/* |
* initialize the variables stack |
@@ -471,6 +522,7 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { |
cur->varsMax = 10; |
cur->vars = NULL; |
cur->varsBase = 0; |
+ cur->maxTemplateVars = xsltMaxVars; |
/* |
* the profiling stack is not initialized by default |
@@ -726,7 +778,7 @@ xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, |
#endif |
/* |
- * Play save and reset the merging mechanism for every new |
+ * Play safe and reset the merging mechanism for every new |
* target node. |
*/ |
if ((target == NULL) || (target->children == NULL)) { |
@@ -2935,8 +2987,7 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, |
* Check for infinite recursion: stop if the maximum of nested templates |
* is excceeded. Adjust xsltMaxDepth if you need more. |
*/ |
- if (((ctxt->templNr >= xsltMaxDepth) || |
- (ctxt->varsNr >= 5 * xsltMaxDepth))) |
+ if (ctxt->templNr >= ctxt->maxTemplateDepth) |
{ |
xsltTransformError(ctxt, NULL, list, |
"xsltApplyXSLTTemplate: A potential infinite template recursion " |
@@ -2944,11 +2995,23 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, |
"You can adjust xsltMaxDepth (--maxdepth) in order to " |
"raise the maximum number of nested template calls and " |
"variables/params (currently set to %d).\n", |
- xsltMaxDepth); |
+ ctxt->maxTemplateDepth); |
xsltDebug(ctxt, contextNode, list, NULL); |
return; |
} |
+ if (ctxt->varsNr >= ctxt->maxTemplateVars) |
+ { |
+ xsltTransformError(ctxt, NULL, list, |
+ "xsltApplyXSLTTemplate: A potential infinite template recursion " |
+ "was detected.\n" |
+ "You can adjust maxTemplateVars (--maxvars) in order to " |
+ "raise the maximum number of variables/params (currently set to %d).\n", |
+ ctxt->maxTemplateVars); |
+ xsltDebug(ctxt, contextNode, list, NULL); |
+ return; |
+ } |
+ |
oldUserFragmentTop = ctxt->tmpRVT; |
ctxt->tmpRVT = NULL; |
oldLocalFragmentTop = ctxt->localRVT; |
@@ -2964,6 +3027,7 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, |
templ->nbCalls++; |
start = xsltTimestamp(); |
profPush(ctxt, 0); |
+ profCallgraphAdd(templ, ctxt->templ); |
} |
/* |
* Push the xsl:template declaration onto the stack. |
@@ -3230,6 +3294,7 @@ xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, |
const xmlChar *doctypeSystem; |
const xmlChar *version; |
const xmlChar *encoding; |
+ int redirect_write_append = 0; |
if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) |
return; |
@@ -3645,10 +3710,38 @@ xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, |
} |
/* |
- * Save the result |
+ * Calls to redirect:write also take an optional attribute append. |
+ * Attribute append="true|yes" which will attempt to simply append |
+ * to an existing file instead of always opening a new file. The |
+ * default behavior of always overwriting the file still happens |
+ * if we do not specify append. |
+ * Note that append use will forbid use of remote URI target. |
*/ |
- ret = xsltSaveResultToFilename((const char *) filename, |
- res, style, 0); |
+ prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append", |
+ NULL); |
+ if (prop != NULL) { |
+ if (xmlStrEqual(prop, (const xmlChar *) "true") || |
+ xmlStrEqual(prop, (const xmlChar *) "yes")) { |
+ style->omitXmlDeclaration = 1; |
+ redirect_write_append = 1; |
+ } else |
+ style->omitXmlDeclaration = 0; |
+ xmlFree(prop); |
+ } |
+ |
+ if (redirect_write_append) { |
+ FILE *f; |
+ |
+ f = fopen((const char *) filename, "ab"); |
+ if (f == NULL) { |
+ ret = -1; |
+ } else { |
+ ret = xsltSaveResultToFile(f, res, style); |
+ fclose(f); |
+ } |
+ } else { |
+ ret = xsltSaveResultToFilename((const char *) filename, res, style, 0); |
+ } |
if (ret < 0) { |
xsltTransformError(ctxt, NULL, inst, |
"xsltDocumentElem: unable to save to %s\n", |
@@ -3915,14 +4008,6 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, |
} |
name = xsltSplitQName(ctxt->dict, prop, &prefix); |
xmlFree(prop); |
- if ((prefix != NULL) && |
- (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3))) |
- { |
- /* |
- * TODO: Should we really disallow an "xml" prefix? |
- */ |
- goto error; |
- } |
} else { |
/* |
* The "name" value was static. |
@@ -3977,7 +4062,19 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, |
if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) |
nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); |
xmlFree(tmpNsName); |
- }; |
+ } |
+ |
+ if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) { |
+ xsltTransformError(ctxt, NULL, inst, |
+ "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ " |
+ "forbidden.\n"); |
+ goto error; |
+ } |
+ if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { |
+ prefix = BAD_CAST "xml"; |
+ } else if (xmlStrEqual(prefix, BAD_CAST "xml")) { |
+ prefix = NULL; |
+ } |
} else { |
xmlNsPtr ns; |
/* |
@@ -3993,13 +4090,13 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, |
* TODO: Check this in the compilation layer in case it's a |
* static value. |
*/ |
- if (prefix != NULL) { |
- xsltTransformError(ctxt, NULL, inst, |
- "xsl:element: The QName '%s:%s' has no " |
- "namespace binding in scope in the stylesheet; " |
- "this is an error, since the namespace was not " |
- "specified by the instruction itself.\n", prefix, name); |
- } |
+ if (prefix != NULL) { |
+ xsltTransformError(ctxt, NULL, inst, |
+ "xsl:element: The QName '%s:%s' has no " |
+ "namespace binding in scope in the stylesheet; " |
+ "this is an error, since the namespace was not " |
+ "specified by the instruction itself.\n", prefix, name); |
+ } |
} else |
nsName = ns->href; |
} |
@@ -4007,7 +4104,17 @@ xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, |
* Find/create a matching ns-decl in the result tree. |
*/ |
if (nsName != NULL) { |
- copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy); |
+ if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { |
+ /* Don't use a prefix of "xmlns" */ |
+ xmlChar *pref = xmlStrdup(BAD_CAST "ns_1"); |
+ |
+ copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy); |
+ |
+ xmlFree(pref); |
+ } else { |
+ copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, |
+ copy); |
+ } |
} else if ((copy->parent != NULL) && |
(copy->parent->type == XML_ELEMENT_NODE) && |
(copy->parent->ns != NULL)) |
@@ -4364,7 +4471,6 @@ xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node, |
xsltStylePreCompPtr comp = castedComp; |
#endif |
xmlXPathObjectPtr res = NULL; |
- xmlNodePtr copy = NULL; |
xmlChar *value = NULL; |
xmlDocPtr oldXPContextDoc; |
xmlNsPtr *oldXPNamespaces; |
@@ -4437,8 +4543,7 @@ xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node, |
goto error; |
} |
if (value[0] != 0) { |
- copy = xsltCopyTextString(ctxt, |
- ctxt->insert, value, comp->noescape); |
+ xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape); |
} |
} else { |
xsltTransformError(ctxt, NULL, inst, |
@@ -4832,7 +4937,10 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, |
list = xmlXPathNodeSetCreate(NULL); |
if (list == NULL) |
goto error; |
- cur = node->children; |
+ if (node->type != XML_NAMESPACE_DECL) |
+ cur = node->children; |
+ else |
+ cur = NULL; |
while (cur != NULL) { |
switch (cur->type) { |
case XML_TEXT_NODE: |
@@ -4881,6 +4989,8 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, |
if (cur->prev != NULL) |
cur->prev->next = cur->next; |
break; |
+ case XML_NAMESPACE_DECL: |
+ break; |
default: |
#ifdef WITH_XSLT_DEBUG_PROCESS |
XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, |