From 46de64e9c01af2dc20bd49482716746b33737f5e Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Wed, 29 May 2002 08:21:33 +0000 Subject: [PATCH] performance patch from Peter Jacobi Daniel * SAX.c parser.c tree.c include/libxml/tree.h: performance patch from Peter Jacobi Daniel --- ChangeLog | 5 ++ SAX.c | 8 +-- include/libxml/tree.h | 10 +++ parser.c | 83 ++++++++++++++++++------ tree.c | 147 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index f1d18748..11267e12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed May 29 10:21:39 CEST 2002 Daniel Veillard + + * SAX.c parser.c tree.c include/libxml/tree.h: performance patch from + Peter Jacobi + Mon May 27 23:18:33 CEST 2002 Daniel Veillard * configure.in: preparing 2.4.22 diff --git a/SAX.c b/SAX.c index e48b1493..9cf06a07 100644 --- a/SAX.c +++ b/SAX.c @@ -907,7 +907,7 @@ attribute(void *ctx, const xmlChar *fullname, const xmlChar *value) } /* !!!!!! */ - ret = xmlNewNsProp(ctxt->node, namespace, name, NULL); + ret = xmlNewNsPropEatName(ctxt->node, namespace, name, NULL); if (ret != NULL) { if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { @@ -984,8 +984,6 @@ attribute(void *ctx, const xmlChar *fullname, const xmlChar *value) if (nval != NULL) xmlFree(nval); - if (name != NULL) - xmlFree(name); if (ns != NULL) xmlFree(ns); } @@ -1194,7 +1192,7 @@ startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) * attributes parsing, since local namespace can be defined as * an attribute at this level. */ - ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL); + ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, name, NULL); if (ret == NULL) return; if (ctxt->myDoc->children == NULL) { #ifdef DEBUG_SAX_TREE @@ -1334,8 +1332,6 @@ startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) if (prefix != NULL) xmlFree(prefix); - if (name != NULL) - xmlFree(name); } diff --git a/include/libxml/tree.h b/include/libxml/tree.h index b6d65b99..33e511cf 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -591,6 +591,10 @@ xmlAttrPtr xmlNewNsProp (xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, const xmlChar *value); +xmlAttrPtr xmlNewNsPropEatName (xmlNodePtr node, + xmlNsPtr ns, + xmlChar *name, + const xmlChar *value); void xmlFreePropList (xmlAttrPtr cur); void xmlFreeProp (xmlAttrPtr cur); xmlAttrPtr xmlCopyProp (xmlNodePtr target, @@ -608,12 +612,18 @@ xmlNodePtr xmlNewDocNode (xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, const xmlChar *content); +xmlNodePtr xmlNewDocNodeEatName (xmlDocPtr doc, + xmlNsPtr ns, + xmlChar *name, + const xmlChar *content); xmlNodePtr xmlNewDocRawNode (xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, const xmlChar *content); xmlNodePtr xmlNewNode (xmlNsPtr ns, const xmlChar *name); +xmlNodePtr xmlNewNodeEatName (xmlNsPtr ns, + xmlChar *name); xmlNodePtr xmlNewChild (xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, diff --git a/parser.c b/parser.c index 98d14835..a3f77869 100644 --- a/parser.c +++ b/parser.c @@ -281,18 +281,24 @@ static int spacePop(xmlParserCtxtPtr ctxt) { xmlPopInput(ctxt); \ } while (0) -#define SHRINK if (ctxt->input->cur - ctxt->input->base > INPUT_CHUNK) {\ - xmlParserInputShrink(ctxt->input); \ - if ((*ctxt->input->cur == 0) && \ - (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \ - xmlPopInput(ctxt); \ +#define SHRINK if (ctxt->input->cur - ctxt->input->base > INPUT_CHUNK) \ + xmlSHRINK (ctxt); + +static void xmlSHRINK (xmlParserCtxtPtr ctxt) { + xmlParserInputShrink(ctxt->input); + if ((*ctxt->input->cur == 0) && + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) + xmlPopInput(ctxt); } -#define GROW if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) { \ - xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ - if ((*ctxt->input->cur == 0) && \ - (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \ - xmlPopInput(ctxt); \ +#define GROW if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) \ + xmlGROW (ctxt); + +static void xmlGROW (xmlParserCtxtPtr ctxt) { + xmlParserInputGrow(ctxt->input, INPUT_CHUNK); + if ((*ctxt->input->cur == 0) && + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) + xmlPopInput(ctxt); } #define SKIP_BLANKS xmlSkipBlankChars(ctxt) @@ -1746,6 +1752,46 @@ xmlParseName(xmlParserCtxtPtr ctxt) { return(xmlParseNameComplex(ctxt)); } +/** + * xmlParseNameAndCompare: + * @ctxt: an XML parser context + * + * parse an XML name and compares for match + * (specialized for endtag parsing) + * + * + * Returns NULL for an illegal name, (xmlChar*) 1 for success + * and the name for mismatch + */ + +xmlChar * +xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { + const xmlChar *cmp = other; + const xmlChar *in; + xmlChar *ret; + int count = 0; + + GROW; + + in = ctxt->input->cur; + while (*in != 0 && *in == *cmp) { + ++in; + ++cmp; + } + if (*cmp == 0 && (*in == '>' || IS_BLANK (*in))) { + /* success */ + ctxt->input->cur = in; + return (xmlChar*) 1; + } + /* failure (or end of input buffer), check with full function */ + ret = xmlParseName (ctxt); + if (ret != 0 && xmlStrEqual (ret, other)) { + xmlFree (ret); + return (xmlChar*) 1; + } + return ret; +} + static xmlChar * xmlParseNameComplex(xmlParserCtxtPtr ctxt) { xmlChar buf[XML_MAX_NAMELEN + 5]; @@ -6556,7 +6602,7 @@ xmlParseEndTag(xmlParserCtxtPtr ctxt) { } SKIP(2); - name = xmlParseName(ctxt); + name = xmlParseNameAndCompare(ctxt,ctxt->name); /* * We should definitely be at the ending "S? '>'" part @@ -6578,20 +6624,17 @@ xmlParseEndTag(xmlParserCtxtPtr ctxt) { * start-tag. * */ - if ((name == NULL) || (ctxt->name == NULL) || - (!xmlStrEqual(name, ctxt->name))) { + if (name != (xmlChar*)1) { ctxt->errNo = XML_ERR_TAG_NAME_MISMATCH; if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) { - if ((name != NULL) && (ctxt->name != NULL)) { + if (name != NULL) { ctxt->sax->error(ctxt->userData, "Opening and ending tag mismatch: %s and %s\n", ctxt->name, name); - } else if (ctxt->name != NULL) { + xmlFree(name); + } else { ctxt->sax->error(ctxt->userData, "Ending tag error for: %s\n", ctxt->name); - } else { - ctxt->sax->error(ctxt->userData, - "Ending tag error: internal error ???\n"); } } @@ -6604,10 +6647,8 @@ xmlParseEndTag(xmlParserCtxtPtr ctxt) { */ if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) && (!ctxt->disableSAX)) - ctxt->sax->endElement(ctxt->userData, name); + ctxt->sax->endElement(ctxt->userData, ctxt->name); - if (name != NULL) - xmlFree(name); oldname = namePop(ctxt); spacePop(ctxt); if (oldname != NULL) { diff --git a/tree.c b/tree.c index eee620b5..c8959f6f 100644 --- a/tree.c +++ b/tree.c @@ -1203,6 +1203,83 @@ xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, return(cur); } +/** + * xmlNewNsPropEatName: + * @node: the holding node + * @ns: the namespace + * @name: the name of the attribute + * @value: the value of the attribute + * + * Create a new property tagged with a namespace and carried by a node. + * Returns a pointer to the attribute + */ +xmlAttrPtr +xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name, + const xmlChar *value) { + xmlAttrPtr cur; + xmlDocPtr doc = NULL; + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewNsPropEatName : name == NULL\n"); +#endif + return(NULL); + } + + /* + * Allocate a new property and fill the fields. + */ + cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); + if (cur == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlNewNsPropEatName : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xmlAttr)); + cur->type = XML_ATTRIBUTE_NODE; + + cur->parent = node; + if (node != NULL) { + doc = node->doc; + cur->doc = doc; + } + cur->ns = ns; + cur->name = name; + if (value != NULL) { + xmlChar *buffer; + xmlNodePtr tmp; + + buffer = xmlEncodeEntitiesReentrant(doc, value); + cur->children = xmlStringGetNodeList(doc, buffer); + cur->last = NULL; + tmp = cur->children; + while (tmp != NULL) { + tmp->parent = (xmlNodePtr) cur; + if (tmp->next == NULL) + cur->last = tmp; + tmp = tmp->next; + } + xmlFree(buffer); + } + + /* + * Add it at the end to preserve parsing order ... + */ + if (node != NULL) { + if (node->properties == NULL) { + node->properties = cur; + } else { + xmlAttrPtr prev = node->properties; + + while (prev->next != NULL) prev = prev->next; + prev->next = cur; + cur->prev = prev; + } + } + return(cur); +} + /** * xmlNewDocProp: * @doc: the document @@ -1431,6 +1508,44 @@ xmlNewNode(xmlNsPtr ns, const xmlChar *name) { return(cur); } +/** + * xmlNewNodeEatName: + * @ns: namespace if any + * @name: the node name + * + * Creation of a new node element. @ns is optional (NULL). + * + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) { + xmlNodePtr cur; + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewNode : name == NULL\n"); +#endif + return(NULL); + } + + /* + * Allocate a new node and fill the fields. + */ + cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (cur == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlNewNode : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_ELEMENT_NODE; + + cur->name = name; + cur->ns = ns; + return(cur); +} + /** * xmlNewDocNode: * @doc: the document @@ -1463,6 +1578,38 @@ xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, return(cur); } +/** + * xmlNewDocNodeEatName: + * @doc: the document + * @ns: namespace if any + * @name: the node name + * @content: the XML text content if any + * + * Creation of a new node element within a document. @ns and @content + * are optional (NULL). + * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities + * references, but XML special chars need to be escaped first by using + * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't + * need entities support. + * + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns, + xmlChar *name, const xmlChar *content) { + xmlNodePtr cur; + + cur = xmlNewNodeEatName(ns, name); + if (cur != NULL) { + cur->doc = doc; + if (content != NULL) { + cur->children = xmlStringGetNodeList(doc, content); + UPDATE_LAST_CHILD_AND_PARENT(cur) + } + } + return(cur); +} + /** * xmlNewDocRawNode: