1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-10-23 01:52:48 +03:00

Make xmlParseContent and xmlParseElement non-recursive

Split xmlParseElement into subfunctions. Use nameNsPush to store prefix,
URI and nsNr on the heap, similar to the push parser.

Closes #84.
This commit is contained in:
Nick Wellnhofer
2019-09-23 14:46:41 +02:00
parent a28bc75158
commit 62150ed2ab
3 changed files with 74 additions and 53 deletions

121
parser.c
View File

@@ -96,6 +96,12 @@ xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID,
static void xmlHaltParser(xmlParserCtxtPtr ctxt); 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 * * Arbitrary limits set in the parser. See XML_PARSE_HUGE *
@@ -1822,7 +1828,6 @@ nodePop(xmlParserCtxtPtr ctxt)
return (ret); return (ret);
} }
#ifdef LIBXML_PUSH_ENABLED
/** /**
* nameNsPush: * nameNsPush:
* @ctxt: an XML parser context * @ctxt: an XML parser context
@@ -1858,6 +1863,11 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value,
goto mem_error; goto mem_error;
} }
ctxt->pushTab = tmp2; 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->nameTab[ctxt->nameNr] = value;
ctxt->name = value; ctxt->name = value;
@@ -1869,6 +1879,7 @@ mem_error:
xmlErrMemory(ctxt, NULL); xmlErrMemory(ctxt, NULL);
return (-1); return (-1);
} }
#ifdef LIBXML_PUSH_ENABLED
/** /**
* nameNsPop: * nameNsPop:
* @ctxt: an XML parser context * @ctxt: an XML parser context
@@ -9812,9 +9823,10 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
void void
xmlParseContent(xmlParserCtxtPtr ctxt) { xmlParseContent(xmlParserCtxtPtr ctxt) {
int nameNr = ctxt->nameNr;
GROW; GROW;
while ((RAW != 0) && while ((RAW != 0) &&
((RAW != '<') || (NXT(1) != '/')) &&
(ctxt->instate != XML_PARSER_EOF)) { (ctxt->instate != XML_PARSER_EOF)) {
const xmlChar *test = CUR_PTR; const xmlChar *test = CUR_PTR;
unsigned int cons = ctxt->input->consumed; unsigned int cons = ctxt->input->consumed;
@@ -9848,7 +9860,13 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
* Fourth case : a sub-element. * Fourth case : a sub-element.
*/ */
else if (*cur == '<') { else if (*cur == '<') {
xmlParseElement(ctxt); if (NXT(1) == '/') {
if (ctxt->nameNr <= nameNr)
break;
xmlParseElementEnd(ctxt);
} else {
xmlParseElementStart(ctxt);
}
} }
/* /*
@@ -9883,7 +9901,7 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
* xmlParseElement: * xmlParseElement:
* @ctxt: an XML parser context * @ctxt: an XML parser context
* *
* parse an XML element, this is highly recursive * parse an XML element
* *
* [39] element ::= EmptyElemTag | STag content ETag * [39] element ::= EmptyElemTag | STag content ETag
* *
@@ -9895,6 +9913,23 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
void void
xmlParseElement(xmlParserCtxtPtr ctxt) { 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 *name;
const xmlChar *prefix = NULL; const xmlChar *prefix = NULL;
const xmlChar *URI = NULL; const xmlChar *URI = NULL;
@@ -9909,7 +9944,7 @@ xmlParseElement(xmlParserCtxtPtr ctxt) {
"Excessive depth in document: %d use XML_PARSE_HUGE option\n", "Excessive depth in document: %d use XML_PARSE_HUGE option\n",
xmlParserMaxDepth); xmlParserMaxDepth);
xmlHaltParser(ctxt); xmlHaltParser(ctxt);
return; return(-1);
} }
/* Capture start position */ /* Capture start position */
@@ -9936,12 +9971,17 @@ xmlParseElement(xmlParserCtxtPtr ctxt) {
name = xmlParseStartTag(ctxt); name = xmlParseStartTag(ctxt);
#endif /* LIBXML_SAX1_ENABLED */ #endif /* LIBXML_SAX1_ENABLED */
if (ctxt->instate == XML_PARSER_EOF) if (ctxt->instate == XML_PARSER_EOF)
return; return(-1);
if (name == NULL) { if (name == NULL) {
spacePop(ctxt); spacePop(ctxt);
return; return(-1);
} }
namePush(ctxt, name); if (ctxt->sax2)
nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr);
#ifdef LIBXML_SAX1_ENABLED
else
namePush(ctxt, name);
#endif /* LIBXML_SAX1_ENABLED */
ret = ctxt->node; ret = ctxt->node;
#ifdef LIBXML_VALID_ENABLED #ifdef LIBXML_VALID_ENABLED
@@ -9982,7 +10022,7 @@ xmlParseElement(xmlParserCtxtPtr ctxt) {
node_info.node = ret; node_info.node = ret;
xmlParserAddNodeInfo(ctxt, &node_info); xmlParserAddNodeInfo(ctxt, &node_info);
} }
return; return(1);
} }
if (RAW == '>') { if (RAW == '>') {
NEXT1; NEXT1;
@@ -10010,41 +10050,39 @@ xmlParseElement(xmlParserCtxtPtr ctxt) {
node_info.node = ret; node_info.node = ret;
xmlParserAddNodeInfo(ctxt, &node_info); xmlParserAddNodeInfo(ctxt, &node_info);
} }
return; return(-1);
} }
/* return(0);
* 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);
/* /**
* end of parsing of this node. * xmlParseElementEnd:
*/ * @ctxt: an XML parser context
nodePop(ctxt); *
namePop(ctxt); * Parse the end of an XML element.
spacePop(ctxt); */
if (nsNr != ctxt->nsNr) static void
nsPop(ctxt, ctxt->nsNr - nsNr); xmlParseElementEnd(xmlParserCtxtPtr ctxt) {
return; xmlParserNodeInfo node_info;
} xmlNodePtr ret = ctxt->node;
if (ctxt->nameNr <= 0)
return;
/* /*
* parse the end of tag: '</' should be here. * parse the end of tag: '</' should be here.
*/ */
if (ctxt->sax2) { if (ctxt->sax2) {
xmlParseEndTag2(ctxt, prefix, URI, line, ctxt->nsNr - nsNr, tlen); 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);
namePop(ctxt); namePop(ctxt);
} }
#ifdef LIBXML_SAX1_ENABLED #ifdef LIBXML_SAX1_ENABLED
else else
xmlParseEndTag1(ctxt, line); xmlParseEndTag1(ctxt, 0);
#endif /* LIBXML_SAX1_ENABLED */ #endif /* LIBXML_SAX1_ENABLED */
/* /*
@@ -12361,13 +12399,6 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
return(NULL); return(NULL);
} }
ctxt->dictNames = 1; 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) { if (sax != NULL) {
#ifdef LIBXML_SAX1_ENABLED #ifdef LIBXML_SAX1_ENABLED
if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler)
@@ -14949,16 +14980,6 @@ xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk,
xmlCtxtReset(ctxt); 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) { if (filename == NULL) {
ctxt->directory = NULL; ctxt->directory = NULL;
} else { } else {

View File

@@ -2,6 +2,6 @@
Bytes: 0xEE 0x5D 0x5D 0x3E Bytes: 0xEE 0x5D 0x5D 0x3E
<d><![CDATA[0000000000000<30>]]> <d><![CDATA[0000000000000<30>]]>
^ ^
./test/errors/754947.xml:1: parser error : Premature end of data in tag d line 1 ./test/errors/754947.xml:1: parser error : EndTag: '</' not found
<d><![CDATA[0000000000000<30>]]> <d><![CDATA[0000000000000<30>]]>
^ ^

View File

@@ -1,10 +1,10 @@
./test/errors/759398.xml:210: parser error : StartTag: invalid element name ./test/errors/759398.xml:210: parser error : StartTag: invalid element name
need to worry about parsers whi<! don't expand PErefs finding 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 308 and termdef ./test/errors/759398.xml:309: parser error : Opening and ending tag mismatch: №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№m line 205 and termdef
and provide access to their content and structure.</termdef> <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 50 and p ./test/errors/759398.xml:314: parser error : Opening and ending tag mismatch: spec line 205 and p
data and the information it must provide to the application.</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 ./test/errors/759398.xml:316: parser error : Extra content at the end of the document