Imported Upstream version 2.9.5_rc1
[platform/upstream/libxml2.git] / parser.c
index 53a6b7f..9a7135f 100644 (file)
--- a/parser.c
+++ b/parser.c
  * daniel@veillard.com
  */
 
+/* To avoid EBCDIC trouble when parsing on zOS */
+#if defined(__MVS__)
+#pragma convert("ISO8859-1")
+#endif
+
 #define IN_LIBXML
 #include "libxml.h"
 
@@ -43,6 +48,7 @@
 #include <limits.h>
 #include <string.h>
 #include <stdarg.h>
+#include <stddef.h>
 #include <libxml/xmlmemory.h>
 #include <libxml/threads.h>
 #include <libxml/globals.h>
@@ -1087,7 +1093,12 @@ typedef xmlDefAttrs *xmlDefAttrsPtr;
 struct _xmlDefAttrs {
     int nbAttrs;       /* number of defaulted attributes on that element */
     int maxAttrs;       /* the size of the array */
-    const xmlChar *values[5]; /* array of localname/prefix/values/external */
+#if __STDC_VERSION__ >= 199901L
+    /* Using a C99 flexible array member avoids UBSan errors. */
+    const xmlChar *values[]; /* array of localname/prefix/values/external */
+#else
+    const xmlChar *values[5];
+#endif
 };
 
 /**
@@ -2037,10 +2048,8 @@ static int spacePop(xmlParserCtxtPtr ctxt) {
 
 #define SKIP(val) do {                                                 \
     ctxt->nbChars += (val),ctxt->input->cur += (val),ctxt->input->col+=(val);                  \
-    if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);    \
-    if ((*ctxt->input->cur == 0) &&                                    \
-        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))           \
-           xmlPopInput(ctxt);                                          \
+    if (*ctxt->input->cur == 0)                                                \
+        xmlParserInputGrow(ctxt->input, INPUT_CHUNK);                  \
   } while (0)
 
 #define SKIPL(val) do {                                                        \
@@ -2052,10 +2061,8 @@ static int spacePop(xmlParserCtxtPtr ctxt) {
        ctxt->nbChars++;                                                \
        ctxt->input->cur++;                                             \
     }                                                                  \
-    if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);    \
-    if ((*ctxt->input->cur == 0) &&                                    \
-        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))           \
-           xmlPopInput(ctxt);                                          \
+    if (*ctxt->input->cur == 0)                                                \
+        xmlParserInputGrow(ctxt->input, INPUT_CHUNK);                  \
   } while (0)
 
 #define SHRINK if ((ctxt->progressive == 0) &&                         \
@@ -2065,10 +2072,9 @@ static int spacePop(xmlParserCtxtPtr ctxt) {
 
 static void xmlSHRINK (xmlParserCtxtPtr ctxt) {
     xmlParserInputShrink(ctxt->input);
-    if ((*ctxt->input->cur == 0) &&
-        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))
-           xmlPopInput(ctxt);
-  }
+    if (*ctxt->input->cur == 0)
+        xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+}
 
 #define GROW if ((ctxt->progressive == 0) &&                           \
                 (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK))   \
@@ -2093,9 +2099,8 @@ static void xmlGROW (xmlParserCtxtPtr ctxt) {
         xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "cur index out of bound");
        return;
     }
-    if ((ctxt->input->cur != NULL) && (*ctxt->input->cur == 0) &&
-        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))
-           xmlPopInput(ctxt);
+    if ((ctxt->input->cur != NULL) && (*ctxt->input->cur == 0))
+        xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
 }
 
 #define SKIP_BLANKS xmlSkipBlankChars(ctxt)
@@ -2115,7 +2120,6 @@ static void xmlGROW (xmlParserCtxtPtr ctxt) {
        ctxt->input->line++; ctxt->input->col = 1;                      \
     } else ctxt->input->col++;                                         \
     ctxt->input->cur += l;                             \
-    if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);    \
   } while (0)
 
 #define CUR_CHAR(l) xmlCurrentChar(ctxt, &l)
@@ -2165,26 +2169,35 @@ xmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
        }
        ctxt->input->cur = cur;
     } else {
-       int cur;
-       do {
-           cur = CUR;
-           while ((IS_BLANK_CH(cur) && /* CHECKED tstblanks.xml */
-                  (ctxt->instate != XML_PARSER_EOF))) {
+        int expandPE = ((ctxt->external != 0) || (ctxt->inputNr != 1));
+
+       while (1) {
+            if (IS_BLANK_CH(CUR)) { /* CHECKED tstblanks.xml */
                NEXT;
-               cur = CUR;
-               res++;
-           }
-           while ((cur == 0) && (ctxt->inputNr > 1) &&
-                  (ctxt->instate != XML_PARSER_COMMENT)) {
-               xmlPopInput(ctxt);
-               cur = CUR;
-           }
-           /*
-            * Need to handle support of entities branching here
-            */
-           if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);
-       } while ((IS_BLANK(cur)) && /* CHECKED tstblanks.xml */
-                (ctxt->instate != XML_PARSER_EOF));
+           } else if (CUR == '%') {
+                /*
+                 * Need to handle support of entities branching here
+                 */
+               if ((expandPE == 0) || (IS_BLANK_CH(NXT(1))) || (NXT(1) == 0))
+                    break;
+               xmlParsePEReference(ctxt);
+            } else if (CUR == 0) {
+                if (ctxt->inputNr <= 1)
+                    break;
+                xmlPopInput(ctxt);
+            } else {
+                break;
+            }
+
+            /*
+             * Also increase the counter when entering or exiting a PERef.
+             * The spec says: "When a parameter-entity reference is recognized
+             * in the DTD and included, its replacement text MUST be enlarged
+             * by the attachment of one leading and one following space (#x20)
+             * character."
+             */
+           res++;
+        }
     }
     return(res);
 }
@@ -2210,10 +2223,13 @@ xmlPopInput(xmlParserCtxtPtr ctxt) {
     if (xmlParserDebugEntities)
        xmlGenericError(xmlGenericErrorContext,
                "Popping input %d\n", ctxt->inputNr);
+    if ((ctxt->inputNr > 1) && (ctxt->inSubset == 0) &&
+        (ctxt->instate != XML_PARSER_EOF))
+        xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
+                    "Unfinished entity outside the DTD");
     xmlFreeInputStream(inputPop(ctxt));
-    if ((*ctxt->input->cur == 0) &&
-        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))
-           return(xmlPopInput(ctxt));
+    if (*ctxt->input->cur == 0)
+        xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
     return(CUR);
 }
 
@@ -2239,6 +2255,13 @@ xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
        xmlGenericError(xmlGenericErrorContext,
                "Pushing input %d : %.30s\n", ctxt->inputNr+1, input->cur);
     }
+    if (((ctxt->inputNr > 40) && ((ctxt->options & XML_PARSE_HUGE) == 0)) ||
+        (ctxt->inputNr > 1024)) {
+        xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
+        while (ctxt->inputNr > 1)
+            xmlFreeInputStream(inputPop(ctxt));
+       return(-1);
+    }
     ret = inputPush(ctxt, input);
     if (ctxt->instate == XML_PARSER_EOF)
         return(-1);
@@ -2444,57 +2467,6 @@ xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) {
 }
 
 /**
- * xmlNewBlanksWrapperInputStream:
- * @ctxt:  an XML parser context
- * @entity:  an Entity pointer
- *
- * Create a new input stream for wrapping
- * blanks around a PEReference
- *
- * Returns the new input stream or NULL
- */
-
-static void deallocblankswrapper (xmlChar *str) {xmlFree(str);}
-
-static xmlParserInputPtr
-xmlNewBlanksWrapperInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
-    xmlParserInputPtr input;
-    xmlChar *buffer;
-    size_t length;
-    if (entity == NULL) {
-       xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
-                   "xmlNewBlanksWrapperInputStream entity\n");
-       return(NULL);
-    }
-    if (xmlParserDebugEntities)
-       xmlGenericError(xmlGenericErrorContext,
-               "new blanks wrapper for entity: %s\n", entity->name);
-    input = xmlNewInputStream(ctxt);
-    if (input == NULL) {
-       return(NULL);
-    }
-    length = xmlStrlen(entity->name) + 5;
-    buffer = xmlMallocAtomic(length);
-    if (buffer == NULL) {
-       xmlErrMemory(ctxt, NULL);
-        xmlFree(input);
-       return(NULL);
-    }
-    buffer [0] = ' ';
-    buffer [1] = '%';
-    buffer [length-3] = ';';
-    buffer [length-2] = ' ';
-    buffer [length-1] = 0;
-    memcpy(buffer + 2, entity->name, length - 5);
-    input->free = deallocblankswrapper;
-    input->base = buffer;
-    input->cur = buffer;
-    input->length = length;
-    input->end = &buffer[length];
-    return(input);
-}
-
-/**
  * xmlParserHandlePEReference:
  * @ctxt:  the parser context
  *
@@ -2528,11 +2500,6 @@ xmlNewBlanksWrapperInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
  */
 void
 xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) {
-    const xmlChar *name;
-    xmlEntityPtr entity = NULL;
-    xmlParserInputPtr input;
-
-    if (RAW != '%') return;
     switch(ctxt->instate) {
        case XML_PARSER_CDATA_SECTION:
            return;
@@ -2587,128 +2554,7 @@ xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) {
             return;
     }
 
-    NEXT;
-    name = xmlParseName(ctxt);
-    if (xmlParserDebugEntities)
-       xmlGenericError(xmlGenericErrorContext,
-               "PEReference: %s\n", name);
-    if (name == NULL) {
-       xmlFatalErr(ctxt, XML_ERR_PEREF_NO_NAME, NULL);
-    } else {
-       if (RAW == ';') {
-           NEXT;
-           if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL))
-               entity = ctxt->sax->getParameterEntity(ctxt->userData, name);
-           if (ctxt->instate == XML_PARSER_EOF)
-               return;
-           if (entity == NULL) {
-
-               /*
-                * [ WFC: Entity Declared ]
-                * In a document without any DTD, a document with only an
-                * internal DTD subset which contains no parameter entity
-                * references, or a document with "standalone='yes'", ...
-                * ... The declaration of a parameter entity must precede
-                * any reference to it...
-                */
-               if ((ctxt->standalone == 1) ||
-                   ((ctxt->hasExternalSubset == 0) &&
-                    (ctxt->hasPErefs == 0))) {
-                   xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY,
-                        "PEReference: %%%s; not found\n", name);
-               } else {
-                   /*
-                    * [ VC: Entity Declared ]
-                    * In a document with an external subset or external
-                    * parameter entities with "standalone='no'", ...
-                    * ... The declaration of a parameter entity must precede
-                    * any reference to it...
-                    */
-                   if ((ctxt->validate) && (ctxt->vctxt.error != NULL)) {
-                       xmlValidityError(ctxt, XML_WAR_UNDECLARED_ENTITY,
-                                        "PEReference: %%%s; not found\n",
-                                        name, NULL);
-                   } else
-                       xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY,
-                                     "PEReference: %%%s; not found\n",
-                                     name, NULL);
-                   ctxt->valid = 0;
-               }
-               xmlParserEntityCheck(ctxt, 0, NULL, 0);
-           } else if (ctxt->input->free != deallocblankswrapper) {
-                   input = xmlNewBlanksWrapperInputStream(ctxt, entity);
-                   if (xmlPushInput(ctxt, input) < 0)
-                       return;
-           } else {
-               if ((entity->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
-                   (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY)) {
-                   xmlChar start[4];
-                   xmlCharEncoding enc;
-
-                   /*
-                    * Note: external parameter entities will not be loaded, it
-                    * is not required for a non-validating parser, unless the
-                    * option of validating, or substituting entities were
-                    * given. Doing so is far more secure as the parser will
-                    * only process data coming from the document entity by
-                    * default.
-                    */
-                    if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
-                       ((ctxt->options & XML_PARSE_NOENT) == 0) &&
-                       ((ctxt->options & XML_PARSE_DTDVALID) == 0) &&
-                       ((ctxt->options & XML_PARSE_DTDLOAD) == 0) &&
-                       ((ctxt->options & XML_PARSE_DTDATTR) == 0) &&
-                       (ctxt->replaceEntities == 0) &&
-                       (ctxt->validate == 0))
-                       return;
-
-                   /*
-                    * handle the extra spaces added before and after
-                    * c.f. http://www.w3.org/TR/REC-xml#as-PE
-                    * this is done independently.
-                    */
-                   input = xmlNewEntityInputStream(ctxt, entity);
-                   if (xmlPushInput(ctxt, input) < 0)
-                       return;
-
-                   /*
-                    * Get the 4 first bytes and decode the charset
-                    * if enc != XML_CHAR_ENCODING_NONE
-                    * plug some encoding conversion routines.
-                    * Note that, since we may have some non-UTF8
-                    * encoding (like UTF16, bug 135229), the 'length'
-                    * is not known, but we can calculate based upon
-                    * the amount of data in the buffer.
-                    */
-                   GROW
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        return;
-                   if ((ctxt->input->end - ctxt->input->cur)>=4) {
-                       start[0] = RAW;
-                       start[1] = NXT(1);
-                       start[2] = NXT(2);
-                       start[3] = NXT(3);
-                       enc = xmlDetectCharEncoding(start, 4);
-                       if (enc != XML_CHAR_ENCODING_NONE) {
-                           xmlSwitchEncoding(ctxt, enc);
-                       }
-                   }
-
-                   if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
-                       (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l' )) &&
-                       (IS_BLANK_CH(NXT(5)))) {
-                       xmlParseTextDecl(ctxt);
-                   }
-               } else {
-                   xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER,
-                            "PEReference: %s is not a parameter entity\n",
-                                     name);
-               }
-           }
-       } else {
-           xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL);
-       }
-    }
+    xmlParsePEReference(ctxt);
 }
 
 /*
@@ -3406,13 +3252,6 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) {
            len += l;
            NEXTL(l);
            c = CUR_CHAR(l);
-           if (c == 0) {
-               count = 0;
-               GROW;
-                if (ctxt->instate == XML_PARSER_EOF)
-                    return(NULL);
-               c = CUR_CHAR(l);
-           }
        }
     }
     if ((len > XML_MAX_NAME_LENGTH) &&
@@ -3420,6 +3259,16 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) {
         xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name");
         return(NULL);
     }
+    if (ctxt->input->cur - ctxt->input->base < len) {
+        /*
+         * There were a couple of bugs where PERefs lead to to a change
+         * of the buffer. Check the buffer size to avoid passing an invalid
+         * pointer to xmlDictLookup.
+         */
+        xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
+                    "unexpected change of input buffer");
+        return (NULL);
+    }
     if ((*ctxt->input->cur == '\n') && (ctxt->input->cur[-1] == '\r'))
         return(xmlDictLookup(ctxt->dict, ctxt->input->cur - (len + 1), len));
     return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len));
@@ -3923,11 +3772,6 @@ xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) {
        }
        COPY_BUF(l,buf,len,c);
        NEXTL(l);
-       /*
-        * Pop-up of finished entities.
-        */
-       while ((RAW == 0) && (ctxt->inputNr > 1)) /* non input consuming */
-           xmlPopInput(ctxt);
 
        GROW;
        c = CUR_CHAR(l);
@@ -4589,7 +4433,7 @@ get_more:
            if (*in == ']') {
                if ((in[1] == ']') && (in[2] == '>')) {
                    xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL);
-                   ctxt->input->cur = in;
+                   ctxt->input->cur = in + 1;
                    return;
                }
                in++;
@@ -4742,7 +4586,7 @@ xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) {
            }
        }
     }
-    if ((cur != 0) && (!IS_CHAR(cur))) {
+    if ((ctxt->input->cur < ctxt->input->end) && (!IS_CHAR(cur))) {
        /* Generate the error and skip the offending character */
         xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR,
                           "PCDATA invalid Char value %d\n",
@@ -4782,22 +4626,20 @@ xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) {
     *publicID = NULL;
     if (CMP6(CUR_PTR, 'S', 'Y', 'S', 'T', 'E', 'M')) {
         SKIP(6);
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space required after 'SYSTEM'\n");
        }
-        SKIP_BLANKS;
        URI = xmlParseSystemLiteral(ctxt);
        if (URI == NULL) {
            xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL);
         }
     } else if (CMP6(CUR_PTR, 'P', 'U', 'B', 'L', 'I', 'C')) {
         SKIP(6);
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                    "Space required after 'PUBLIC'\n");
        }
-        SKIP_BLANKS;
        *publicID = xmlParsePubidLiteral(ctxt);
        if (*publicID == NULL) {
            xmlFatalErr(ctxt, XML_ERR_PUBID_REQUIRED, NULL);
@@ -4806,26 +4648,20 @@ xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) {
            /*
             * We don't handle [83] so "S SystemLiteral" is required.
             */
-           if (!IS_BLANK_CH(CUR)) {
+           if (SKIP_BLANKS == 0) {
                xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                        "Space required after the Public Identifier\n");
            }
        } else {
            /*
             * We handle [83] so we return immediately, if
-            * "S SystemLiteral" is not detected. From a purely parsing
-            * point of view that's a nice mess.
+            * "S SystemLiteral" is not detected. We skip blanks if no
+             * system literal was found, but this is harmless since we must
+             * be at the end of a NotationDecl.
             */
-           const xmlChar *ptr;
-           GROW;
-
-           ptr = CUR_PTR;
-           if (!IS_BLANK_CH(*ptr)) return(NULL);
-
-           while (IS_BLANK_CH(*ptr)) ptr++; /* TODO: dangerous, fix ! */
-           if ((*ptr != '\'') && (*ptr != '"')) return(NULL);
+           if (SKIP_BLANKS == 0) return(NULL);
+           if ((CUR != '\'') && (CUR != '"')) return(NULL);
        }
-        SKIP_BLANKS;
        URI = xmlParseSystemLiteral(ctxt);
        if (URI == NULL) {
            xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL);
@@ -4955,7 +4791,8 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf,
     } else {
        if (inputid != ctxt->input->id) {
            xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-               "Comment doesn't start and stop in the same entity\n");
+                          "Comment doesn't start and stop in the same"
+                           " entity\n");
        }
         NEXT;
        if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
@@ -5103,7 +4940,8 @@ get_more:
                if (in[2] == '>') {
                    if (ctxt->input->id != inputid) {
                        xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-                       "comment doesn't start and stop in the same entity\n");
+                                      "comment doesn't start and stop in the"
+                                       " same entity\n");
                    }
                    SKIP(3);
                    if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
@@ -5271,7 +5109,7 @@ xmlParsePI(xmlParserCtxtPtr ctxt) {
     int count = 0;
 
     if ((RAW == '<') && (NXT(1) == '?')) {
-       xmlParserInputPtr input = ctxt->input;
+       int inputid = ctxt->input->id;
        state = ctxt->instate;
         ctxt->instate = XML_PARSER_PI;
        /*
@@ -5287,9 +5125,10 @@ xmlParsePI(xmlParserCtxtPtr ctxt) {
         target = xmlParsePITarget(ctxt);
        if (target != NULL) {
            if ((RAW == '?') && (NXT(1) == '>')) {
-               if (input != ctxt->input) {
+               if (inputid != ctxt->input->id) {
                    xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-           "PI declaration doesn't start and stop in the same entity\n");
+                                  "PI declaration doesn't start and stop in"
+                                   " the same entity\n");
                }
                SKIP(2);
 
@@ -5310,12 +5149,10 @@ xmlParsePI(xmlParserCtxtPtr ctxt) {
                ctxt->instate = state;
                return;
            }
-           cur = CUR;
-           if (!IS_BLANK(cur)) {
+           if (SKIP_BLANKS == 0) {
                xmlFatalErrMsgStr(ctxt, XML_ERR_SPACE_REQUIRED,
                          "ParsePI: PI %s space expected\n", target);
            }
-            SKIP_BLANKS;
            cur = CUR_CHAR(l);
            while (IS_CHAR(cur) && /* checked */
                   ((cur != '?') || (NXT(1) != '>'))) {
@@ -5371,9 +5208,10 @@ xmlParsePI(xmlParserCtxtPtr ctxt) {
                xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
                      "ParsePI: PI %s never end ...\n", target);
            } else {
-               if (input != ctxt->input) {
-                   xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
-           "PI declaration doesn't start and stop in the same entity\n");
+               if (inputid != ctxt->input->id) {
+                   xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                                  "PI declaration doesn't start and stop in"
+                                   " the same entity\n");
                }
                SKIP(2);
 
@@ -5429,32 +5267,30 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
     xmlChar *Systemid;
 
     if (CMP10(CUR_PTR, '<', '!', 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) {
-       xmlParserInputPtr input = ctxt->input;
+       int inputid = ctxt->input->id;
        SHRINK;
        SKIP(10);
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space required after '<!NOTATION'\n");
            return;
        }
-       SKIP_BLANKS;
 
         name = xmlParseName(ctxt);
        if (name == NULL) {
            xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_STARTED, NULL);
            return;
        }
-       if (!IS_BLANK_CH(CUR)) {
-           xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
-                    "Space required after the NOTATION name'\n");
-           return;
-       }
        if (xmlStrchr(name, ':') != NULL) {
            xmlNsErr(ctxt, XML_NS_ERR_COLON,
                     "colons are forbidden from notation names '%s'\n",
                     name, NULL, NULL);
        }
-       SKIP_BLANKS;
+       if (SKIP_BLANKS == 0) {
+           xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
+                    "Space required after the NOTATION name'\n");
+           return;
+       }
 
        /*
         * Parse the IDs.
@@ -5463,9 +5299,10 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
        SKIP_BLANKS;
 
        if (RAW == '>') {
-           if (input != ctxt->input) {
-               xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
-       "Notation declaration doesn't start and stop in the same entity\n");
+           if (inputid != ctxt->input->id) {
+               xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                              "Notation declaration doesn't start and stop"
+                               " in the same entity\n");
            }
            NEXT;
            if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
@@ -5509,23 +5346,20 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
     const xmlChar *ndata = NULL;
     int isParameter = 0;
     xmlChar *orig = NULL;
-    int skipped;
 
     /* GROW; done in the caller */
     if (CMP8(CUR_PTR, '<', '!', 'E', 'N', 'T', 'I', 'T', 'Y')) {
-       xmlParserInputPtr input = ctxt->input;
+       int inputid = ctxt->input->id;
        SHRINK;
        SKIP(8);
-       skipped = SKIP_BLANKS;
-       if (skipped == 0) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space required after '<!ENTITY'\n");
        }
 
        if (RAW == '%') {
            NEXT;
-           skipped = SKIP_BLANKS;
-           if (skipped == 0) {
+           if (SKIP_BLANKS == 0) {
                xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                               "Space required after '%%'\n");
            }
@@ -5543,8 +5377,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
                     "colons are forbidden from entities names '%s'\n",
                     name, NULL, NULL);
        }
-        skipped = SKIP_BLANKS;
-       if (skipped == 0) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space required after the entity name\n");
        }
@@ -5655,18 +5488,16 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
                        xmlFreeURI(uri);
                    }
                }
-               if ((RAW != '>') && (!IS_BLANK_CH(CUR))) {
+               if ((RAW != '>') && (SKIP_BLANKS == 0)) {
                    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                                   "Space required before 'NDATA'\n");
                }
-               SKIP_BLANKS;
                if (CMP5(CUR_PTR, 'N', 'D', 'A', 'T', 'A')) {
                    SKIP(5);
-                   if (!IS_BLANK_CH(CUR)) {
+                   if (SKIP_BLANKS == 0) {
                        xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                                       "Space required after 'NDATA'\n");
                    }
-                   SKIP_BLANKS;
                    ndata = xmlParseName(ctxt);
                    if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
                        (ctxt->sax->unparsedEntityDecl != NULL))
@@ -5705,16 +5536,17 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
            }
        }
        if (ctxt->instate == XML_PARSER_EOF)
-           return;
+           goto done;
        SKIP_BLANKS;
        if (RAW != '>') {
            xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_NOT_FINISHED,
                    "xmlParseEntityDecl: entity %s not terminated\n", name);
            xmlHaltParser(ctxt);
        } else {
-           if (input != ctxt->input) {
+           if (inputid != ctxt->input->id) {
                xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-       "Entity declaration doesn't start and stop in the same entity\n");
+                              "Entity declaration doesn't start and stop in"
+                               " the same entity\n");
            }
            NEXT;
        }
@@ -5736,17 +5568,17 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
                    cur = xmlSAX2GetEntity(ctxt, name);
                }
            }
-            if (cur != NULL) {
-               if (cur->orig != NULL)
-                   xmlFree(orig);
-               else
-                   cur->orig = orig;
-           } else
-               xmlFree(orig);
+            if ((cur != NULL) && (cur->orig == NULL)) {
+               cur->orig = orig;
+                orig = NULL;
+           }
        }
+
+done:
        if (value != NULL) xmlFree(value);
        if (URI != NULL) xmlFree(URI);
        if (literal != NULL) xmlFree(literal);
+        if (orig != NULL) xmlFree(orig);
     }
 }
 
@@ -5797,11 +5629,10 @@ xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) {
     if (CMP6(CUR_PTR, '#', 'F', 'I', 'X', 'E', 'D')) {
        SKIP(6);
        val = XML_ATTRIBUTE_FIXED;
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space required after '#FIXED'\n");
        }
-       SKIP_BLANKS;
     }
     ret = xmlParseAttValue(ctxt);
     ctxt->instate = XML_PARSER_DTD;
@@ -5973,12 +5804,11 @@ int
 xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
     if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) {
        SKIP(8);
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space required after 'NOTATION'\n");
            return(0);
        }
-        SKIP_BLANKS;
        *tree = xmlParseNotationType(ctxt);
        if (*tree == NULL) return(0);
        return(XML_ATTRIBUTE_NOTATION);
@@ -6082,14 +5912,13 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
     xmlEnumerationPtr tree;
 
     if (CMP9(CUR_PTR, '<', '!', 'A', 'T', 'T', 'L', 'I', 'S', 'T')) {
-       xmlParserInputPtr input = ctxt->input;
+       int inputid = ctxt->input->id;
 
        SKIP(9);
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                                 "Space required after '<!ATTLIST'\n");
        }
-        SKIP_BLANKS;
         elemName = xmlParseName(ctxt);
        if (elemName == NULL) {
            xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
@@ -6099,7 +5928,6 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
        SKIP_BLANKS;
        GROW;
        while ((RAW != '>') && (ctxt->instate != XML_PARSER_EOF)) {
-           const xmlChar *check = CUR_PTR;
            int type;
            int def;
            xmlChar *defaultValue = NULL;
@@ -6113,12 +5941,11 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
                break;
            }
            GROW;
-           if (!IS_BLANK_CH(CUR)) {
+           if (SKIP_BLANKS == 0) {
                xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                        "Space required after the attribute name\n");
                break;
            }
-           SKIP_BLANKS;
 
            type = xmlParseAttributeType(ctxt, &tree);
            if (type <= 0) {
@@ -6126,14 +5953,13 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
            }
 
            GROW;
-           if (!IS_BLANK_CH(CUR)) {
+           if (SKIP_BLANKS == 0) {
                xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                               "Space required after the attribute type\n");
                if (tree != NULL)
                    xmlFreeEnumeration(tree);
                break;
            }
-           SKIP_BLANKS;
 
            def = xmlParseDefaultDecl(ctxt, &defaultValue);
            if (def <= 0) {
@@ -6148,7 +5974,7 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
 
            GROW;
             if (RAW != '>') {
-               if (!IS_BLANK_CH(CUR)) {
+               if (SKIP_BLANKS == 0) {
                    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                        "Space required after the attribute default value\n");
                    if (defaultValue != NULL)
@@ -6157,16 +5983,6 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
                        xmlFreeEnumeration(tree);
                    break;
                }
-               SKIP_BLANKS;
-           }
-           if (check == CUR_PTR) {
-               xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
-                           "in xmlParseAttributeListDecl\n");
-               if (defaultValue != NULL)
-                   xmlFree(defaultValue);
-               if (tree != NULL)
-                   xmlFreeEnumeration(tree);
-               break;
            }
            if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
                (ctxt->sax->attributeDecl != NULL))
@@ -6188,10 +6004,10 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
            GROW;
        }
        if (RAW == '>') {
-           if (input != ctxt->input) {
-               xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY,
-    "Attribute list declaration doesn't start and stop in the same entity\n",
-                                 NULL, NULL);
+           if (inputid != ctxt->input->id) {
+               xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                               "Attribute list declaration doesn't start and"
+                               " stop in the same entity\n");
            }
            NEXT;
        }
@@ -6228,10 +6044,10 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) {
        SKIP_BLANKS;
        SHRINK;
        if (RAW == ')') {
-           if ((ctxt->validate) && (ctxt->input->id != inputchk)) {
-               xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY,
-"Element content declaration doesn't start and stop in the same entity\n",
-                                 NULL, NULL);
+           if (ctxt->input->id != inputchk) {
+               xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                               "Element content declaration doesn't start and"
+                               " stop in the same entity\n");
            }
            NEXT;
            ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_PCDATA);
@@ -6272,7 +6088,7 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) {
            if (elem == NULL) {
                xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
                        "xmlParseElementMixedContentDecl : Name expected\n");
-               xmlFreeDocElementContent(ctxt->myDoc, cur);
+               xmlFreeDocElementContent(ctxt->myDoc, ret);
                return(NULL);
            }
            SKIP_BLANKS;
@@ -6287,10 +6103,10 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) {
             }
             if (ret != NULL)
                 ret->ocur = XML_ELEMENT_CONTENT_MULT;
-           if ((ctxt->validate) && (ctxt->input->id != inputchk)) {
-               xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY,
-"Element content declaration doesn't start and stop in the same entity\n",
-                                NULL, NULL);
+           if (ctxt->input->id != inputchk) {
+               xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                               "Element content declaration doesn't start and"
+                               " stop in the same entity\n");
            }
            SKIP(2);
        } else {
@@ -6530,10 +6346,10 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk,
        if (last != NULL)
            last->parent = cur;
     }
-    if ((ctxt->validate) && (ctxt->input->id != inputchk)) {
-       xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY,
-"Element content declaration doesn't start and stop in the same entity\n",
-                        NULL, NULL);
+    if (ctxt->input->id != inputchk) {
+       xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                       "Element content declaration doesn't start and stop in"
+                       " the same entity\n");
     }
     NEXT;
     if (RAW == '?') {
@@ -6706,28 +6522,24 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
 
     /* GROW; done in the caller */
     if (CMP9(CUR_PTR, '<', '!', 'E', 'L', 'E', 'M', 'E', 'N', 'T')) {
-       xmlParserInputPtr input = ctxt->input;
+       int inputid = ctxt->input->id;
 
        SKIP(9);
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space required after 'ELEMENT'\n");
            return(-1);
        }
-        SKIP_BLANKS;
         name = xmlParseName(ctxt);
        if (name == NULL) {
            xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
                           "xmlParseElementDecl: no name for Element\n");
            return(-1);
        }
-       while ((RAW == 0) && (ctxt->inputNr > 1))
-           xmlPopInput(ctxt);
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space required after the element name\n");
        }
-        SKIP_BLANKS;
        if (CMP5(CUR_PTR, 'E', 'M', 'P', 'T', 'Y')) {
            SKIP(5);
            /*
@@ -6759,12 +6571,6 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
        }
 
        SKIP_BLANKS;
-       /*
-        * Pop-up of finished entities.
-        */
-       while ((RAW == 0) && (ctxt->inputNr > 1))
-           xmlPopInput(ctxt);
-       SKIP_BLANKS;
 
        if (RAW != '>') {
            xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL);
@@ -6772,9 +6578,10 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
                xmlFreeDocElementContent(ctxt->myDoc, content);
            }
        } else {
-           if (input != ctxt->input) {
+           if (inputid != ctxt->input->id) {
                xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-    "Element declaration doesn't start and stop in the same entity\n");
+                               "Element declaration doesn't start and stop in"
+                               " the same entity\n");
            }
 
            NEXT;
@@ -6827,9 +6634,9 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
            return;
        } else {
            if (ctxt->input->id != id) {
-               xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY,
-           "All markup of the conditional section is not in the same entity\n",
-                                    NULL, NULL);
+               xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                              "All markup of the conditional section is not"
+                               " in the same entity\n");
            }
            NEXT;
        }
@@ -6842,6 +6649,8 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
                    "Entering INCLUDE Conditional Section\n");
        }
 
+        SKIP_BLANKS;
+        GROW;
        while (((RAW != 0) && ((RAW != ']') || (NXT(1) != ']') ||
                (NXT(2) != '>'))) && (ctxt->instate != XML_PARSER_EOF)) {
            const xmlChar *check = CUR_PTR;
@@ -6849,18 +6658,11 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
 
            if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
                xmlParseConditionalSections(ctxt);
-           } else if (IS_BLANK_CH(CUR)) {
-               NEXT;
-           } else if (RAW == '%') {
-               xmlParsePEReference(ctxt);
            } else
                xmlParseMarkupDecl(ctxt);
 
-           /*
-            * Pop-up of finished entities.
-            */
-           while ((RAW == 0) && (ctxt->inputNr > 1))
-               xmlPopInput(ctxt);
+            SKIP_BLANKS;
+            GROW;
 
            if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
                xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL);
@@ -6890,9 +6692,9 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
            return;
        } else {
            if (ctxt->input->id != id) {
-               xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY,
-           "All markup of the conditional section is not in the same entity\n",
-                                    NULL, NULL);
+               xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                              "All markup of the conditional section is not"
+                               " in the same entity\n");
            }
            NEXT;
        }
@@ -6954,9 +6756,9 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
        xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL);
     } else {
        if (ctxt->input->id != id) {
-           xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY,
-       "All markup of the conditional section is not in the same entity\n",
-                                NULL, NULL);
+           xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
+                          "All markup of the conditional section is not in"
+                           " the same entity\n");
        }
        if ((ctxt-> instate != XML_PARSER_EOF) &&
            ((ctxt->input->cur + 3) <= ctxt->input->end))
@@ -7024,13 +6826,6 @@ xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
         return;
 
     /*
-     * This is only for internal subset. On external entities,
-     * the replacement is done before parsing stage
-     */
-    if ((ctxt->external == 0) && (ctxt->inputNr == 1))
-       xmlParsePEReference(ctxt);
-
-    /*
      * Conditional sections are allowed from entities included
      * by PE References in the internal subset.
      */
@@ -7067,11 +6862,10 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
        return;
     }
 
-    if (!IS_BLANK_CH(CUR)) {
+    if (SKIP_BLANKS == 0) {
        xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                       "Space needed after '<?xml'\n");
     }
-    SKIP_BLANKS;
 
     /*
      * We may have the VersionInfo here.
@@ -7080,7 +6874,7 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
     if (version == NULL)
        version = xmlCharStrdup(XML_DEFAULT_VERSION);
     else {
-       if (!IS_BLANK_CH(CUR)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "Space needed here\n");
        }
@@ -7171,27 +6965,19 @@ xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID,
 
     ctxt->instate = XML_PARSER_DTD;
     ctxt->external = 1;
+    SKIP_BLANKS;
     while (((RAW == '<') && (NXT(1) == '?')) ||
            ((RAW == '<') && (NXT(1) == '!')) ||
-          (RAW == '%') || IS_BLANK_CH(CUR)) {
+          (RAW == '%')) {
        const xmlChar *check = CUR_PTR;
        unsigned int cons = ctxt->input->consumed;
 
        GROW;
         if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
            xmlParseConditionalSections(ctxt);
-       } else if (IS_BLANK_CH(CUR)) {
-           NEXT;
-       } else if (RAW == '%') {
-            xmlParsePEReference(ctxt);
        } else
            xmlParseMarkupDecl(ctxt);
-
-       /*
-        * Pop-up of finished entities.
-        */
-       while ((RAW == 0) && (ctxt->inputNr > 1))
-           xmlPopInput(ctxt);
+        SKIP_BLANKS;
 
        if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
            xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL);
@@ -7420,6 +7206,9 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
        }
        if (ent->checked == 0)
            ent->checked = 2;
+
+        /* Prevent entity from being parsed and expanded twice (Bug 760367). */
+        was_checked = 0;
     } else if (ent->checked != 1) {
        ctxt->nbentities += ent->checked / 2;
     }
@@ -8056,12 +7845,14 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
     NEXT;
     name = xmlParseName(ctxt);
     if (name == NULL) {
-       xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
-                      "xmlParsePEReference: no name\n");
+       xmlFatalErrMsg(ctxt, XML_ERR_PEREF_NO_NAME, "PEReference: no name\n");
        return;
     }
+    if (xmlParserDebugEntities)
+       xmlGenericError(xmlGenericErrorContext,
+               "PEReference: %s\n", name);
     if (RAW != ';') {
-       xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL);
+       xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL);
         return;
     }
 
@@ -8103,10 +7894,15 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
             * ... The declaration of a parameter entity must
             * precede any reference to it...
             */
-           xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY,
-                         "PEReference: %%%s; not found\n",
-                         name, NULL);
-           ctxt->valid = 0;
+            if ((ctxt->validate) && (ctxt->vctxt.error != NULL)) {
+                xmlValidityError(ctxt, XML_WAR_UNDECLARED_ENTITY,
+                                 "PEReference: %%%s; not found\n",
+                                 name, NULL);
+            } else
+                xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY,
+                              "PEReference: %%%s; not found\n",
+                              name, NULL);
+            ctxt->valid = 0;
        }
        xmlParserEntityCheck(ctxt, 0, NULL, 0);
     } else {
@@ -8118,33 +7914,54 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
            xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY,
                  "Internal: %%%s; is not a parameter entity\n",
                          name, NULL);
-       } else if (ctxt->input->free != deallocblankswrapper) {
-           input = xmlNewBlanksWrapperInputStream(ctxt, entity);
-           if (xmlPushInput(ctxt, input) < 0)
-               return;
        } else {
-           /*
-            * TODO !!!
-            * handle the extra spaces added before and after
-            * c.f. http://www.w3.org/TR/REC-xml#as-PE
-            */
+            xmlChar start[4];
+            xmlCharEncoding enc;
+
+           if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
+               ((ctxt->options & XML_PARSE_NOENT) == 0) &&
+               ((ctxt->options & XML_PARSE_DTDVALID) == 0) &&
+               ((ctxt->options & XML_PARSE_DTDLOAD) == 0) &&
+               ((ctxt->options & XML_PARSE_DTDATTR) == 0) &&
+               (ctxt->replaceEntities == 0) &&
+               (ctxt->validate == 0))
+               return;
+
            input = xmlNewEntityInputStream(ctxt, entity);
-           if (xmlPushInput(ctxt, input) < 0)
+           if (xmlPushInput(ctxt, input) < 0) {
+                xmlFreeInputStream(input);
                return;
-           if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
-               (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) &&
-               (IS_BLANK_CH(NXT(5)))) {
-               xmlParseTextDecl(ctxt);
-               if (ctxt->errNo ==
-                   XML_ERR_UNSUPPORTED_ENCODING) {
-                   /*
-                    * The XML REC instructs us to stop parsing
-                    * right here
-                    */
-                   xmlHaltParser(ctxt);
-                   return;
-               }
-           }
+            }
+
+           if (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) {
+                /*
+                 * Get the 4 first bytes and decode the charset
+                 * if enc != XML_CHAR_ENCODING_NONE
+                 * plug some encoding conversion routines.
+                 * Note that, since we may have some non-UTF8
+                 * encoding (like UTF16, bug 135229), the 'length'
+                 * is not known, but we can calculate based upon
+                 * the amount of data in the buffer.
+                 */
+                GROW
+                if (ctxt->instate == XML_PARSER_EOF)
+                    return;
+                if ((ctxt->input->end - ctxt->input->cur)>=4) {
+                    start[0] = RAW;
+                    start[1] = NXT(1);
+                    start[2] = NXT(2);
+                    start[3] = NXT(3);
+                    enc = xmlDetectCharEncoding(start, 4);
+                    if (enc != XML_CHAR_ENCODING_NONE) {
+                        xmlSwitchEncoding(ctxt, enc);
+                    }
+                }
+
+                if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) &&
+                    (IS_BLANK_CH(NXT(5)))) {
+                    xmlParseTextDecl(ctxt);
+                }
+            }
        }
     }
     ctxt->hasPErefs = 1;
@@ -8320,6 +8137,7 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) {
        entity = ctxt->sax->getParameterEntity(ctxt->userData, name);
     if (ctxt->instate == XML_PARSER_EOF) {
        xmlFree(name);
+       *str = ptr;
        return(NULL);
     }
     if (entity == NULL) {
@@ -8465,7 +8283,8 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) {
         * PEReferences.
         * Subsequence (markupdecl | PEReference | S)*
         */
-       while ((RAW != ']') && (ctxt->instate != XML_PARSER_EOF)) {
+       while (((RAW != ']') || (ctxt->inputNr > 1)) &&
+               (ctxt->instate != XML_PARSER_EOF)) {
            const xmlChar *check = CUR_PTR;
            unsigned int cons = ctxt->input->consumed;
 
@@ -8473,16 +8292,13 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) {
            xmlParseMarkupDecl(ctxt);
            xmlParsePEReference(ctxt);
 
-           /*
-            * Pop-up of finished entities.
-            */
-           while ((RAW == 0) && (ctxt->inputNr > 1))
-               xmlPopInput(ctxt);
-
            if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
                xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
             "xmlParseInternalSubset: error detected in Markup declaration\n");
-               break;
+                if (ctxt->inputNr > 1)
+                    xmlPopInput(ctxt);
+                else
+                   break;
            }
        }
        if (RAW == ']') {
@@ -8560,7 +8376,7 @@ xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) {
        ctxt->instate = XML_PARSER_CONTENT;
     } else {
        xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
-              "Specification mandate value for attribute %s\n", name);
+              "Specification mandates value for attribute %s\n", name);
        return(NULL);
     }
 
@@ -8717,11 +8533,10 @@ failed:
        GROW
        if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>'))))
            break;
-       if (!IS_BLANK_CH(RAW)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "attributes construct error\n");
        }
-       SKIP_BLANKS;
         if ((cons == ctxt->input->consumed) && (q == CUR_PTR) &&
             (attname == NULL) && (attvalue == NULL)) {
            xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
@@ -9293,7 +9108,7 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt,
         ctxt->instate = XML_PARSER_CONTENT;
     } else {
         xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
-                          "Specification mandate value for attribute %s\n",
+                          "Specification mandates value for attribute %s\n",
                           name);
         return (NULL);
     }
@@ -9376,9 +9191,8 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
     xmlChar *attvalue;
     const xmlChar **atts = ctxt->atts;
     int maxatts = ctxt->maxatts;
-    int nratts, nbatts, nbdef;
-    int i, j, nbNs, attval, oldline, oldcol, inputNr;
-    const xmlChar *base;
+    int nratts, nbatts, nbdef, inputid;
+    int i, j, nbNs, attval;
     unsigned long cur;
     int nsNr = ctxt->nsNr;
 
@@ -9392,13 +9206,9 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
      *       The Shrinking is only possible once the full set of attribute
      *       callbacks have been done.
      */
-reparse:
     SHRINK;
-    base = ctxt->input->base;
     cur = ctxt->input->cur - ctxt->input->base;
-    inputNr = ctxt->inputNr;
-    oldline = ctxt->input->line;
-    oldcol = ctxt->input->col;
+    inputid = ctxt->input->id;
     nbatts = 0;
     nratts = 0;
     nbdef = 0;
@@ -9422,8 +9232,6 @@ reparse:
      */
     SKIP_BLANKS;
     GROW;
-    if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
-        goto base_changed;
 
     while (((RAW != '>') &&
           ((RAW != '/') || (NXT(1) != '>')) &&
@@ -9434,211 +9242,181 @@ reparse:
 
        attname = xmlParseAttribute2(ctxt, prefix, localname,
                                     &aprefix, &attvalue, &len, &alloc);
-       if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr)) {
-           if ((attvalue != NULL) && (alloc != 0))
-               xmlFree(attvalue);
-           attvalue = NULL;
-           goto base_changed;
-       }
-        if ((attname != NULL) && (attvalue != NULL)) {
-           if (len < 0) len = xmlStrlen(attvalue);
-            if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) {
-               const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len);
-               xmlURIPtr uri;
-
-                if (URL == NULL) {
-                   xmlErrMemory(ctxt, "dictionary allocation failure");
-                   if ((attvalue != NULL) && (alloc != 0))
-                       xmlFree(attvalue);
-                   return(NULL);
-               }
-                if (*URL != 0) {
-                   uri = xmlParseURI((const char *) URL);
-                   if (uri == NULL) {
-                       xmlNsErr(ctxt, XML_WAR_NS_URI,
-                                "xmlns: '%s' is not a valid URI\n",
-                                          URL, NULL, NULL);
-                   } else {
-                       if (uri->scheme == NULL) {
-                           xmlNsWarn(ctxt, XML_WAR_NS_URI_RELATIVE,
-                                     "xmlns: URI %s is not absolute\n",
-                                     URL, NULL, NULL);
-                       }
-                       xmlFreeURI(uri);
-                   }
-                   if (URL == ctxt->str_xml_ns) {
-                       if (attname != ctxt->str_xml) {
-                           xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
-                        "xml namespace URI cannot be the default namespace\n",
-                                    NULL, NULL, NULL);
-                       }
-                       goto skip_default_ns;
-                   }
-                   if ((len == 29) &&
-                       (xmlStrEqual(URL,
-                                BAD_CAST "http://www.w3.org/2000/xmlns/"))) {
-                       xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
-                            "reuse of the xmlns namespace name is forbidden\n",
-                                NULL, NULL, NULL);
-                       goto skip_default_ns;
-                   }
-               }
-               /*
-                * check that it's not a defined namespace
-                */
-               for (j = 1;j <= nbNs;j++)
-                   if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL)
-                       break;
-               if (j <= nbNs)
-                   xmlErrAttributeDup(ctxt, NULL, attname);
-               else
-                   if (nsPush(ctxt, NULL, URL) > 0) nbNs++;
-skip_default_ns:
-               if ((attvalue != NULL) && (alloc != 0)) {
-                   xmlFree(attvalue);
-                   attvalue = NULL;
-               }
-               if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>'))))
-                   break;
-               if (!IS_BLANK_CH(RAW)) {
-                   xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
-                                  "attributes construct error\n");
-                   break;
-               }
-               SKIP_BLANKS;
-               if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
-                   goto base_changed;
-               continue;
-           }
-            if (aprefix == ctxt->str_xmlns) {
-               const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len);
-               xmlURIPtr uri;
-
-                if (attname == ctxt->str_xml) {
-                   if (URL != ctxt->str_xml_ns) {
-                       xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
-                                "xml namespace prefix mapped to wrong URI\n",
-                                NULL, NULL, NULL);
-                   }
-                   /*
-                    * Do not keep a namespace definition node
-                    */
-                   goto skip_ns;
-               }
+        if ((attname == NULL) || (attvalue == NULL))
+            goto next_attr;
+       if (len < 0) len = xmlStrlen(attvalue);
+
+        if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) {
+            const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len);
+            xmlURIPtr uri;
+
+            if (URL == NULL) {
+                xmlErrMemory(ctxt, "dictionary allocation failure");
+                if ((attvalue != NULL) && (alloc != 0))
+                    xmlFree(attvalue);
+                return(NULL);
+            }
+            if (*URL != 0) {
+                uri = xmlParseURI((const char *) URL);
+                if (uri == NULL) {
+                    xmlNsErr(ctxt, XML_WAR_NS_URI,
+                             "xmlns: '%s' is not a valid URI\n",
+                                       URL, NULL, NULL);
+                } else {
+                    if (uri->scheme == NULL) {
+                        xmlNsWarn(ctxt, XML_WAR_NS_URI_RELATIVE,
+                                  "xmlns: URI %s is not absolute\n",
+                                  URL, NULL, NULL);
+                    }
+                    xmlFreeURI(uri);
+                }
                 if (URL == ctxt->str_xml_ns) {
-                   if (attname != ctxt->str_xml) {
-                       xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
-                                "xml namespace URI mapped to wrong prefix\n",
-                                NULL, NULL, NULL);
-                   }
-                   goto skip_ns;
-               }
-                if (attname == ctxt->str_xmlns) {
-                   xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
-                            "redefinition of the xmlns prefix is forbidden\n",
-                            NULL, NULL, NULL);
-                   goto skip_ns;
-               }
-               if ((len == 29) &&
-                   (xmlStrEqual(URL,
-                                BAD_CAST "http://www.w3.org/2000/xmlns/"))) {
-                   xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
-                            "reuse of the xmlns namespace name is forbidden\n",
-                            NULL, NULL, NULL);
-                   goto skip_ns;
-               }
-               if ((URL == NULL) || (URL[0] == 0)) {
-                   xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
-                            "xmlns:%s: Empty XML namespace is not allowed\n",
-                                 attname, NULL, NULL);
-                   goto skip_ns;
-               } else {
-                   uri = xmlParseURI((const char *) URL);
-                   if (uri == NULL) {
-                       xmlNsErr(ctxt, XML_WAR_NS_URI,
-                            "xmlns:%s: '%s' is not a valid URI\n",
-                                          attname, URL, NULL);
-                   } else {
-                       if ((ctxt->pedantic) && (uri->scheme == NULL)) {
-                           xmlNsWarn(ctxt, XML_WAR_NS_URI_RELATIVE,
-                                     "xmlns:%s: URI %s is not absolute\n",
-                                     attname, URL, NULL);
-                       }
-                       xmlFreeURI(uri);
-                   }
-               }
-
-               /*
-                * check that it's not a defined namespace
-                */
-               for (j = 1;j <= nbNs;j++)
-                   if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname)
-                       break;
-               if (j <= nbNs)
-                   xmlErrAttributeDup(ctxt, aprefix, attname);
-               else
-                   if (nsPush(ctxt, attname, URL) > 0) nbNs++;
-skip_ns:
-               if ((attvalue != NULL) && (alloc != 0)) {
-                   xmlFree(attvalue);
-                   attvalue = NULL;
-               }
-               if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>'))))
-                   break;
-               if (!IS_BLANK_CH(RAW)) {
-                   xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
-                                  "attributes construct error\n");
-                   break;
-               }
-               SKIP_BLANKS;
-               if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
-                   goto base_changed;
-               continue;
-           }
+                    if (attname != ctxt->str_xml) {
+                        xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
+                     "xml namespace URI cannot be the default namespace\n",
+                                 NULL, NULL, NULL);
+                    }
+                    goto next_attr;
+                }
+                if ((len == 29) &&
+                    (xmlStrEqual(URL,
+                             BAD_CAST "http://www.w3.org/2000/xmlns/"))) {
+                    xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
+                         "reuse of the xmlns namespace name is forbidden\n",
+                             NULL, NULL, NULL);
+                    goto next_attr;
+                }
+            }
+            /*
+             * check that it's not a defined namespace
+             */
+            for (j = 1;j <= nbNs;j++)
+                if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL)
+                    break;
+            if (j <= nbNs)
+                xmlErrAttributeDup(ctxt, NULL, attname);
+            else
+                if (nsPush(ctxt, NULL, URL) > 0) nbNs++;
+
+        } else if (aprefix == ctxt->str_xmlns) {
+            const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len);
+            xmlURIPtr uri;
+
+            if (attname == ctxt->str_xml) {
+                if (URL != ctxt->str_xml_ns) {
+                    xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
+                             "xml namespace prefix mapped to wrong URI\n",
+                             NULL, NULL, NULL);
+                }
+                /*
+                 * Do not keep a namespace definition node
+                 */
+                goto next_attr;
+            }
+            if (URL == ctxt->str_xml_ns) {
+                if (attname != ctxt->str_xml) {
+                    xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
+                             "xml namespace URI mapped to wrong prefix\n",
+                             NULL, NULL, NULL);
+                }
+                goto next_attr;
+            }
+            if (attname == ctxt->str_xmlns) {
+                xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
+                         "redefinition of the xmlns prefix is forbidden\n",
+                         NULL, NULL, NULL);
+                goto next_attr;
+            }
+            if ((len == 29) &&
+                (xmlStrEqual(URL,
+                             BAD_CAST "http://www.w3.org/2000/xmlns/"))) {
+                xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
+                         "reuse of the xmlns namespace name is forbidden\n",
+                         NULL, NULL, NULL);
+                goto next_attr;
+            }
+            if ((URL == NULL) || (URL[0] == 0)) {
+                xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE,
+                         "xmlns:%s: Empty XML namespace is not allowed\n",
+                              attname, NULL, NULL);
+                goto next_attr;
+            } else {
+                uri = xmlParseURI((const char *) URL);
+                if (uri == NULL) {
+                    xmlNsErr(ctxt, XML_WAR_NS_URI,
+                         "xmlns:%s: '%s' is not a valid URI\n",
+                                       attname, URL, NULL);
+                } else {
+                    if ((ctxt->pedantic) && (uri->scheme == NULL)) {
+                        xmlNsWarn(ctxt, XML_WAR_NS_URI_RELATIVE,
+                                  "xmlns:%s: URI %s is not absolute\n",
+                                  attname, URL, NULL);
+                    }
+                    xmlFreeURI(uri);
+                }
+            }
 
-           /*
-            * Add the pair to atts
-            */
-           if ((atts == NULL) || (nbatts + 5 > maxatts)) {
-               if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) {
-                   if (attvalue[len] == 0)
-                       xmlFree(attvalue);
-                   goto failed;
-               }
-               maxatts = ctxt->maxatts;
-               atts = ctxt->atts;
-           }
-           ctxt->attallocs[nratts++] = alloc;
-           atts[nbatts++] = attname;
-           atts[nbatts++] = aprefix;
-           atts[nbatts++] = NULL; /* the URI will be fetched later */
-           atts[nbatts++] = attvalue;
-           attvalue += len;
-           atts[nbatts++] = attvalue;
-           /*
-            * tag if some deallocation is needed
-            */
-           if (alloc != 0) attval = 1;
-       } else {
-           if ((attvalue != NULL) && (attvalue[len] == 0))
-               xmlFree(attvalue);
-       }
+            /*
+             * check that it's not a defined namespace
+             */
+            for (j = 1;j <= nbNs;j++)
+                if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname)
+                    break;
+            if (j <= nbNs)
+                xmlErrAttributeDup(ctxt, aprefix, attname);
+            else
+                if (nsPush(ctxt, attname, URL) > 0) nbNs++;
+
+        } else {
+            /*
+             * Add the pair to atts
+             */
+            if ((atts == NULL) || (nbatts + 5 > maxatts)) {
+                if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) {
+                    goto next_attr;
+                }
+                maxatts = ctxt->maxatts;
+                atts = ctxt->atts;
+            }
+            ctxt->attallocs[nratts++] = alloc;
+            atts[nbatts++] = attname;
+            atts[nbatts++] = aprefix;
+            /*
+             * The namespace URI field is used temporarily to point at the
+             * base of the current input buffer for non-alloced attributes.
+             * When the input buffer is reallocated, all the pointers become
+             * invalid, but they can be reconstructed later.
+             */
+            if (alloc)
+                atts[nbatts++] = NULL;
+            else
+                atts[nbatts++] = ctxt->input->base;
+            atts[nbatts++] = attvalue;
+            attvalue += len;
+            atts[nbatts++] = attvalue;
+            /*
+             * tag if some deallocation is needed
+             */
+            if (alloc != 0) attval = 1;
+            attvalue = NULL; /* moved into atts */
+        }
 
-failed:
+next_attr:
+        if ((attvalue != NULL) && (alloc != 0)) {
+            xmlFree(attvalue);
+            attvalue = NULL;
+        }
 
        GROW
         if (ctxt->instate == XML_PARSER_EOF)
             break;
-       if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
-           goto base_changed;
        if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>'))))
            break;
-       if (!IS_BLANK_CH(RAW)) {
+       if (SKIP_BLANKS == 0) {
            xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
                           "attributes construct error\n");
            break;
        }
-       SKIP_BLANKS;
         if ((cons == ctxt->input->consumed) && (q == CUR_PTR) &&
             (attname == NULL) && (attvalue == NULL)) {
            xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
@@ -9646,8 +9424,27 @@ failed:
            break;
        }
         GROW;
-       if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr))
-           goto base_changed;
+    }
+
+    if (ctxt->input->id != inputid) {
+        xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
+                    "Unexpected change of input\n");
+        localname = NULL;
+        goto done;
+    }
+
+    /* Reconstruct attribute value pointers. */
+    for (i = 0, j = 0; j < nratts; i += 5, j++) {
+        if (atts[i+2] != NULL) {
+            /*
+             * Arithmetic on dangling pointers is technically undefined
+             * behavior, but well...
+             */
+            ptrdiff_t offset = ctxt->input->base - atts[i+2];
+            atts[i+2]  = NULL;    /* Reset repurposed namespace URI */
+            atts[i+3] += offset;  /* value */
+            atts[i+4] += offset;  /* valuend */
+        }
     }
 
     /*
@@ -9794,6 +9591,7 @@ failed:
                          nsname, 0, NULL, nbatts / 5, nbdef, atts);
     }
 
+done:
     /*
      * Free up attribute allocated strings if needed
      */
@@ -9804,34 +9602,6 @@ failed:
     }
 
     return(localname);
-
-base_changed:
-    /*
-     * the attribute strings are valid iif the base didn't changed
-     */
-    if (attval != 0) {
-       for (i = 3,j = 0; j < nratts;i += 5,j++)
-           if ((ctxt->attallocs[j] != 0) && (atts[i] != NULL))
-               xmlFree((xmlChar *) atts[i]);
-    }
-
-    /*
-     * We can't switch from one entity to another in the middle
-     * of a start tag
-     */
-    if (inputNr != ctxt->inputNr) {
-        xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-                   "Start tag doesn't start and stop in the same entity\n");
-       return(NULL);
-    }
-
-    ctxt->input->cur = ctxt->input->base + cur;
-    ctxt->input->line = oldline;
-    ctxt->input->col = oldcol;
-    if (ctxt->wellFormed == 1) {
-       goto reparse;
-    }
-    return(NULL);
 }
 
 /**
@@ -10100,11 +9870,6 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
        }
 
        GROW;
-       /*
-        * Pop-up of finished entities.
-        */
-       while ((RAW == 0) && (ctxt->inputNr > 1))
-           xmlPopInput(ctxt);
        SHRINK;
 
        if ((cons == ctxt->input->consumed) && (test == CUR_PTR)) {
@@ -11257,7 +11022,7 @@ xmlParseGetLasts(xmlParserCtxtPtr ctxt, const xmlChar **lastlt,
  * Check that the block of characters is okay as SCdata content [20]
  *
  * Returns the number of bytes to pass if okay, a negative index where an
- *         UTF-8 error occured otherwise
+ *         UTF-8 error occurred otherwise
  */
 static int
 xmlCheckCdataPush(const xmlChar *utf, int len, int complete) {
@@ -11399,13 +11164,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
        if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1))
            return(0);
 
-
-       /*
-        * Pop-up of finished entities.
-        */
-       while ((RAW == 0) && (ctxt->inputNr > 1))
-           xmlPopInput(ctxt);
-
        if (ctxt->input == NULL) break;
        if (ctxt->input->buf == NULL)
            avail = ctxt->input->length -
@@ -11756,11 +11514,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
                    ctxt->checkIndex = 0;
                    xmlParseCharData(ctxt, 0);
                }
-               /*
-                * Pop-up of finished entities.
-                */
-               while ((RAW == 0) && (ctxt->inputNr > 1))
-                   xmlPopInput(ctxt);
                if ((cons == ctxt->input->consumed) && (test == CUR_PTR)) {
                    xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
                                "detected an error in element content\n");
@@ -12703,6 +12456,8 @@ xmlHaltParser(xmlParserCtxtPtr ctxt) {
         return;
     ctxt->instate = XML_PARSER_EOF;
     ctxt->disableSAX = 1;
+    while (ctxt->inputNr > 1)
+        xmlFreeInputStream(inputPop(ctxt));
     if (ctxt->input != NULL) {
         /*
         * in case there was a specific allocation deallocate before
@@ -12714,6 +12469,7 @@ xmlHaltParser(xmlParserCtxtPtr ctxt) {
        }
        ctxt->input->cur = BAD_CAST"";
        ctxt->input->base = ctxt->input->cur;
+        ctxt->input->end = ctxt->input->cur;
     }
 }
 
@@ -13482,7 +13238,7 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
     /*
      * And record the last error if any
      */
-    if (ctxt->lastError.code != XML_ERR_OK)
+    if ((oldctxt != NULL) && (ctxt->lastError.code != XML_ERR_OK))
         xmlCopyError(&ctxt->lastError, &oldctxt->lastError);
 
     if (sax != NULL)