diff options
Diffstat (limited to 'parser.c')
-rw-r--r-- | parser.c | 1310 |
1 files changed, 527 insertions, 783 deletions
@@ -30,10 +30,15 @@ * 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" -#if defined(WIN32) && !defined (__CYGWIN__) +#if defined(_WIN32) && !defined (__CYGWIN__) #define XML_DIR_SEP '\\' #else #define XML_DIR_SEP '/' @@ -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> @@ -77,12 +83,6 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif -#ifdef HAVE_ZLIB_H -#include <zlib.h> -#endif -#ifdef HAVE_LZMA_H -#include <lzma.h> -#endif #include "buf.h" #include "enc.h" @@ -149,7 +149,7 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, rep = xmlStringDecodeEntities(ctxt, ent->content, XML_SUBSTITUTE_REF, 0, 0, 0); --ctxt->depth; - if (ctxt->errNo == XML_ERR_ENTITY_LOOP) { + if ((rep == NULL) || (ctxt->errNo == XML_ERR_ENTITY_LOOP)) { ent->content[0] = 0; } @@ -1087,7 +1087,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 }; /** @@ -1324,7 +1329,7 @@ xmlAddSpecialAttr(xmlParserCtxtPtr ctxt, return; xmlHashAddEntry2(ctxt->attsSpecial, fullname, fullattr, - (void *) (long) type); + (void *) (ptrdiff_t) type); return; mem_error: @@ -1343,7 +1348,7 @@ xmlCleanSpecialAttrCallback(void *payload, void *data, const xmlChar *unused ATTRIBUTE_UNUSED) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) data; - if (((long) payload) == XML_ATTRIBUTE_CDATA) { + if (((ptrdiff_t) payload) == XML_ATTRIBUTE_CDATA) { xmlHashRemoveEntry2(ctxt->attsSpecial, fullname, fullattr, NULL); } } @@ -1855,7 +1860,7 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, ctxt->name = value; ctxt->pushTab[ctxt->nameNr * 3] = (void *) prefix; ctxt->pushTab[ctxt->nameNr * 3 + 1] = (void *) URI; - ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) (long) nsNr; + ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) (ptrdiff_t) nsNr; return (ctxt->nameNr++); mem_error: xmlErrMemory(ctxt, NULL); @@ -2037,10 +2042,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 +2055,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 +2066,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)) \ @@ -2080,7 +2080,8 @@ static void xmlGROW (xmlParserCtxtPtr ctxt) { if (((curEnd > (unsigned long) XML_MAX_LOOKUP_LIMIT) || (curBase > (unsigned long) XML_MAX_LOOKUP_LIMIT)) && - ((ctxt->input->buf) && (ctxt->input->buf->readcallback != (xmlInputReadCallback) xmlNop)) && + ((ctxt->input->buf) && + (ctxt->input->buf->readcallback != xmlInputReadCallbackNop)) && ((ctxt->options & XML_PARSE_HUGE) == 0)) { xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "Huge input lookup"); xmlHaltParser(ctxt); @@ -2093,9 +2094,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 +2115,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 +2164,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 +2218,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 +2250,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 +2462,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 +2495,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 +2549,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); } /* @@ -2790,9 +2631,9 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, if (c == 0) break; if ((c == '&') && (str[1] == '#')) { int val = xmlParseStringCharRef(ctxt, &str); - if (val != 0) { - COPY_BUF(0,buffer,nbchars,val); - } + if (val == 0) + goto int_error; + COPY_BUF(0,buffer,nbchars,val); if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { growBuffer(buffer, XML_PARSER_BUFFER_SIZE); } @@ -2802,9 +2643,6 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, "String decoding Entity Reference: %.30s\n", str); ent = xmlParseStringEntityRef(ctxt, &str); - if ((ctxt->lastError.code == XML_ERR_ENTITY_LOOP) || - (ctxt->lastError.code == XML_ERR_INTERNAL_ERROR)) - goto int_error; xmlParserEntityCheck(ctxt, 0, ent, 0); if (ent != NULL) ctxt->nbentities += ent->checked / 2; @@ -2818,30 +2656,27 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, } else { xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "predefined entity has no content\n"); + goto int_error; } } else if ((ent != NULL) && (ent->content != NULL)) { ctxt->depth++; rep = xmlStringDecodeEntities(ctxt, ent->content, what, 0, 0, 0); ctxt->depth--; - - if ((ctxt->lastError.code == XML_ERR_ENTITY_LOOP) || - (ctxt->lastError.code == XML_ERR_INTERNAL_ERROR)) - goto int_error; - - if (rep != NULL) { - current = rep; - while (*current != 0) { /* non input consuming loop */ - buffer[nbchars++] = *current++; - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) - goto int_error; - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } - xmlFree(rep); - rep = NULL; - } + if (rep == NULL) + goto int_error; + + current = rep; + while (*current != 0) { /* non input consuming loop */ + buffer[nbchars++] = *current++; + if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { + if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) + goto int_error; + growBuffer(buffer, XML_PARSER_BUFFER_SIZE); + } + } + xmlFree(rep); + rep = NULL; } else if (ent != NULL) { int i = xmlStrlen(ent->name); const xmlChar *cur = ent->name; @@ -2859,8 +2694,6 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, xmlGenericError(xmlGenericErrorContext, "String decoding PE Reference: %.30s\n", str); ent = xmlParseStringPEReference(ctxt, &str); - if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP) - goto int_error; xmlParserEntityCheck(ctxt, 0, ent, 0); if (ent != NULL) ctxt->nbentities += ent->checked / 2; @@ -2886,19 +2719,19 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, rep = xmlStringDecodeEntities(ctxt, ent->content, what, 0, 0, 0); ctxt->depth--; - if (rep != NULL) { - current = rep; - while (*current != 0) { /* non input consuming loop */ - buffer[nbchars++] = *current++; - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) - goto int_error; - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } - xmlFree(rep); - rep = NULL; - } + if (rep == NULL) + goto int_error; + current = rep; + while (*current != 0) { /* non input consuming loop */ + buffer[nbchars++] = *current++; + if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { + if (xmlParserEntityCheck(ctxt, nbchars, ent, 0)) + goto int_error; + growBuffer(buffer, XML_PARSER_BUFFER_SIZE); + } + } + xmlFree(rep); + rep = NULL; } } else { COPY_BUF(l,buffer,nbchars,c); @@ -3406,13 +3239,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,15 +3246,18 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name"); return(NULL); } - if (ctxt->input->cur > ctxt->input->base && (*ctxt->input->cur == '\n') && (ctxt->input->cur[-1] == '\r')) { - if (ctxt->input->base > ctxt->input->cur - (len + 1)) { - return(NULL); - } - return(xmlDictLookup(ctxt->dict, ctxt->input->cur - (len + 1), len)); - } - if (ctxt->input->base > ctxt->input->cur - len) { - 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)); } @@ -3541,9 +3370,9 @@ xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) { */ ctxt->input->cur -= l; GROW; - ctxt->input->cur += l; if (ctxt->instate == XML_PARSER_EOF) return(NULL); + ctxt->input->cur += l; c = CUR_CHAR(l); } } @@ -3899,10 +3728,8 @@ xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { ctxt->instate = XML_PARSER_ENTITY_VALUE; input = ctxt->input; GROW; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return(NULL); - } + if (ctxt->instate == XML_PARSER_EOF) + goto error; NEXT; c = CUR_CHAR(l); /* @@ -3923,18 +3750,12 @@ xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); if (tmp == NULL) { xmlErrMemory(ctxt, NULL); - xmlFree(buf); - return(NULL); + goto error; } buf = tmp; } 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); @@ -3944,10 +3765,13 @@ xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { } } buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return(NULL); + if (ctxt->instate == XML_PARSER_EOF) + goto error; + if (c != stop) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); + goto error; } + NEXT; /* * Raise problem w.r.t. '&' and '%' being used in non-entities @@ -3959,20 +3783,25 @@ xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) { xmlChar *name; xmlChar tmp = *cur; + int nameOk = 0; cur++; name = xmlParseStringName(ctxt, &cur); - if ((name == NULL) || (*cur != ';')) { + if (name != NULL) { + nameOk = 1; + xmlFree(name); + } + if ((nameOk == 0) || (*cur != ';')) { xmlFatalErrMsgInt(ctxt, XML_ERR_ENTITY_CHAR_ERROR, "EntityValue: '%c' forbidden except for entities references\n", tmp); + goto error; } if ((tmp == '%') && (ctxt->inSubset == 1) && (ctxt->inputNr == 1)) { xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); + goto error; } - if (name != NULL) - xmlFree(name); if (*cur == 0) break; } @@ -3981,28 +3810,24 @@ xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { /* * Then PEReference entities are substituted. + * + * NOTE: 4.4.7 Bypassed + * When a general entity reference appears in the EntityValue in + * an entity declaration, it is bypassed and left as is. + * so XML_SUBSTITUTE_REF is not set here. */ - if (c != stop) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); - xmlFree(buf); - } else { - NEXT; - /* - * NOTE: 4.4.7 Bypassed - * When a general entity reference appears in the EntityValue in - * an entity declaration, it is bypassed and left as is. - * so XML_SUBSTITUTE_REF is not set here. - */ - ++ctxt->depth; - ret = xmlStringDecodeEntities(ctxt, buf, XML_SUBSTITUTE_PEREF, - 0, 0, 0); - --ctxt->depth; - if (orig != NULL) - *orig = buf; - else - xmlFree(buf); + ++ctxt->depth; + ret = xmlStringDecodeEntities(ctxt, buf, XML_SUBSTITUTE_PEREF, + 0, 0, 0); + --ctxt->depth; + if (orig != NULL) { + *orig = buf; + buf = NULL; } +error: + if (buf != NULL) + xmlFree(buf); return(ret); } @@ -4172,7 +3997,9 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) { ent->checked |= 1; xmlFree(rep); rep = NULL; - } + } else { + ent->content[0] = 0; + } } /* @@ -4596,7 +4423,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++; @@ -4789,22 +4616,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); @@ -4813,26 +4638,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); @@ -4962,7 +4781,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) && @@ -5110,7 +4930,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) && @@ -5278,7 +5099,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; /* @@ -5294,9 +5115,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); @@ -5317,12 +5139,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) != '>'))) { @@ -5378,9 +5198,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); @@ -5436,32 +5257,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. @@ -5470,9 +5289,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) && @@ -5516,23 +5336,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"); } @@ -5550,8 +5367,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"); } @@ -5662,18 +5478,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)) @@ -5712,16 +5526,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; } @@ -5743,17 +5558,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); } } @@ -5804,11 +5619,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; @@ -5980,12 +5794,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); @@ -6089,14 +5902,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, @@ -6106,7 +5918,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; @@ -6120,12 +5931,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) { @@ -6133,14 +5943,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) { @@ -6155,7 +5964,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) @@ -6164,16 +5973,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)) @@ -6195,10 +5994,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; } @@ -6235,10 +6034,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); @@ -6279,7 +6078,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; @@ -6294,10 +6093,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 { @@ -6537,10 +6336,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 == '?') { @@ -6713,28 +6512,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); /* @@ -6766,12 +6561,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); @@ -6779,9 +6568,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; @@ -6834,9 +6624,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; } @@ -6849,6 +6639,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; @@ -6856,18 +6648,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); @@ -6897,9 +6682,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; } @@ -6961,9 +6746,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)) @@ -7031,13 +6816,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. */ @@ -7074,11 +6852,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. @@ -7087,7 +6864,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"); } @@ -7178,27 +6955,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 +7189,8 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { (ret != XML_WAR_UNDECLARED_ENTITY)) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, "Entity '%s' failed to parse\n", ent->name); + if (ent->content != NULL) + ent->content[0] = 0; xmlParserEntityCheck(ctxt, 0, ent, 0); } else if (list != NULL) { xmlFreeNodeList(list); @@ -7427,6 +7198,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; } @@ -8063,12 +7837,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; } @@ -8110,10 +7886,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 { @@ -8125,41 +7906,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 { + 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; - /* - * TODO !!! - * handle the extra spaces added before and after - * c.f. http://www.w3.org/TR/REC-xml#as-PE - */ + ((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; @@ -8335,6 +8129,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) { @@ -8473,6 +8268,7 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { * Is there any DTD definition ? */ if (RAW == '[') { + int baseInputNr = ctxt->inputNr; ctxt->instate = XML_PARSER_DTD; NEXT; /* @@ -8480,7 +8276,8 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { * PEReferences. * Subsequence (markupdecl | PEReference | S)* */ - while ((RAW != ']') && (ctxt->instate != XML_PARSER_EOF)) { + while (((RAW != ']') || (ctxt->inputNr > baseInputNr)) && + (ctxt->instate != XML_PARSER_EOF)) { const xmlChar *check = CUR_PTR; unsigned int cons = ctxt->input->consumed; @@ -8488,16 +8285,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 > baseInputNr) + xmlPopInput(ctxt); + else + break; } } if (RAW == ']') { @@ -8575,7 +8369,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); } @@ -8732,11 +8526,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, @@ -9274,8 +9067,8 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, if (ctxt->attsSpecial != NULL) { int type; - type = (int) (long) xmlHashQLookup2(ctxt->attsSpecial, - pref, elem, *prefix, name); + type = (int) (ptrdiff_t) xmlHashQLookup2(ctxt->attsSpecial, + pref, elem, *prefix, name); if (type != 0) normalize = 1; } @@ -9308,7 +9101,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); } @@ -9391,9 +9184,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; @@ -9407,13 +9199,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; @@ -9437,8 +9225,6 @@ reparse: */ SKIP_BLANKS; GROW; - if ((ctxt->input->base != base) || (inputNr != ctxt->inputNr)) - goto base_changed; while (((RAW != '>') && ((RAW != '/') || (NXT(1) != '>')) && @@ -9449,211 +9235,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, @@ -9661,8 +9417,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 */ + } } /* @@ -9809,6 +9584,7 @@ failed: nsname, 0, NULL, nbatts / 5, nbdef, atts); } +done: /* * Free up attribute allocated strings if needed */ @@ -9819,34 +9595,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); } /** @@ -10115,11 +9863,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)) { @@ -11272,7 +11015,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) { @@ -11414,13 +11157,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 - @@ -11771,11 +11507,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"); @@ -11798,9 +11529,10 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { } if (ctxt->sax2) { xmlParseEndTag2(ctxt, - (void *) ctxt->pushTab[ctxt->nameNr * 3 - 3], - (void *) ctxt->pushTab[ctxt->nameNr * 3 - 2], 0, - (int) (long) ctxt->pushTab[ctxt->nameNr * 3 - 1], 0); + (void *) ctxt->pushTab[ctxt->nameNr * 3 - 3], + (void *) ctxt->pushTab[ctxt->nameNr * 3 - 2], 0, + (int) (ptrdiff_t) + ctxt->pushTab[ctxt->nameNr * 3 - 1], 0); nameNsPop(ctxt); } #ifdef LIBXML_SAX1_ENABLED @@ -12486,6 +12218,7 @@ xmldecl_done: /* TODO 2.6.0 */ xmlGenericError(xmlGenericErrorContext, "xmlParseChunk: encoder error\n"); + xmlHaltParser(ctxt); return(XML_ERR_INVALID_ENCODING); } xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current); @@ -12718,6 +12451,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 @@ -12729,6 +12464,7 @@ xmlHaltParser(xmlParserCtxtPtr ctxt) { } ctxt->input->cur = BAD_CAST""; ctxt->input->base = ctxt->input->cur; + ctxt->input->end = ctxt->input->cur; } } @@ -13497,7 +13233,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) @@ -13631,6 +13367,7 @@ xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, ctxt->userData = ctxt; if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); ctxt->dict = oldctxt->dict; + ctxt->input_id = oldctxt->input_id + 1; ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); @@ -13884,6 +13621,7 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, xmlDetectSAX2(ctxt); ctxt->myDoc = doc; /* parsing in context, i.e. as within existing content */ + ctxt->input_id = 2; ctxt->instate = XML_PARSER_CONTENT; fake = xmlNewComment(NULL); @@ -14096,6 +13834,7 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, newDoc->oldNs = doc->oldNs; } ctxt->instate = XML_PARSER_CONTENT; + ctxt->input_id = 2; ctxt->depth = depth; /* @@ -14256,6 +13995,11 @@ xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID, if (pctx != NULL) { ctxt->options = pctx->options; ctxt->_private = pctx->_private; + /* + * this is a subparser of pctx, so the input_id should be + * incremented to distinguish from main entity + */ + ctxt->input_id = pctx->input_id + 1; } uri = xmlBuildURI(URL, base); @@ -15137,7 +14881,7 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) xmlInitNodeInfoSeq(&ctxt->node_seq); if (ctxt->attsDefault != NULL) { - xmlHashFree(ctxt->attsDefault, (xmlHashDeallocator) xmlFree); + xmlHashFree(ctxt->attsDefault, xmlHashDefaultDeallocator); ctxt->attsDefault = NULL; } if (ctxt->attsSpecial != NULL) { |