a lot of performance work especially the speed of streaming through the
* globals.c libxml.h parser.c parserInternals.c tree.c xmllint.c
xmlreader.c include/libxml/parser.h: a lot of performance work
especially the speed of streaming through the reader and push
interface. Some thread related optimizations. Nearly doubled the
speed of parsing through the reader.
Daniel
diff --git a/ChangeLog b/ChangeLog
index b7008b3..f9482f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Mon Apr 21 23:33:38 CEST 2003 Daniel Veillard <daniel@veillard.com>
+
+ * globals.c libxml.h parser.c parserInternals.c tree.c xmllint.c
+ xmlreader.c include/libxml/parser.h: a lot of performance work
+ especially the speed of streaming through the reader and push
+ interface. Some thread related optimizations. Nearly doubled the
+ speed of parsing through the reader.
+
Sun Apr 20 10:36:05 MDT 2003 John Fleck <jfleck@inkstain.net>
* doc/xmllint.xml
diff --git a/globals.c b/globals.c
index 380c94e..0fc54e2 100644
--- a/globals.c
+++ b/globals.c
@@ -488,6 +488,7 @@
{
xmlRegisterNodeFunc old = xmlRegisterNodeDefaultValue;
+ __xmlRegisterCallbacks = 1;
xmlRegisterNodeDefaultValue = func;
return(old);
}
@@ -505,6 +506,7 @@
{
xmlDeregisterNodeFunc old = xmlDeregisterNodeDefaultValue;
+ __xmlRegisterCallbacks = 1;
xmlDeregisterNodeDefaultValue = func;
return(old);
}
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index d623e73..4578ad9 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -233,6 +233,7 @@
int linenumbers; /* set line number in element content */
void *catalogs; /* document's own catalog */
int recovery; /* run in recovery mode */
+ int progressive; /* is this a progressive parsing */
};
/**
diff --git a/libxml.h b/libxml.h
index 8b1b949..fcf0f9e 100644
--- a/libxml.h
+++ b/libxml.h
@@ -40,4 +40,10 @@
#include "trio.h"
#endif
+/*
+ * Internal variable indicating if a callback has been registered for
+ * node creation/destruction. It avoids spending a lot of time in locking
+ * function while checking if the callback exists.
+ */
+extern int __xmlRegisterCallbacks;
#endif /* ! __XML_LIBXML_H__ */
diff --git a/parser.c b/parser.c
index 2e8021e..728b5bd 100644
--- a/parser.c
+++ b/parser.c
@@ -368,7 +368,8 @@
xmlPopInput(ctxt); \
} while (0)
-#define SHRINK if (ctxt->input->cur - ctxt->input->base > INPUT_CHUNK) \
+#define SHRINK if ((ctxt->progressive == 0) && \
+ (ctxt->input->cur - ctxt->input->base > INPUT_CHUNK))\
xmlSHRINK (ctxt);
static void xmlSHRINK (xmlParserCtxtPtr ctxt) {
@@ -378,7 +379,8 @@
xmlPopInput(ctxt);
}
-#define GROW if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) \
+#define GROW if ((ctxt->progressive == 0) && \
+ (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \
xmlGROW (ctxt);
static void xmlGROW (xmlParserCtxtPtr ctxt) {
@@ -386,7 +388,7 @@
if ((*ctxt->input->cur == 0) &&
(xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))
xmlPopInput(ctxt);
- }
+}
#define SKIP_BLANKS xmlSkipBlankChars(ctxt)
@@ -8191,6 +8193,55 @@
}
/**
+ * xmlParseGetLasts:
+ * @ctxt: an XML parser context
+ * @lastlt: pointer to store the last '<' from the input
+ * @lastgt: pointer to store the last '>' from the input
+ *
+ * Lookup the last < and > in the current chunk
+ */
+static void
+xmlParseGetLasts(xmlParserCtxtPtr ctxt, const xmlChar **lastlt,
+ const xmlChar **lastgt) {
+ const xmlChar *tmp;
+
+ if ((ctxt == NULL) || (lastlt == NULL) || (lastgt == NULL)) {
+ xmlGenericError(xmlGenericErrorContext,
+ "Internal error: xmlParseGetLasts\n");
+ return;
+ }
+ if ((ctxt->progressive == 1) && (ctxt->inputNr == 1)) {
+ tmp = ctxt->input->end;
+ tmp--;
+ while ((tmp >= ctxt->input->base) && (*tmp != '<') &&
+ (*tmp != '>')) tmp--;
+ if (tmp < ctxt->input->base) {
+ *lastlt = NULL;
+ *lastgt = NULL;
+ } else if (*tmp == '<') {
+ *lastlt = tmp;
+ tmp--;
+ while ((tmp >= ctxt->input->base) && (*tmp != '>')) tmp--;
+ if (tmp < ctxt->input->base)
+ *lastgt = NULL;
+ else
+ *lastgt = tmp;
+ } else {
+ *lastgt = tmp;
+ tmp--;
+ while ((tmp >= ctxt->input->base) && (*tmp != '<')) tmp--;
+ if (tmp < ctxt->input->base)
+ *lastlt = NULL;
+ else
+ *lastlt = tmp;
+ }
+
+ } else {
+ *lastlt = NULL;
+ *lastgt = NULL;
+ }
+}
+/**
* xmlParseTryOrFinish:
* @ctxt: an XML parser context
* @terminate: last chunk indicator
@@ -8204,6 +8255,7 @@
int ret = 0;
int avail;
xmlChar cur, next;
+ const xmlChar *lastlt, *lastgt;
#ifdef DEBUG_PUSH
switch (ctxt->instate) {
@@ -8258,9 +8310,13 @@
}
#endif
- while (1) {
- SHRINK;
+ if (ctxt->input->cur - ctxt->input->base > 4096) {
+ xmlSHRINK(ctxt);
+ ctxt->checkIndex = 0;
+ }
+ xmlParseGetLasts(ctxt, &lastlt, &lastgt);
+ while (1) {
/*
* Pop-up of finished entities.
*/
@@ -8269,7 +8325,8 @@
if (ctxt->input ==NULL) break;
if (ctxt->input->buf == NULL)
- avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base);
+ avail = ctxt->input->length -
+ (ctxt->input->cur - ctxt->input->base);
else {
/*
* If we are operating on converted input, try to flush
@@ -8412,12 +8469,317 @@
#endif
}
break;
+ case XML_PARSER_START_TAG: {
+ xmlChar *name, *oldname;
+
+ if ((avail < 2) && (ctxt->inputNr == 1))
+ goto done;
+ cur = ctxt->input->cur[0];
+ if (cur != '<') {
+ ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt->userData,
+ "Start tag expect, '<' not found\n");
+ ctxt->wellFormed = 0;
+ if (ctxt->recovery == 0) ctxt->disableSAX = 1;
+ ctxt->instate = XML_PARSER_EOF;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering EOF\n");
+#endif
+ if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+ ctxt->sax->endDocument(ctxt->userData);
+ goto done;
+ }
+ if (!terminate) {
+ if (ctxt->progressive) {
+ if ((lastgt == NULL) || (ctxt->input->cur > lastgt))
+ goto done;
+ } else if (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0) {
+ goto done;
+ }
+ }
+ if (ctxt->spaceNr == 0)
+ spacePush(ctxt, -1);
+ else
+ spacePush(ctxt, *ctxt->space);
+ name = xmlParseStartTag(ctxt);
+ if (name == NULL) {
+ spacePop(ctxt);
+ ctxt->instate = XML_PARSER_EOF;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering EOF\n");
+#endif
+ if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+ ctxt->sax->endDocument(ctxt->userData);
+ goto done;
+ }
+ namePush(ctxt, name);
+
+ /*
+ * [ VC: Root Element Type ]
+ * The Name in the document type declaration must match
+ * the element type of the root element.
+ */
+ if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc &&
+ ctxt->node && (ctxt->node == ctxt->myDoc->children))
+ ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
+
+ /*
+ * Check for an Empty Element.
+ */
+ if ((RAW == '/') && (NXT(1) == '>')) {
+ SKIP(2);
+ if ((ctxt->sax != NULL) &&
+ (ctxt->sax->endElement != NULL) && (!ctxt->disableSAX))
+ ctxt->sax->endElement(ctxt->userData, name);
+ oldname = namePop(ctxt);
+ spacePop(ctxt);
+ if (oldname != NULL) {
+#ifdef DEBUG_STACK
+ xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
+#endif
+ xmlFree(oldname);
+ }
+ if (ctxt->name == NULL) {
+ ctxt->instate = XML_PARSER_EPILOG;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering EPILOG\n");
+#endif
+ } else {
+ ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering CONTENT\n");
+#endif
+ }
+ break;
+ }
+ if (RAW == '>') {
+ NEXT;
+ } else {
+ ctxt->errNo = XML_ERR_GT_REQUIRED;
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt->userData,
+ "Couldn't find end of Start Tag %s\n",
+ name);
+ ctxt->wellFormed = 0;
+ if (ctxt->recovery == 0) ctxt->disableSAX = 1;
+
+ /*
+ * end of parsing of this node.
+ */
+ nodePop(ctxt);
+ oldname = namePop(ctxt);
+ spacePop(ctxt);
+ if (oldname != NULL) {
+#ifdef DEBUG_STACK
+ xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
+#endif
+ xmlFree(oldname);
+ }
+ }
+ ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering CONTENT\n");
+#endif
+ break;
+ }
+ case XML_PARSER_CONTENT: {
+ const xmlChar *test;
+ unsigned int cons;
+ if ((avail < 2) && (ctxt->inputNr == 1))
+ goto done;
+ cur = ctxt->input->cur[0];
+ next = ctxt->input->cur[1];
+
+ test = CUR_PTR;
+ cons = ctxt->input->consumed;
+ if ((cur == '<') && (next == '/')) {
+ ctxt->instate = XML_PARSER_END_TAG;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering END_TAG\n");
+#endif
+ break;
+ } else if ((cur == '<') && (next == '?')) {
+ if ((!terminate) &&
+ (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
+ goto done;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: Parsing PI\n");
+#endif
+ xmlParsePI(ctxt);
+ } else if ((cur == '<') && (next != '!')) {
+ ctxt->instate = XML_PARSER_START_TAG;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering START_TAG\n");
+#endif
+ break;
+ } else if ((cur == '<') && (next == '!') &&
+ (ctxt->input->cur[2] == '-') &&
+ (ctxt->input->cur[3] == '-')) {
+ if ((!terminate) &&
+ (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+ goto done;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: Parsing Comment\n");
+#endif
+ xmlParseComment(ctxt);
+ ctxt->instate = XML_PARSER_CONTENT;
+ } else if ((cur == '<') && (ctxt->input->cur[1] == '!') &&
+ (ctxt->input->cur[2] == '[') &&
+ (ctxt->input->cur[3] == 'C') &&
+ (ctxt->input->cur[4] == 'D') &&
+ (ctxt->input->cur[5] == 'A') &&
+ (ctxt->input->cur[6] == 'T') &&
+ (ctxt->input->cur[7] == 'A') &&
+ (ctxt->input->cur[8] == '[')) {
+ SKIP(9);
+ ctxt->instate = XML_PARSER_CDATA_SECTION;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering CDATA_SECTION\n");
+#endif
+ break;
+ } else if ((cur == '<') && (next == '!') &&
+ (avail < 9)) {
+ goto done;
+ } else if (cur == '&') {
+ if ((!terminate) &&
+ (xmlParseLookupSequence(ctxt, ';', 0, 0) < 0))
+ goto done;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: Parsing Reference\n");
+#endif
+ xmlParseReference(ctxt);
+ } else {
+ /* TODO Avoid the extra copy, handle directly !!! */
+ /*
+ * Goal of the following test is:
+ * - minimize calls to the SAX 'character' callback
+ * when they are mergeable
+ * - handle an problem for isBlank when we only parse
+ * a sequence of blank chars and the next one is
+ * not available to check against '<' presence.
+ * - tries to homogenize the differences in SAX
+ * callbacks between the push and pull versions
+ * of the parser.
+ */
+ if ((ctxt->inputNr == 1) &&
+ (avail < XML_PARSER_BIG_BUFFER_SIZE)) {
+ if (!terminate) {
+ if (ctxt->progressive) {
+ if ((lastlt == NULL) ||
+ (ctxt->input->cur > lastlt))
+ goto done;
+ } else if (xmlParseLookupSequence(ctxt,
+ '<', 0, 0) < 0) {
+ goto done;
+ }
+ }
+ }
+ ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: Parsing char data\n");
+#endif
+ xmlParseCharData(ctxt, 0);
+ }
+ /*
+ * Pop-up of finished entities.
+ */
+ while ((RAW == 0) && (ctxt->inputNr > 1))
+ xmlPopInput(ctxt);
+ if ((cons == ctxt->input->consumed) && (test == CUR_PTR)) {
+ ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+ if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+ ctxt->sax->error(ctxt->userData,
+ "detected an error in element content\n");
+ ctxt->wellFormed = 0;
+ if (ctxt->recovery == 0) ctxt->disableSAX = 1;
+ ctxt->instate = XML_PARSER_EOF;
+ break;
+ }
+ break;
+ }
+ case XML_PARSER_END_TAG:
+ if (avail < 2)
+ goto done;
+ if (!terminate) {
+ if (ctxt->progressive) {
+ if ((lastgt == NULL) || (ctxt->input->cur > lastgt))
+ goto done;
+ } else if (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0) {
+ goto done;
+ }
+ }
+ xmlParseEndTag(ctxt);
+ if (ctxt->name == NULL) {
+ ctxt->instate = XML_PARSER_EPILOG;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering EPILOG\n");
+#endif
+ } else {
+ ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering CONTENT\n");
+#endif
+ }
+ break;
+ case XML_PARSER_CDATA_SECTION: {
+ /*
+ * The Push mode need to have the SAX callback for
+ * cdataBlock merge back contiguous callbacks.
+ */
+ int base;
+
+ base = xmlParseLookupSequence(ctxt, ']', ']', '>');
+ if (base < 0) {
+ if (avail >= XML_PARSER_BIG_BUFFER_SIZE + 2) {
+ if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
+ if (ctxt->sax->cdataBlock != NULL)
+ ctxt->sax->cdataBlock(ctxt->userData, ctxt->input->cur,
+ XML_PARSER_BIG_BUFFER_SIZE);
+ }
+ SKIP(XML_PARSER_BIG_BUFFER_SIZE);
+ ctxt->checkIndex = 0;
+ }
+ goto done;
+ } else {
+ if ((ctxt->sax != NULL) && (base > 0) &&
+ (!ctxt->disableSAX)) {
+ if (ctxt->sax->cdataBlock != NULL)
+ ctxt->sax->cdataBlock(ctxt->userData,
+ ctxt->input->cur, base);
+ }
+ SKIP(base + 3);
+ ctxt->checkIndex = 0;
+ ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering CONTENT\n");
+#endif
+ }
+ break;
+ }
case XML_PARSER_MISC:
SKIP_BLANKS;
if (ctxt->input->buf == NULL)
- avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base);
+ avail = ctxt->input->length -
+ (ctxt->input->cur - ctxt->input->base);
else
- avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base);
+ avail = ctxt->input->buf->buffer->use -
+ (ctxt->input->cur - ctxt->input->base);
if (avail < 2)
goto done;
cur = ctxt->input->cur[0];
@@ -8432,7 +8794,8 @@
#endif
xmlParsePI(ctxt);
} else if ((cur == '<') && (next == '!') &&
- (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) {
+ (ctxt->input->cur[2] == '-') &&
+ (ctxt->input->cur[3] == '-')) {
if ((!terminate) &&
(xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
goto done;
@@ -8443,9 +8806,12 @@
xmlParseComment(ctxt);
ctxt->instate = XML_PARSER_MISC;
} else if ((cur == '<') && (next == '!') &&
- (ctxt->input->cur[2] == 'D') && (ctxt->input->cur[3] == 'O') &&
- (ctxt->input->cur[4] == 'C') && (ctxt->input->cur[5] == 'T') &&
- (ctxt->input->cur[6] == 'Y') && (ctxt->input->cur[7] == 'P') &&
+ (ctxt->input->cur[2] == 'D') &&
+ (ctxt->input->cur[3] == 'O') &&
+ (ctxt->input->cur[4] == 'C') &&
+ (ctxt->input->cur[5] == 'T') &&
+ (ctxt->input->cur[6] == 'Y') &&
+ (ctxt->input->cur[7] == 'P') &&
(ctxt->input->cur[8] == 'E')) {
if ((!terminate) &&
(xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
@@ -8484,21 +8850,14 @@
goto done;
} else {
ctxt->instate = XML_PARSER_START_TAG;
+ ctxt->progressive = 1;
+ xmlParseGetLasts(ctxt, &lastlt, &lastgt);
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
"PP: entering START_TAG\n");
#endif
}
break;
- case XML_PARSER_IGNORE:
- xmlGenericError(xmlGenericErrorContext,
- "PP: internal error, state == IGNORE");
- ctxt->instate = XML_PARSER_DTD;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering DTD\n");
-#endif
- break;
case XML_PARSER_PROLOG:
SKIP_BLANKS;
if (ctxt->input->buf == NULL)
@@ -8534,6 +8893,8 @@
goto done;
} else {
ctxt->instate = XML_PARSER_START_TAG;
+ ctxt->progressive = 1;
+ xmlParseGetLasts(ctxt, &lastlt, &lastgt);
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
"PP: entering START_TAG\n");
@@ -8591,290 +8952,6 @@
goto done;
}
break;
- case XML_PARSER_START_TAG: {
- xmlChar *name, *oldname;
-
- if ((avail < 2) && (ctxt->inputNr == 1))
- goto done;
- cur = ctxt->input->cur[0];
- if (cur != '<') {
- ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
- if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
- ctxt->sax->error(ctxt->userData,
- "Start tag expect, '<' not found\n");
- ctxt->wellFormed = 0;
- if (ctxt->recovery == 0) ctxt->disableSAX = 1;
- ctxt->instate = XML_PARSER_EOF;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering EOF\n");
-#endif
- if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
- ctxt->sax->endDocument(ctxt->userData);
- goto done;
- }
- if ((!terminate) &&
- (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
- goto done;
- if (ctxt->spaceNr == 0)
- spacePush(ctxt, -1);
- else
- spacePush(ctxt, *ctxt->space);
- name = xmlParseStartTag(ctxt);
- if (name == NULL) {
- spacePop(ctxt);
- ctxt->instate = XML_PARSER_EOF;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering EOF\n");
-#endif
- if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
- ctxt->sax->endDocument(ctxt->userData);
- goto done;
- }
- namePush(ctxt, xmlStrdup(name));
-
- /*
- * [ VC: Root Element Type ]
- * The Name in the document type declaration must match
- * the element type of the root element.
- */
- if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc &&
- ctxt->node && (ctxt->node == ctxt->myDoc->children))
- ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
-
- /*
- * Check for an Empty Element.
- */
- if ((RAW == '/') && (NXT(1) == '>')) {
- SKIP(2);
- if ((ctxt->sax != NULL) &&
- (ctxt->sax->endElement != NULL) && (!ctxt->disableSAX))
- ctxt->sax->endElement(ctxt->userData, name);
- xmlFree(name);
- oldname = namePop(ctxt);
- spacePop(ctxt);
- if (oldname != NULL) {
-#ifdef DEBUG_STACK
- xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
-#endif
- xmlFree(oldname);
- }
- if (ctxt->name == NULL) {
- ctxt->instate = XML_PARSER_EPILOG;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering EPILOG\n");
-#endif
- } else {
- ctxt->instate = XML_PARSER_CONTENT;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering CONTENT\n");
-#endif
- }
- break;
- }
- if (RAW == '>') {
- NEXT;
- } else {
- ctxt->errNo = XML_ERR_GT_REQUIRED;
- if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
- ctxt->sax->error(ctxt->userData,
- "Couldn't find end of Start Tag %s\n",
- name);
- ctxt->wellFormed = 0;
- if (ctxt->recovery == 0) ctxt->disableSAX = 1;
-
- /*
- * end of parsing of this node.
- */
- nodePop(ctxt);
- oldname = namePop(ctxt);
- spacePop(ctxt);
- if (oldname != NULL) {
-#ifdef DEBUG_STACK
- xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
-#endif
- xmlFree(oldname);
- }
- }
- xmlFree(name);
- ctxt->instate = XML_PARSER_CONTENT;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering CONTENT\n");
-#endif
- break;
- }
- case XML_PARSER_CONTENT: {
- const xmlChar *test;
- unsigned int cons;
- if ((avail < 2) && (ctxt->inputNr == 1))
- goto done;
- cur = ctxt->input->cur[0];
- next = ctxt->input->cur[1];
-
- test = CUR_PTR;
- cons = ctxt->input->consumed;
- if ((cur == '<') && (next == '?')) {
- if ((!terminate) &&
- (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
- goto done;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: Parsing PI\n");
-#endif
- xmlParsePI(ctxt);
- } else if ((cur == '<') && (next == '!') &&
- (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) {
- if ((!terminate) &&
- (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
- goto done;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: Parsing Comment\n");
-#endif
- xmlParseComment(ctxt);
- ctxt->instate = XML_PARSER_CONTENT;
- } else if ((cur == '<') && (ctxt->input->cur[1] == '!') &&
- (ctxt->input->cur[2] == '[') && (NXT(3) == 'C') &&
- (ctxt->input->cur[4] == 'D') && (NXT(5) == 'A') &&
- (ctxt->input->cur[6] == 'T') && (NXT(7) == 'A') &&
- (ctxt->input->cur[8] == '[')) {
- SKIP(9);
- ctxt->instate = XML_PARSER_CDATA_SECTION;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering CDATA_SECTION\n");
-#endif
- break;
- } else if ((cur == '<') && (next == '!') &&
- (avail < 9)) {
- goto done;
- } else if ((cur == '<') && (next == '/')) {
- ctxt->instate = XML_PARSER_END_TAG;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering END_TAG\n");
-#endif
- break;
- } else if (cur == '<') {
- ctxt->instate = XML_PARSER_START_TAG;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering START_TAG\n");
-#endif
- break;
- } else if (cur == '&') {
- if ((!terminate) &&
- (xmlParseLookupSequence(ctxt, ';', 0, 0) < 0))
- goto done;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: Parsing Reference\n");
-#endif
- xmlParseReference(ctxt);
- } else {
- /* TODO Avoid the extra copy, handle directly !!! */
- /*
- * Goal of the following test is:
- * - minimize calls to the SAX 'character' callback
- * when they are mergeable
- * - handle an problem for isBlank when we only parse
- * a sequence of blank chars and the next one is
- * not available to check against '<' presence.
- * - tries to homogenize the differences in SAX
- * callbacks between the push and pull versions
- * of the parser.
- */
- if ((ctxt->inputNr == 1) &&
- (avail < XML_PARSER_BIG_BUFFER_SIZE)) {
- if ((!terminate) &&
- (xmlParseLookupSequence(ctxt, '<', 0, 0) < 0))
- goto done;
- }
- ctxt->checkIndex = 0;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: Parsing char data\n");
-#endif
- xmlParseCharData(ctxt, 0);
- }
- /*
- * Pop-up of finished entities.
- */
- while ((RAW == 0) && (ctxt->inputNr > 1))
- xmlPopInput(ctxt);
- if ((cons == ctxt->input->consumed) && (test == CUR_PTR)) {
- ctxt->errNo = XML_ERR_INTERNAL_ERROR;
- if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
- ctxt->sax->error(ctxt->userData,
- "detected an error in element content\n");
- ctxt->wellFormed = 0;
- if (ctxt->recovery == 0) ctxt->disableSAX = 1;
- ctxt->instate = XML_PARSER_EOF;
- break;
- }
- break;
- }
- case XML_PARSER_CDATA_SECTION: {
- /*
- * The Push mode need to have the SAX callback for
- * cdataBlock merge back contiguous callbacks.
- */
- int base;
-
- base = xmlParseLookupSequence(ctxt, ']', ']', '>');
- if (base < 0) {
- if (avail >= XML_PARSER_BIG_BUFFER_SIZE + 2) {
- if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
- if (ctxt->sax->cdataBlock != NULL)
- ctxt->sax->cdataBlock(ctxt->userData, ctxt->input->cur,
- XML_PARSER_BIG_BUFFER_SIZE);
- }
- SKIP(XML_PARSER_BIG_BUFFER_SIZE);
- ctxt->checkIndex = 0;
- }
- goto done;
- } else {
- if ((ctxt->sax != NULL) && (base > 0) &&
- (!ctxt->disableSAX)) {
- if (ctxt->sax->cdataBlock != NULL)
- ctxt->sax->cdataBlock(ctxt->userData,
- ctxt->input->cur, base);
- }
- SKIP(base + 3);
- ctxt->checkIndex = 0;
- ctxt->instate = XML_PARSER_CONTENT;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering CONTENT\n");
-#endif
- }
- break;
- }
- case XML_PARSER_END_TAG:
- if (avail < 2)
- goto done;
- if ((!terminate) &&
- (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
- goto done;
- xmlParseEndTag(ctxt);
- if (ctxt->name == NULL) {
- ctxt->instate = XML_PARSER_EPILOG;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering EPILOG\n");
-#endif
- } else {
- ctxt->instate = XML_PARSER_CONTENT;
-#ifdef DEBUG_PUSH
- xmlGenericError(xmlGenericErrorContext,
- "PP: entering CONTENT\n");
-#endif
- }
- break;
case XML_PARSER_DTD: {
/*
* Sorry but progressive parsing of the internal subset
@@ -8965,6 +9042,15 @@
"PP: entering CONTENT\n");
#endif
break;
+ case XML_PARSER_IGNORE:
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: internal error, state == IGNORE");
+ ctxt->instate = XML_PARSER_DTD;
+#ifdef DEBUG_PUSH
+ xmlGenericError(xmlGenericErrorContext,
+ "PP: entering DTD\n");
+#endif
+ break;
case XML_PARSER_PI:
xmlGenericError(xmlGenericErrorContext,
"PP: internal error, state == PI\n");
@@ -9056,8 +9142,10 @@
xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size);
#endif
+#if 0
if ((terminate) || (ctxt->input->buf->buffer->use > 80))
xmlParseTryOrFinish(ctxt, terminate);
+#endif
} else if (ctxt->instate != XML_PARSER_EOF) {
if ((ctxt->input != NULL) && ctxt->input->buf != NULL) {
xmlParserInputBufferPtr in = ctxt->input->buf;
diff --git a/parserInternals.c b/parserInternals.c
index 741d766..e3b4446 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -1051,8 +1051,10 @@
* Do not shrink on large buffers whose only a tiny fraction
* was consumed
*/
+#if 0
if ((int) in->buf->buffer->use > used + 2 * INPUT_CHUNK)
return;
+#endif
if (used > INPUT_CHUNK) {
ret = xmlBufferShrink(in->buf->buffer, used - LINE_LEN);
if (ret > 0) {
diff --git a/python/tests/reader2.py b/python/tests/reader2.py
index 7519a90..f8ca254 100755
--- a/python/tests/reader2.py
+++ b/python/tests/reader2.py
@@ -16,7 +16,7 @@
</rss>
^
../../test/valid/xlink.xml:450: validity error: ID dt-arc already defined
- <p><termdef id="dt-arc" term="Arc">An <term>arc</term> is contained within an
+ <p><termdef id="dt-arc" term="Arc">An <ter
^
../../test/valid/xlink.xml:530: validity error: attribute def line 199 references an unknown ID "dt-xlg"
diff --git a/tree.c b/tree.c
index abe9cf2..867f074 100644
--- a/tree.c
+++ b/tree.c
@@ -38,6 +38,8 @@
#include <libxml/HTMLtree.h>
#endif
+int __xmlRegisterCallbacks = 0;
+
xmlNsPtr xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
/************************************************************************
@@ -744,7 +746,7 @@
doc->extSubset = cur;
cur->doc = doc;
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -854,7 +856,7 @@
}
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -875,7 +877,7 @@
return;
}
- if (xmlDeregisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
if (cur->children != NULL) {
@@ -946,7 +948,7 @@
cur->doc = cur;
cur->charset = XML_CHAR_ENCODING_UTF8;
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -969,7 +971,7 @@
return;
}
- if (xmlDeregisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
/*
@@ -1552,7 +1554,7 @@
}
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -1632,7 +1634,7 @@
}
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -1712,7 +1714,7 @@
}
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -1767,7 +1769,7 @@
}
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -1811,7 +1813,7 @@
return;
}
- if (xmlDeregisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
/* Check for ID removal -> leading to invalid references ! */
@@ -1912,7 +1914,7 @@
cur->content = xmlStrdup(content);
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -1953,7 +1955,7 @@
cur->name = xmlStrdup(name);
cur->ns = ns;
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue(cur);
return(cur);
}
@@ -1994,7 +1996,7 @@
cur->name = name;
cur->ns = ns;
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
return(cur);
}
@@ -2118,7 +2120,7 @@
cur->doc = doc;
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue(cur);
return(cur);
}
@@ -2151,7 +2153,7 @@
cur->content = xmlStrdup(content);
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue(cur);
return(cur);
}
@@ -2254,7 +2256,7 @@
} else
cur->name = xmlStrdup(name);
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue(cur);
return(cur);
}
@@ -2308,7 +2310,7 @@
cur->last = (xmlNodePtr) ent;
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue(cur);
return(cur);
}
@@ -2359,7 +2361,7 @@
cur->content = xmlStrndup(content, len);
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue(cur);
return(cur);
}
@@ -2411,7 +2413,7 @@
cur->content = xmlStrdup(content);
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue(cur);
return(cur);
}
@@ -2446,7 +2448,7 @@
cur->content = xmlStrndup(content, len);
}
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue(cur);
return(cur);
}
@@ -3076,7 +3078,7 @@
/* unroll to speed up freeing the document */
if (cur->type != XML_DTD_NODE) {
- if (xmlDeregisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
xmlDeregisterNodeDefaultValue(cur);
if ((cur->children != NULL) &&
@@ -3161,7 +3163,7 @@
return;
}
- if (xmlDeregisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
xmlDeregisterNodeDefaultValue(cur);
if ((cur->children != NULL) &&
@@ -3630,7 +3632,7 @@
* in case ret does get coalesced in xmlAddChild
* the deregister-node callback is called; so we register ret now already
*/
- if (xmlRegisterNodeDefaultValue)
+ if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
tmp = xmlAddChild(parent, ret);
diff --git a/xmllint.c b/xmllint.c
index 60c175b..698170c 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -763,12 +763,11 @@
}
if (f != NULL) {
int ret;
- int res, size = 3;
+ int res, size = 1024;
char chars[1024];
xmlParserCtxtPtr ctxt;
- if (repeat)
- size = 1024;
+ /* if (repeat) size = 1024; */
res = fread(chars, 1, 4, f);
if (res > 0) {
ctxt = xmlCreatePushParserCtxt(NULL, NULL,
diff --git a/xmlreader.c b/xmlreader.c
index 6cdadc9..9a24110 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -56,6 +56,7 @@
#define DUMP_READER
#endif
+#define CHUNK_SIZE 512
/************************************************************************
* *
* The parser: maps the Text Reader API on top of the existing *
@@ -340,9 +341,8 @@
*/
static int
xmlTextReaderPushData(xmlTextReaderPtr reader) {
- unsigned int cur = reader->cur;
xmlBufferPtr inbuf;
- int val;
+ int val, s;
int oldstate;
if ((reader->input == NULL) || (reader->input->buffer == NULL))
@@ -351,8 +351,9 @@
oldstate = reader->state;
reader->state = XML_TEXTREADER_NONE;
inbuf = reader->input->buffer;
+
while (reader->state == XML_TEXTREADER_NONE) {
- if (cur >= inbuf->use) {
+ if (inbuf->use < reader->cur + CHUNK_SIZE) {
/*
* Refill the buffer unless we are at the end of the stream
*/
@@ -365,47 +366,39 @@
(reader->ctxt->myDoc != NULL))
return(val);
}
+
} else
break;
}
/*
- * parse by block of 512 bytes
+ * parse by block of CHUNK_SIZE bytes, various tests show that
+ * it's the best tradeoff at least on a 1.2GH Duron
*/
- if ((cur >= reader->cur + 512) || (cur >= inbuf->use)) {
- if (cur < inbuf->use)
- cur = cur + 1;
+ if (inbuf->use >= reader->cur + CHUNK_SIZE) {
val = xmlParseChunk(reader->ctxt,
(const char *) &inbuf->content[reader->cur],
- cur - reader->cur, 0);
+ CHUNK_SIZE, 0);
+ reader->cur += CHUNK_SIZE;
if (val != 0)
return(-1);
- reader->cur = cur;
- break;
} else {
- cur = cur + 1;
-
- /*
- * One may have to force a flush at some point when parsing really
- * large CDATA sections
- */
- if ((cur - reader->cur > 4096) && (reader->base == 0) &&
- (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
- cur = cur + 1;
- val = xmlParseChunk(reader->ctxt,
- (const char *) &inbuf->content[reader->cur],
- cur - reader->cur, 0);
- if (val != 0)
- return(-1);
- reader->cur = cur;
- }
+ s = inbuf->use - reader->cur;
+ val = xmlParseChunk(reader->ctxt,
+ (const char *) &inbuf->content[reader->cur],
+ s, 0);
+ reader->cur += s;
+ if (val != 0)
+ return(-1);
+ break;
}
}
+
/*
* Discard the consumed input when needed and possible
*/
if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
- if ((reader->cur >= 4096) && (reader->base == 0)) {
- val = xmlBufferShrink(inbuf, cur);
+ if (reader->cur >= 4096) {
+ val = xmlBufferShrink(inbuf, reader->cur);
if (val >= 0) {
reader->cur -= val;
}
@@ -416,12 +409,13 @@
* At the end of the stream signal that the work is done to the Push
* parser.
*/
- if (reader->mode == XML_TEXTREADER_MODE_EOF) {
+ else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
if (reader->mode != XML_TEXTREADER_DONE) {
+ s = inbuf->use - reader->cur;
val = xmlParseChunk(reader->ctxt,
(const char *) &inbuf->content[reader->cur],
- cur - reader->cur, 1);
- reader->cur = cur;
+ s, 1);
+ reader->cur = inbuf->use;
reader->mode = XML_TEXTREADER_DONE;
}
}
@@ -767,17 +761,17 @@
* that the parser didn't finished or that we arent at the end
* of stream, continue processing.
*/
- while (((oldstate == XML_TEXTREADER_BACKTRACK) ||
+ while ((reader->node->next == NULL) &&
+ (reader->ctxt->nodeNr == olddepth) &&
+ ((oldstate == XML_TEXTREADER_BACKTRACK) ||
(reader->node->children == NULL) ||
(reader->node->type == XML_ENTITY_REF_NODE) ||
(reader->node->type == XML_DTD_NODE) ||
(reader->node->type == XML_DOCUMENT_NODE) ||
(reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
- (reader->node->next == NULL) &&
((reader->ctxt->node == NULL) ||
(reader->ctxt->node == reader->node) ||
(reader->ctxt->node == reader->node->parent)) &&
- (reader->ctxt->nodeNr == olddepth) &&
(reader->ctxt->instate != XML_PARSER_EOF)) {
val = xmlTextReaderPushData(reader);
if (val < 0)
@@ -785,45 +779,6 @@
if (reader->node == NULL)
goto node_end;
}
- /*
- * If we are in the middle of a piece of CDATA make sure it's finished
- * Maybe calling a function checking that a non-character() callback was
- * received would be cleaner for the loop exit.
- */
- if ((oldstate == XML_TEXTREADER_ELEMENT) &&
- (reader->ctxt->instate == XML_PARSER_CDATA_SECTION)) {
- while ((reader->ctxt->instate == XML_PARSER_CDATA_SECTION) &&
- (((reader->node->content == NULL) &&
- (reader->node->next != NULL) &&
- (reader->node->next->type == XML_CDATA_SECTION_NODE) &&
- (reader->node->next->next == NULL) &&
- (reader->node->parent->next == NULL)) ||
- ((reader->node->children != NULL) &&
- (reader->node->children->type == XML_CDATA_SECTION_NODE) &&
- (reader->node->children->next == NULL) &&
- (reader->node->children->next == NULL)))) {
- val = xmlTextReaderPushData(reader);
- if (val < 0)
- return(-1);
- }
- }
- if ((oldstate == XML_TEXTREADER_ELEMENT) &&
- (reader->ctxt->instate == XML_PARSER_CONTENT)) {
- while ((reader->ctxt->instate == XML_PARSER_CONTENT) &&
- (((reader->node->content == NULL) &&
- (reader->node->next != NULL) &&
- (reader->node->next->type == XML_TEXT_NODE) &&
- (reader->node->next->next == NULL) &&
- (reader->node->parent->next == NULL)) ||
- ((reader->node->children != NULL) &&
- (reader->node->children->type == XML_TEXT_NODE) &&
- (reader->node->children->next == NULL) &&
- (reader->node->children->next == NULL)))) {
- val = xmlTextReaderPushData(reader);
- if (val < 0)
- return(-1);
- }
- }
if (oldstate != XML_TEXTREADER_BACKTRACK) {
if ((reader->node->children != NULL) &&
(reader->node->type != XML_ENTITY_REF_NODE) &&
@@ -900,6 +855,15 @@
DUMP_READER
/*
+ * If we are in the middle of a piece of CDATA make sure it's finished
+ */
+ if ((reader->node != NULL) &&
+ ((reader->node->type == XML_TEXT_NODE) ||
+ (reader->node->type == XML_CDATA_SECTION_NODE))) {
+ xmlTextReaderExpand(reader);
+ }
+
+ /*
* Handle entities enter and exit when in entity replacement mode
*/
if ((reader->node != NULL) &&