diff options
author | Nick Wellnhofer <wellnhofer@aevum.de> | 2023-11-04 20:21:54 +0100 |
---|---|---|
committer | Nick Wellnhofer <wellnhofer@aevum.de> | 2023-11-04 20:21:54 +0100 |
commit | a31e1b0665ae2bdc7202b4db681383fde12351aa (patch) | |
tree | 662df187158c3b5d0498a1237c002b8d7c7b0109 | |
parent | a40c32ac1f4a5eb24696343deb1a6f557b7f8c9b (diff) | |
download | libxml2-a31e1b0665ae2bdc7202b4db681383fde12351aa.tar.gz |
SAX2: Fix quadratic behavior in xmlSAX2AttributeNs
The last missing piece to make parsing of attributes O(n).
-rw-r--r-- | SAX2.c | 91 |
1 files changed, 50 insertions, 41 deletions
@@ -1855,8 +1855,10 @@ decode: * The default handling is to convert the attribute into an * DOM subtree and past it in a new xmlAttr element added to * the element. + * + * Returns the new attribute or NULL in case of error. */ -static void +static xmlAttrPtr xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, const xmlChar * localname, const xmlChar * prefix, @@ -1884,42 +1886,28 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, ret = ctxt->freeAttrs; ctxt->freeAttrs = ret->next; ctxt->freeAttrsNr--; - memset(ret, 0, sizeof(xmlAttr)); - ret->type = XML_ATTRIBUTE_NODE; - - ret->parent = ctxt->node; - ret->doc = ctxt->myDoc; - ret->ns = namespace; + } else { + ret = xmlMalloc(sizeof(*ret)); + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt, NULL); + return(NULL); + } + } - if (ctxt->dictNames) - ret->name = localname; - else - ret->name = xmlStrdup(localname); + memset(ret, 0, sizeof(xmlAttr)); + ret->type = XML_ATTRIBUTE_NODE; - /* 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; + ret->parent = ctxt->node; + ret->doc = ctxt->myDoc; + ret->ns = namespace; - while (prev->next != NULL) prev = prev->next; - prev->next = ret; - ret->prev = prev; - } + if (ctxt->dictNames) + ret->name = localname; + else + ret->name = xmlStrdup(localname); - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) - xmlRegisterNodeDefaultValue((xmlNodePtr)ret); - } else { - if (ctxt->dictNames) - ret = xmlNewNsPropEatName(ctxt->node, namespace, - (xmlChar *) localname, NULL); - else - ret = xmlNewNsProp(ctxt->node, namespace, localname, NULL); - if (ret == NULL) { - xmlErrMemory(ctxt, "xmlSAX2AttributeNs"); - return; - } - } + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)ret); if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { xmlNodePtr tmp; @@ -2065,6 +2053,8 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, } if (dup != NULL) xmlFree(dup); + + return(ret); } /** @@ -2275,7 +2265,11 @@ xmlSAX2StartElementNs(void *ctx, * process all the other attributes */ if (nb_attributes > 0) { + xmlAttrPtr prev = NULL; + for (j = 0,i = 0;i < nb_attributes;i++,j+=5) { + xmlAttrPtr attr = NULL; + /* * Handle the rare case of an undefined attribute prefix */ @@ -2286,23 +2280,38 @@ xmlSAX2StartElementNs(void *ctx, fullname = xmlDictQLookup(ctxt->dict, attributes[j+1], attributes[j]); if (fullname != NULL) { - xmlSAX2AttributeNs(ctxt, fullname, NULL, - attributes[j+3], attributes[j+4]); - continue; + attr = xmlSAX2AttributeNs(ctxt, fullname, NULL, + attributes[j+3], + attributes[j+4]); + goto have_attr; } } else { lname = xmlBuildQName(attributes[j], attributes[j+1], NULL, 0); if (lname != NULL) { - xmlSAX2AttributeNs(ctxt, lname, NULL, - attributes[j+3], attributes[j+4]); + attr = xmlSAX2AttributeNs(ctxt, lname, NULL, + attributes[j+3], + attributes[j+4]); xmlFree(lname); - continue; + goto have_attr; } } } - xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1], - attributes[j+3], attributes[j+4]); + attr = xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1], + 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; } } |