Roll libxml to bfd2f430

revert-non-recursive-xml-parsing.patch was fixed upstream, so this also
removes the revert patch.

The new test baselines are more correct than they used to be. One of the
new libxml patches fixes line numbers, and you can see that's the only
difference in the new baselines, and that the new line numbers are more
correct than the old ones.

Bug: 934413
Change-Id: I986b89d4bc7b9b67c6c3baf9427d15cfd9bef41c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2878399
Reviewed-by: Stephen Chenney <schenney@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#882649}
NOKEYCHECK=True
GitOrigin-RevId: 74fc8143a66d02419015ac8652b50632b5ea62e1
diff --git a/README.chromium b/README.chromium
index 25d4dd5..df76eb4 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,6 +1,6 @@
 Name: libxml
 URL: http://xmlsoft.org
-Version: 7279d236364739a05657a8a614c15990eb08d0c6
+Version: bfd2f4300fb348a0fb8265a17546a0eb8bdec719
 CPEPrefix: cpe:/a:xmlsoft:libxml2:2.9.9
 License: MIT
 License File: src/Copyright
@@ -20,8 +20,6 @@
     See https://crbug.com/708433
 - libxml2-2.9.4-security-xpath-nodetab-uaf.patch: See https://crbug.com/705445
 - chromium-issue-708434.patch: Guard against input counter overflow.
-- revert-non-recursive-xml-parsing.patch: Making parts of the XML parser
-    non-recursive broke a few web platform tests.
 - chromium-issue-1138555.patch: Change TRUE to 1 for ICU68 which remove the
   #define of TRUE.
 - Add helper classes in the chromium/ subdirectory.
diff --git a/chromium/revert-non-recursive-xml-parsing.patch b/chromium/revert-non-recursive-xml-parsing.patch
deleted file mode 100644
index e81c7c2..0000000
--- a/chromium/revert-non-recursive-xml-parsing.patch
+++ /dev/null
@@ -1,268 +0,0 @@
-diff --git a/parser.c b/parser.c
-index 072eb22d..f863edd1 100644
---- a/parser.c
-+++ b/parser.c
-@@ -96,12 +96,6 @@ xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID,
- 
- static void xmlHaltParser(xmlParserCtxtPtr ctxt);
- 
--static int
--xmlParseElementStart(xmlParserCtxtPtr ctxt);
--
--static void
--xmlParseElementEnd(xmlParserCtxtPtr ctxt);
--
- /************************************************************************
-  *									*
-  *	Arbitrary limits set in the parser. See XML_PARSE_HUGE		*
-@@ -1828,6 +1822,7 @@ nodePop(xmlParserCtxtPtr ctxt)
-     return (ret);
- }
- 
-+#ifdef LIBXML_PUSH_ENABLED
- /**
-  * nameNsPush:
-  * @ctxt:  an XML parser context
-@@ -1863,11 +1858,6 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value,
- 	    goto mem_error;
-         }
- 	ctxt->pushTab = tmp2;
--    } else if (ctxt->pushTab == NULL) {
--        ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 *
--                                            sizeof(ctxt->pushTab[0]));
--        if (ctxt->pushTab == NULL)
--            goto mem_error;
-     }
-     ctxt->nameTab[ctxt->nameNr] = value;
-     ctxt->name = value;
-@@ -1879,7 +1869,6 @@ mem_error:
-     xmlErrMemory(ctxt, NULL);
-     return (-1);
- }
--#ifdef LIBXML_PUSH_ENABLED
- /**
-  * nameNsPop:
-  * @ctxt: an XML parser context
-@@ -9812,10 +9801,9 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
- 
- void
- xmlParseContent(xmlParserCtxtPtr ctxt) {
--    int nameNr = ctxt->nameNr;
--
-     GROW;
-     while ((RAW != 0) &&
-+	   ((RAW != '<') || (NXT(1) != '/')) &&
- 	   (ctxt->instate != XML_PARSER_EOF)) {
- 	const xmlChar *test = CUR_PTR;
- 	unsigned int cons = ctxt->input->consumed;
-@@ -9849,13 +9837,7 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
- 	 * Fourth case :  a sub-element.
- 	 */
- 	else if (*cur == '<') {
--            if (NXT(1) == '/') {
--                if (ctxt->nameNr <= nameNr)
--                    break;
--	        xmlParseElementEnd(ctxt);
--            } else {
--	        xmlParseElementStart(ctxt);
--            }
-+	    xmlParseElement(ctxt);
- 	}
- 
- 	/*
-@@ -9890,7 +9872,7 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
-  * xmlParseElement:
-  * @ctxt:  an XML parser context
-  *
-- * parse an XML element
-+ * parse an XML element, this is highly recursive
-  *
-  * [39] element ::= EmptyElemTag | STag content ETag
-  *
-@@ -9902,23 +9884,6 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
- 
- void
- xmlParseElement(xmlParserCtxtPtr ctxt) {
--    if (xmlParseElementStart(ctxt) != 0)
--        return;
--    xmlParseContent(ctxt);
--    if (ctxt->instate == XML_PARSER_EOF)
--	return;
--    xmlParseElementEnd(ctxt);
--}
--
--/**
-- * xmlParseElementStart:
-- * @ctxt:  an XML parser context
-- *
-- * Parse the start of an XML element. Returns -1 in case of error, 0 if an
-- * opening tag was parsed, 1 if an empty element was parsed.
-- */
--static int
--xmlParseElementStart(xmlParserCtxtPtr ctxt) {
-     const xmlChar *name;
-     const xmlChar *prefix = NULL;
-     const xmlChar *URI = NULL;
-@@ -9933,7 +9898,7 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) {
- 		 "Excessive depth in document: %d use XML_PARSE_HUGE option\n",
- 			  xmlParserMaxDepth);
- 	xmlHaltParser(ctxt);
--	return(-1);
-+	return;
-     }
- 
-     /* Capture start position */
-@@ -9960,17 +9925,12 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) {
- 	name = xmlParseStartTag(ctxt);
- #endif /* LIBXML_SAX1_ENABLED */
-     if (ctxt->instate == XML_PARSER_EOF)
--	return(-1);
-+	return;
-     if (name == NULL) {
- 	spacePop(ctxt);
--        return(-1);
-+        return;
-     }
--    if (ctxt->sax2)
--        nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr);
--#ifdef LIBXML_SAX1_ENABLED
--    else
--        namePush(ctxt, name);
--#endif /* LIBXML_SAX1_ENABLED */
-+    namePush(ctxt, name);
-     ret = ctxt->node;
- 
- #ifdef LIBXML_VALID_ENABLED
-@@ -10011,7 +9971,7 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) {
- 	   node_info.node = ret;
- 	   xmlParserAddNodeInfo(ctxt, &node_info);
- 	}
--	return(1);
-+	return;
-     }
-     if (RAW == '>') {
-         NEXT1;
-@@ -10039,39 +9999,41 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) {
- 	   node_info.node = ret;
- 	   xmlParserAddNodeInfo(ctxt, &node_info);
- 	}
--	return(-1);
-+	return;
-     }
- 
--    return(0);
--}
--
--/**
-- * xmlParseElementEnd:
-- * @ctxt:  an XML parser context
-- *
-- * Parse the end of an XML element.
-- */
--static void
--xmlParseElementEnd(xmlParserCtxtPtr ctxt) {
--    xmlParserNodeInfo node_info;
--    xmlNodePtr ret = ctxt->node;
-+    /*
-+     * Parse the content of the element:
-+     */
-+    xmlParseContent(ctxt);
-+    if (ctxt->instate == XML_PARSER_EOF)
-+	return;
-+    if (!IS_BYTE_CHAR(RAW)) {
-+        xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
-+	 "Premature end of data in tag %s line %d\n",
-+		                name, line, NULL);
- 
--    if (ctxt->nameNr <= 0)
--        return;
-+	/*
-+	 * end of parsing of this node.
-+	 */
-+	nodePop(ctxt);
-+	namePop(ctxt);
-+	spacePop(ctxt);
-+	if (nsNr != ctxt->nsNr)
-+	    nsPop(ctxt, ctxt->nsNr - nsNr);
-+	return;
-+    }
- 
-     /*
-      * parse the end of tag: '</' should be here.
-      */
-     if (ctxt->sax2) {
--        const xmlChar *prefix = ctxt->pushTab[ctxt->nameNr * 3 - 3];
--        const xmlChar *URI = ctxt->pushTab[ctxt->nameNr * 3 - 2];
--        int nsNr = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 3 - 1];
--	xmlParseEndTag2(ctxt, prefix, URI, 0, nsNr, 0);
-+	xmlParseEndTag2(ctxt, prefix, URI, line, ctxt->nsNr - nsNr, tlen);
- 	namePop(ctxt);
-     }
- #ifdef LIBXML_SAX1_ENABLED
--    else
--	xmlParseEndTag1(ctxt, 0);
-+      else
-+	xmlParseEndTag1(ctxt, line);
- #endif /* LIBXML_SAX1_ENABLED */
- 
-     /*
-@@ -12388,6 +12350,13 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
- 	return(NULL);
-     }
-     ctxt->dictNames = 1;
-+    ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 * sizeof(xmlChar *));
-+    if (ctxt->pushTab == NULL) {
-+        xmlErrMemory(ctxt, NULL);
-+	xmlFreeParserInputBuffer(buf);
-+	xmlFreeParserCtxt(ctxt);
-+	return(NULL);
-+    }
-     if (sax != NULL) {
- #ifdef LIBXML_SAX1_ENABLED
- 	if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler)
-@@ -14835,6 +14804,16 @@ xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk,
- 
-     xmlCtxtReset(ctxt);
- 
-+    if (ctxt->pushTab == NULL) {
-+        ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 *
-+	                                    sizeof(xmlChar *));
-+        if (ctxt->pushTab == NULL) {
-+	    xmlErrMemory(ctxt, NULL);
-+            xmlFreeParserInputBuffer(buf);
-+            return(1);
-+        }
-+    }
-+
-     if (filename == NULL) {
-         ctxt->directory = NULL;
-     } else {
-diff --git a/result/errors/754947.xml.err b/result/errors/754947.xml.err
-index 51e9b4ed..f45cb5a2 100644
---- a/result/errors/754947.xml.err
-+++ b/result/errors/754947.xml.err
-@@ -2,6 +2,6 @@
- Bytes: 0xEE 0x5D 0x5D 0x3E
- <d><![CDATA[0000000000000î]]>
-                          ^
--./test/errors/754947.xml:1: parser error : EndTag: '</' not found
-+./test/errors/754947.xml:1: parser error : Premature end of data in tag d line 1
- <d><![CDATA[0000000000000î]]>
-                              ^
-diff --git a/result/errors/759398.xml.err b/result/errors/759398.xml.err
-index bc9e5e03..f6036a3b 100644
---- a/result/errors/759398.xml.err
-+++ b/result/errors/759398.xml.err
-@@ -1,10 +1,10 @@
- ./test/errors/759398.xml:210: parser error : StartTag: invalid element name
- need to worry about parsers whi<! don't expand PErefs finding
-                                 ^
--./test/errors/759398.xml:309: parser error : Opening and ending tag mismatch: №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№m line 205 and termdef
-+./test/errors/759398.xml:309: parser error : Opening and ending tag mismatch: №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№m line 308 and termdef
- and provide access to their content and structure.</termdef> <termdef
-                                                             ^
--./test/errors/759398.xml:314: parser error : Opening and ending tag mismatch: spec line 205 and p
-+./test/errors/759398.xml:314: parser error : Opening and ending tag mismatch: spec line 50 and p
- data and the information it must provide to the application.</p>
-                                                                 ^
- ./test/errors/759398.xml:316: parser error : Extra content at the end of the document
diff --git a/chromium/roll.py b/chromium/roll.py
index 5c9b2fe..ef23d4c 100755
--- a/chromium/roll.py
+++ b/chromium/roll.py
@@ -66,8 +66,6 @@
 #    e. Complete the review as usual
 
 PATCHES = [
-    # TODO(dcheng): reach out upstream to see what's going on here.
-    'revert-non-recursive-xml-parsing.patch',
     'chromium-issue-599427.patch',
     'chromium-issue-628581.patch',
     'libxml2-2.9.4-security-xpath-nodetab-uaf.patch',
diff --git a/src/include/libxml/parser.h b/src/include/libxml/parser.h
index 1c86a97..0ba1c38 100644
--- a/src/include/libxml/parser.h
+++ b/src/include/libxml/parser.h
@@ -169,6 +169,8 @@
     XML_PARSE_READER = 5
 } xmlParserMode;
 
+typedef struct _xmlStartTag xmlStartTag;
+
 /**
  * xmlParserCtxt:
  *
@@ -280,7 +282,7 @@
     int                nsMax;         /* the size of the arrays */
     const xmlChar *   *nsTab;         /* the array of prefix/namespace name */
     int               *attallocs;     /* which attribute were allocated */
-    void *            *pushTab;       /* array of data for push */
+    xmlStartTag       *pushTab;       /* array of data for push */
     xmlHashTablePtr    attsDefault;   /* defaulted attributes if any */
     xmlHashTablePtr    attsSpecial;   /* non-CDATA attributes if any */
     int                nsWellFormed;  /* is the document XML Namespace okay */
diff --git a/src/libxml2.spec b/src/libxml2.spec
index 017e34e..1cd4855 100644
--- a/src/libxml2.spec
+++ b/src/libxml2.spec
@@ -204,6 +204,6 @@
 %endif # with_python3
 
 %changelog
-* Thu May  6 2021 Daniel Veillard <veillard@redhat.com>
+* Mon May 10 2021 Daniel Veillard <veillard@redhat.com>
 - upstream release 2.9.10 see http://xmlsoft.org/news.html
 
diff --git a/src/parser.c b/src/parser.c
index c69a1c3..eba5f61 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -87,6 +87,13 @@
 #include "buf.h"
 #include "enc.h"
 
+struct _xmlStartTag {
+    const xmlChar *prefix;
+    const xmlChar *URI;
+    int line;
+    int nsNr;
+};
+
 static void
 xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info);
 
@@ -96,6 +103,12 @@
 
 static void xmlHaltParser(xmlParserCtxtPtr ctxt);
 
+static int
+xmlParseElementStart(xmlParserCtxtPtr ctxt);
+
+static void
+xmlParseElementEnd(xmlParserCtxtPtr ctxt);
+
 /************************************************************************
  *									*
  *	Arbitrary limits set in the parser. See XML_PARSE_HUGE		*
@@ -1833,13 +1846,14 @@
     return (ret);
 }
 
-#ifdef LIBXML_PUSH_ENABLED
 /**
  * nameNsPush:
  * @ctxt:  an XML parser context
  * @value:  the element name
  * @prefix:  the element prefix
  * @URI:  the element namespace name
+ * @line:  the current line number for error messages
+ * @nsNr:  the number of namespaces pushed on the namespace table
  *
  * Pushes a new element name/prefix/URL on top of the name stack
  *
@@ -1847,11 +1861,13 @@
  */
 static int
 nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value,
-           const xmlChar *prefix, const xmlChar *URI, int nsNr)
+           const xmlChar *prefix, const xmlChar *URI, int line, int nsNr)
 {
+    xmlStartTag *tag;
+
     if (ctxt->nameNr >= ctxt->nameMax) {
         const xmlChar * *tmp;
-        void **tmp2;
+        xmlStartTag *tmp2;
         ctxt->nameMax *= 2;
         tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab,
                                     ctxt->nameMax *
@@ -1861,25 +1877,33 @@
 	    goto mem_error;
         }
 	ctxt->nameTab = tmp;
-        tmp2 = (void **) xmlRealloc((void * *)ctxt->pushTab,
-                                    ctxt->nameMax * 3 *
+        tmp2 = (xmlStartTag *) xmlRealloc((void * *)ctxt->pushTab,
+                                    ctxt->nameMax *
                                     sizeof(ctxt->pushTab[0]));
         if (tmp2 == NULL) {
 	    ctxt->nameMax /= 2;
 	    goto mem_error;
         }
 	ctxt->pushTab = tmp2;
+    } else if (ctxt->pushTab == NULL) {
+        ctxt->pushTab = (xmlStartTag *) xmlMalloc(ctxt->nameMax *
+                                            sizeof(ctxt->pushTab[0]));
+        if (ctxt->pushTab == NULL)
+            goto mem_error;
     }
     ctxt->nameTab[ctxt->nameNr] = value;
     ctxt->name = value;
-    ctxt->pushTab[ctxt->nameNr * 3] = (void *) prefix;
-    ctxt->pushTab[ctxt->nameNr * 3 + 1] = (void *) URI;
-    ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) (ptrdiff_t) nsNr;
+    tag = &ctxt->pushTab[ctxt->nameNr];
+    tag->prefix = prefix;
+    tag->URI = URI;
+    tag->line = line;
+    tag->nsNr = nsNr;
     return (ctxt->nameNr++);
 mem_error:
     xmlErrMemory(ctxt, NULL);
     return (-1);
 }
+#ifdef LIBXML_PUSH_ENABLED
 /**
  * nameNsPop:
  * @ctxt: an XML parser context
@@ -9656,10 +9680,8 @@
  */
 
 static void
-xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix,
-                const xmlChar *URI, int line, int nsNr, int tlen) {
+xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlStartTag *tag) {
     const xmlChar *name;
-    size_t curLength;
 
     GROW;
     if ((RAW != '<') || (NXT(1) != '/')) {
@@ -9668,24 +9690,10 @@
     }
     SKIP(2);
 
-    curLength = ctxt->input->end - ctxt->input->cur;
-    if ((tlen > 0) && (curLength >= (size_t)tlen) &&
-        (xmlStrncmp(ctxt->input->cur, ctxt->name, tlen) == 0)) {
-        if ((curLength >= (size_t)(tlen + 1)) &&
-	    (ctxt->input->cur[tlen] == '>')) {
-	    ctxt->input->cur += tlen + 1;
-	    ctxt->input->col += tlen + 1;
-	    goto done;
-	}
-	ctxt->input->cur += tlen;
-	ctxt->input->col += tlen;
-	name = (xmlChar*)1;
-    } else {
-	if (prefix == NULL)
-	    name = xmlParseNameAndCompare(ctxt, ctxt->name);
-	else
-	    name = xmlParseQNameAndCompare(ctxt, ctxt->name, prefix);
-    }
+    if (tag->prefix == NULL)
+        name = xmlParseNameAndCompare(ctxt, ctxt->name);
+    else
+        name = xmlParseQNameAndCompare(ctxt, ctxt->name, tag->prefix);
 
     /*
      * We should definitely be at the ending "S? '>'" part
@@ -9707,25 +9715,22 @@
      */
     if (name != (xmlChar*)1) {
         if (name == NULL) name = BAD_CAST "unparsable";
-        if ((line == 0) && (ctxt->node != NULL))
-            line = ctxt->node->line;
         xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
 		     "Opening and ending tag mismatch: %s line %d and %s\n",
-		                ctxt->name, line, name);
+		                ctxt->name, tag->line, name);
     }
 
     /*
      * SAX: End of Tag
      */
-done:
     if ((ctxt->sax != NULL) && (ctxt->sax->endElementNs != NULL) &&
 	(!ctxt->disableSAX))
-	ctxt->sax->endElementNs(ctxt->userData, ctxt->name, prefix, URI);
+	ctxt->sax->endElementNs(ctxt->userData, ctxt->name, tag->prefix,
+                                tag->URI);
 
     spacePop(ctxt);
-    if (nsNr != 0)
-	nsPop(ctxt, nsNr);
-    return;
+    if (tag->nsNr != 0)
+	nsPop(ctxt, tag->nsNr);
 }
 
 /**
@@ -9841,19 +9846,19 @@
 }
 
 /**
- * xmlParseContent:
+ * xmlParseContentInternal:
  * @ctxt:  an XML parser context
  *
- * Parse a content:
- *
- * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ * Parse a content sequence. Stops at EOF or '</'. Leaves checking of
+ * unexpected EOF to the caller.
  */
 
-void
-xmlParseContent(xmlParserCtxtPtr ctxt) {
+static void
+xmlParseContentInternal(xmlParserCtxtPtr ctxt) {
+    int nameNr = ctxt->nameNr;
+
     GROW;
     while ((RAW != 0) &&
-	   ((RAW != '<') || (NXT(1) != '/')) &&
 	   (ctxt->instate != XML_PARSER_EOF)) {
 	const xmlChar *test = CUR_PTR;
 	unsigned int cons = ctxt->input->consumed;
@@ -9887,7 +9892,13 @@
 	 * Fourth case :  a sub-element.
 	 */
 	else if (*cur == '<') {
-	    xmlParseElement(ctxt);
+            if (NXT(1) == '/') {
+                if (ctxt->nameNr <= nameNr)
+                    break;
+	        xmlParseElementEnd(ctxt);
+            } else {
+	        xmlParseElementStart(ctxt);
+            }
 	}
 
 	/*
@@ -9919,10 +9930,34 @@
 }
 
 /**
+ * xmlParseContent:
+ * @ctxt:  an XML parser context
+ *
+ * Parse a content sequence. Stops at EOF or '</'.
+ *
+ * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ */
+
+void
+xmlParseContent(xmlParserCtxtPtr ctxt) {
+    int nameNr = ctxt->nameNr;
+
+    xmlParseContentInternal(ctxt);
+
+    if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->nameNr > nameNr)) {
+        const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
+        int line = ctxt->pushTab[ctxt->nameNr - 1].line;
+        xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
+                "Premature end of data in tag %s line %d\n",
+		name, line, NULL);
+    }
+}
+
+/**
  * xmlParseElement:
  * @ctxt:  an XML parser context
  *
- * parse an XML element, this is highly recursive
+ * parse an XML element
  *
  * [39] element ::= EmptyElemTag | STag content ETag
  *
@@ -9934,6 +9969,34 @@
 
 void
 xmlParseElement(xmlParserCtxtPtr ctxt) {
+    if (xmlParseElementStart(ctxt) != 0)
+        return;
+
+    xmlParseContentInternal(ctxt);
+    if (ctxt->instate == XML_PARSER_EOF)
+	return;
+
+    if (CUR == 0) {
+        const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
+        int line = ctxt->pushTab[ctxt->nameNr - 1].line;
+        xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
+                "Premature end of data in tag %s line %d\n",
+		name, line, NULL);
+        return;
+    }
+
+    xmlParseElementEnd(ctxt);
+}
+
+/**
+ * xmlParseElementStart:
+ * @ctxt:  an XML parser context
+ *
+ * Parse the start of an XML element. Returns -1 in case of error, 0 if an
+ * opening tag was parsed, 1 if an empty element was parsed.
+ */
+static int
+xmlParseElementStart(xmlParserCtxtPtr ctxt) {
     const xmlChar *name;
     const xmlChar *prefix = NULL;
     const xmlChar *URI = NULL;
@@ -9948,7 +10011,7 @@
 		 "Excessive depth in document: %d use XML_PARSE_HUGE option\n",
 			  xmlParserMaxDepth);
 	xmlHaltParser(ctxt);
-	return;
+	return(-1);
     }
 
     /* Capture start position */
@@ -9975,12 +10038,12 @@
 	name = xmlParseStartTag(ctxt);
 #endif /* LIBXML_SAX1_ENABLED */
     if (ctxt->instate == XML_PARSER_EOF)
-	return;
+	return(-1);
     if (name == NULL) {
 	spacePop(ctxt);
-        return;
+        return(-1);
     }
-    namePush(ctxt, name);
+    nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr);
     ret = ctxt->node;
 
 #ifdef LIBXML_VALID_ENABLED
@@ -10021,7 +10084,7 @@
 	   node_info.node = ret;
 	   xmlParserAddNodeInfo(ctxt, &node_info);
 	}
-	return;
+	return(1);
     }
     if (RAW == '>') {
         NEXT1;
@@ -10049,41 +10112,36 @@
 	   node_info.node = ret;
 	   xmlParserAddNodeInfo(ctxt, &node_info);
 	}
-	return;
+	return(-1);
     }
 
-    /*
-     * Parse the content of the element:
-     */
-    xmlParseContent(ctxt);
-    if (ctxt->instate == XML_PARSER_EOF)
-	return;
-    if (!IS_BYTE_CHAR(RAW)) {
-        xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
-	 "Premature end of data in tag %s line %d\n",
-		                name, line, NULL);
+    return(0);
+}
 
-	/*
-	 * end of parsing of this node.
-	 */
-	nodePop(ctxt);
-	namePop(ctxt);
-	spacePop(ctxt);
-	if (nsNr != ctxt->nsNr)
-	    nsPop(ctxt, ctxt->nsNr - nsNr);
-	return;
-    }
+/**
+ * xmlParseElementEnd:
+ * @ctxt:  an XML parser context
+ *
+ * Parse the end of an XML element.
+ */
+static void
+xmlParseElementEnd(xmlParserCtxtPtr ctxt) {
+    xmlParserNodeInfo node_info;
+    xmlNodePtr ret = ctxt->node;
+
+    if (ctxt->nameNr <= 0)
+        return;
 
     /*
      * parse the end of tag: '</' should be here.
      */
     if (ctxt->sax2) {
-	xmlParseEndTag2(ctxt, prefix, URI, line, ctxt->nsNr - nsNr, tlen);
+	xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]);
 	namePop(ctxt);
     }
 #ifdef LIBXML_SAX1_ENABLED
-      else
-	xmlParseEndTag1(ctxt, line);
+    else
+	xmlParseEndTag1(ctxt, 0);
 #endif /* LIBXML_SAX1_ENABLED */
 
     /*
@@ -11353,6 +11411,7 @@
 	        const xmlChar *name;
 		const xmlChar *prefix = NULL;
 		const xmlChar *URI = NULL;
+                int line = ctxt->input->line;
 		int nsNr = ctxt->nsNr;
 
 		if ((avail < 2) && (ctxt->inputNr == 1))
@@ -11450,12 +11509,7 @@
 		    nodePop(ctxt);
 		    spacePop(ctxt);
 		}
-		if (ctxt->sax2)
-		    nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr);
-#ifdef LIBXML_SAX1_ENABLED
-		else
-		    namePush(ctxt, name);
-#endif /* LIBXML_SAX1_ENABLED */
+                nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr);
 
 		ctxt->instate = XML_PARSER_CONTENT;
                 ctxt->progressive = 1;
@@ -11572,11 +11626,7 @@
 		    }
 		}
 		if (ctxt->sax2) {
-		    xmlParseEndTag2(ctxt,
-		            (void *) ctxt->pushTab[ctxt->nameNr * 3 - 3],
-		            (void *) ctxt->pushTab[ctxt->nameNr * 3 - 2], 0,
-		            (int) (ptrdiff_t)
-                                ctxt->pushTab[ctxt->nameNr * 3 - 1], 0);
+	            xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]);
 		    nameNsPop(ctxt);
 		}
 #ifdef LIBXML_SAX1_ENABLED
@@ -12400,13 +12450,6 @@
 	return(NULL);
     }
     ctxt->dictNames = 1;
-    ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 * sizeof(xmlChar *));
-    if (ctxt->pushTab == NULL) {
-        xmlErrMemory(ctxt, NULL);
-	xmlFreeParserInputBuffer(buf);
-	xmlFreeParserCtxt(ctxt);
-	return(NULL);
-    }
     if (sax != NULL) {
 #ifdef LIBXML_SAX1_ENABLED
 	if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler)
@@ -14869,16 +14912,6 @@
 
     xmlCtxtReset(ctxt);
 
-    if (ctxt->pushTab == NULL) {
-        ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 *
-	                                    sizeof(xmlChar *));
-        if (ctxt->pushTab == NULL) {
-	    xmlErrMemory(ctxt, NULL);
-            xmlFreeParserInputBuffer(buf);
-            return(1);
-        }
-    }
-
     if (filename == NULL) {
         ctxt->directory = NULL;
     } else {