1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-10-26 00:37:43 +03:00

SAX2: Fix quadratic behavior in xmlSAX2AttributeNs

The last missing piece to make parsing of attributes O(n).
This commit is contained in:
Nick Wellnhofer
2023-11-04 20:21:54 +01:00
parent a40c32ac1f
commit a31e1b0665

95
SAX2.c
View File

@@ -1855,8 +1855,10 @@ decode:
* The default handling is to convert the attribute into an * The default handling is to convert the attribute into an
* DOM subtree and past it in a new xmlAttr element added to * DOM subtree and past it in a new xmlAttr element added to
* the element. * the element.
*
* Returns the new attribute or NULL in case of error.
*/ */
static void static xmlAttrPtr
xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt,
const xmlChar * localname, const xmlChar * localname,
const xmlChar * prefix, const xmlChar * prefix,
@@ -1884,43 +1886,29 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt,
ret = ctxt->freeAttrs; ret = ctxt->freeAttrs;
ctxt->freeAttrs = ret->next; ctxt->freeAttrs = ret->next;
ctxt->freeAttrsNr--; ctxt->freeAttrsNr--;
memset(ret, 0, sizeof(xmlAttr));
ret->type = XML_ATTRIBUTE_NODE;
ret->parent = ctxt->node;
ret->doc = ctxt->myDoc;
ret->ns = namespace;
if (ctxt->dictNames)
ret->name = localname;
else
ret->name = xmlStrdup(localname);
/* link at the end to preserve order, TODO speed up with a last */
if (ctxt->node->properties == NULL) {
ctxt->node->properties = ret;
} else {
xmlAttrPtr prev = ctxt->node->properties;
while (prev->next != NULL) prev = prev->next;
prev->next = ret;
ret->prev = prev;
}
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
} else { } else {
if (ctxt->dictNames) ret = xmlMalloc(sizeof(*ret));
ret = xmlNewNsPropEatName(ctxt->node, namespace, if (ret == NULL) {
(xmlChar *) localname, NULL); xmlSAX2ErrMemory(ctxt, NULL);
else return(NULL);
ret = xmlNewNsProp(ctxt->node, namespace, localname, NULL); }
if (ret == NULL) {
xmlErrMemory(ctxt, "xmlSAX2AttributeNs");
return;
}
} }
memset(ret, 0, sizeof(xmlAttr));
ret->type = XML_ATTRIBUTE_NODE;
ret->parent = ctxt->node;
ret->doc = ctxt->myDoc;
ret->ns = namespace;
if (ctxt->dictNames)
ret->name = localname;
else
ret->name = xmlStrdup(localname);
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
xmlNodePtr tmp; xmlNodePtr tmp;
@@ -2065,6 +2053,8 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt,
} }
if (dup != NULL) if (dup != NULL)
xmlFree(dup); xmlFree(dup);
return(ret);
} }
/** /**
@@ -2275,7 +2265,11 @@ xmlSAX2StartElementNs(void *ctx,
* process all the other attributes * process all the other attributes
*/ */
if (nb_attributes > 0) { if (nb_attributes > 0) {
xmlAttrPtr prev = NULL;
for (j = 0,i = 0;i < nb_attributes;i++,j+=5) { for (j = 0,i = 0;i < nb_attributes;i++,j+=5) {
xmlAttrPtr attr = NULL;
/* /*
* Handle the rare case of an undefined attribute prefix * Handle the rare case of an undefined attribute prefix
*/ */
@@ -2286,23 +2280,38 @@ xmlSAX2StartElementNs(void *ctx,
fullname = xmlDictQLookup(ctxt->dict, attributes[j+1], fullname = xmlDictQLookup(ctxt->dict, attributes[j+1],
attributes[j]); attributes[j]);
if (fullname != NULL) { if (fullname != NULL) {
xmlSAX2AttributeNs(ctxt, fullname, NULL, attr = xmlSAX2AttributeNs(ctxt, fullname, NULL,
attributes[j+3], attributes[j+4]); attributes[j+3],
continue; attributes[j+4]);
goto have_attr;
} }
} else { } else {
lname = xmlBuildQName(attributes[j], attributes[j+1], lname = xmlBuildQName(attributes[j], attributes[j+1],
NULL, 0); NULL, 0);
if (lname != NULL) { if (lname != NULL) {
xmlSAX2AttributeNs(ctxt, lname, NULL, attr = xmlSAX2AttributeNs(ctxt, lname, NULL,
attributes[j+3], attributes[j+4]); attributes[j+3],
attributes[j+4]);
xmlFree(lname); xmlFree(lname);
continue; goto have_attr;
} }
} }
} }
xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1], attr = xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1],
attributes[j+3], attributes[j+4]); attributes[j+3], attributes[j+4]);
have_attr:
if (attr == NULL)
continue;
/* link at the end to preserve order */
if (prev == NULL) {
ctxt->node->properties = attr;
} else {
prev->next = attr;
attr->prev = prev;
}
prev = attr;
} }
} }