diff options
author | setser <[email protected]> | 2022-05-09 00:13:37 +0300 |
---|---|---|
committer | setser <[email protected]> | 2022-05-09 00:13:37 +0300 |
commit | e87e3fc8d0e04eb7ba3eee221bb91613b527ad85 (patch) | |
tree | 5279c128bdbdf902b9a08d9fae8e55b91910a553 /contrib/libs/libxml/parser.c | |
parent | f4f3e4024a1f32bd0bc3fa20239025a1b179e42d (diff) |
Update libxml to 2.9.13
ref:f572491d236694e847142c36f0f5546c649e05d7
Diffstat (limited to 'contrib/libs/libxml/parser.c')
-rw-r--r-- | contrib/libs/libxml/parser.c | 657 |
1 files changed, 303 insertions, 354 deletions
diff --git a/contrib/libs/libxml/parser.c b/contrib/libs/libxml/parser.c index a34bb6cdd81..8ca9b2ddcf1 100644 --- a/contrib/libs/libxml/parser.c +++ b/contrib/libs/libxml/parser.c @@ -87,6 +87,13 @@ #include "buf.h" #include "enc.h" +struct _xmlStartTag { + const xmlChar *prefix; + const xmlChar *URI; + int line; + int nsNr; +}; + static void xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info); @@ -133,6 +140,7 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, xmlEntityPtr ent, size_t replacement) { size_t consumed = 0; + int i; if ((ctxt == NULL) || (ctxt->options & XML_PARSE_HUGE)) return (0); @@ -170,6 +178,28 @@ xmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size, rep = NULL; } } + + /* + * Prevent entity exponential check, not just replacement while + * parsing the DTD + * The check is potentially costly so do that only once in a thousand + */ + if ((ctxt->instate == XML_PARSER_DTD) && (ctxt->nbentities > 10000) && + (ctxt->nbentities % 1024 == 0)) { + for (i = 0;i < ctxt->inputNr;i++) { + consumed += ctxt->inputTab[i]->consumed + + (ctxt->inputTab[i]->cur - ctxt->inputTab[i]->base); + } + if (ctxt->nbentities > consumed * XML_PARSER_NON_LINEAR) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + ctxt->instate = XML_PARSER_EOF; + return (1); + } + consumed = 0; + } + + + if (replacement != 0) { if (replacement < XML_MAX_TEXT_LENGTH) return(0); @@ -1073,11 +1103,15 @@ xmlHasFeature(xmlFeature feature) */ static void xmlDetectSAX2(xmlParserCtxtPtr ctxt) { + xmlSAXHandlerPtr sax; if (ctxt == NULL) return; + sax = ctxt->sax; #ifdef LIBXML_SAX1_ENABLED - if ((ctxt->sax) && (ctxt->sax->initialized == XML_SAX2_MAGIC) && - ((ctxt->sax->startElementNs != NULL) || - (ctxt->sax->endElementNs != NULL))) ctxt->sax2 = 1; + if ((sax) && (sax->initialized == XML_SAX2_MAGIC) && + ((sax->startElementNs != NULL) || + (sax->endElementNs != NULL) || + ((sax->startElement == NULL) && (sax->endElement == NULL)))) + ctxt->sax2 = 1; #else ctxt->sax2 = 1; #endif /* LIBXML_SAX1_ENABLED */ @@ -1834,6 +1868,8 @@ nodePop(xmlParserCtxtPtr ctxt) * @value: the element name * @prefix: the element prefix * @URI: the element namespace name + * @line: the current line number for error messages + * @nsNr: the number of namespaces pushed on the namespace table * * Pushes a new element name/prefix/URL on top of the name stack * @@ -1841,11 +1877,13 @@ nodePop(xmlParserCtxtPtr ctxt) */ static int nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, - const xmlChar *prefix, const xmlChar *URI, int nsNr) + const xmlChar *prefix, const xmlChar *URI, int line, int nsNr) { + xmlStartTag *tag; + if (ctxt->nameNr >= ctxt->nameMax) { const xmlChar * *tmp; - void **tmp2; + xmlStartTag *tmp2; ctxt->nameMax *= 2; tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, ctxt->nameMax * @@ -1855,8 +1893,8 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, goto mem_error; } ctxt->nameTab = tmp; - tmp2 = (void **) xmlRealloc((void * *)ctxt->pushTab, - ctxt->nameMax * 3 * + tmp2 = (xmlStartTag *) xmlRealloc((void * *)ctxt->pushTab, + ctxt->nameMax * sizeof(ctxt->pushTab[0])); if (tmp2 == NULL) { ctxt->nameMax /= 2; @@ -1864,16 +1902,18 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, } ctxt->pushTab = tmp2; } else if (ctxt->pushTab == NULL) { - ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 * + ctxt->pushTab = (xmlStartTag *) xmlMalloc(ctxt->nameMax * sizeof(ctxt->pushTab[0])); if (ctxt->pushTab == NULL) goto mem_error; } ctxt->nameTab[ctxt->nameNr] = value; ctxt->name = value; - ctxt->pushTab[ctxt->nameNr * 3] = (void *) prefix; - ctxt->pushTab[ctxt->nameNr * 3 + 1] = (void *) URI; - ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) (ptrdiff_t) nsNr; + tag = &ctxt->pushTab[ctxt->nameNr]; + tag->prefix = prefix; + tag->URI = URI; + tag->line = line; + tag->nsNr = nsNr; return (ctxt->nameNr++); mem_error: xmlErrMemory(ctxt, NULL); @@ -2055,7 +2095,7 @@ static int spacePop(xmlParserCtxtPtr ctxt) { ((unsigned char *) s)[ 9 ] == c10 ) #define SKIP(val) do { \ - ctxt->nbChars += (val),ctxt->input->cur += (val),ctxt->input->col+=(val); \ + ctxt->input->cur += (val),ctxt->input->col+=(val); \ if (*ctxt->input->cur == 0) \ xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ } while (0) @@ -2066,7 +2106,6 @@ static int spacePop(xmlParserCtxtPtr ctxt) { if (*(ctxt->input->cur) == '\n') { \ ctxt->input->line++; ctxt->input->col = 1; \ } else ctxt->input->col++; \ - ctxt->nbChars++; \ ctxt->input->cur++; \ } \ if (*ctxt->input->cur == 0) \ @@ -2119,7 +2158,6 @@ static void xmlGROW (xmlParserCtxtPtr ctxt) { #define NEXT1 { \ ctxt->input->col++; \ ctxt->input->cur++; \ - ctxt->nbChars++; \ if (*ctxt->input->cur == 0) \ xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ } @@ -2156,7 +2194,8 @@ xmlSkipBlankChars(xmlParserCtxtPtr ctxt) { * It's Okay to use CUR/NEXT here since all the blanks are on * the ASCII range. */ - if ((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) { + if (((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) || + (ctxt->instate == XML_PARSER_START)) { const xmlChar *cur; /* * if we are in the document content, go really fast @@ -2332,7 +2371,6 @@ xmlParseCharRef(xmlParserCtxtPtr ctxt) { if (RAW == ';') { /* on purpose to avoid reentrancy problems with NEXT and SKIP */ ctxt->input->col++; - ctxt->nbChars ++; ctxt->input->cur++; } } else if ((RAW == '&') && (NXT(1) == '#')) { @@ -2361,7 +2399,6 @@ xmlParseCharRef(xmlParserCtxtPtr ctxt) { if (RAW == ';') { /* on purpose to avoid reentrancy problems with NEXT and SKIP */ ctxt->input->col++; - ctxt->nbChars ++; ctxt->input->cur++; } } else { @@ -2684,8 +2721,10 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, rep = xmlStringDecodeEntities(ctxt, ent->content, what, 0, 0, 0); ctxt->depth--; - if (rep == NULL) + if (rep == NULL) { + ent->content[0] = 0; goto int_error; + } current = rep; while (*current != 0) { /* non input consuming loop */ @@ -2740,8 +2779,11 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, rep = xmlStringDecodeEntities(ctxt, ent->content, what, 0, 0, 0); ctxt->depth--; - if (rep == NULL) + if (rep == NULL) { + if (ent->content != NULL) + ent->content[0] = 0; goto int_error; + } current = rep; while (*current != 0) { /* non input consuming loop */ buffer[nbchars++] = *current++; @@ -3333,7 +3375,6 @@ xmlParseName(xmlParserCtxtPtr ctxt) { } ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); ctxt->input->cur = in; - ctxt->nbChars += count; ctxt->input->col += count; if (ret == NULL) xmlErrMemory(ctxt, NULL); @@ -3456,7 +3497,6 @@ xmlParseNCName(xmlParserCtxtPtr ctxt) { } ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); ctxt->input->cur = in; - ctxt->nbChars += count; ctxt->input->col += count; if (ret == NULL) { xmlErrMemory(ctxt, NULL); @@ -3493,10 +3533,10 @@ xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { while (*in != 0 && *in == *cmp) { ++in; ++cmp; - ctxt->input->col++; } if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { /* success */ + ctxt->input->col += in - ctxt->input->cur; ctxt->input->cur = in; return (const xmlChar*) 1; } @@ -3912,7 +3952,6 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) { "AttValue length too long\n"); goto mem_error; } - if (c == 0) break; if (c == '&') { in_space = 0; if (NXT(1) == '#') { @@ -4207,6 +4246,7 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { } count++; if (count > 50) { + SHRINK; GROW; count = 0; if (ctxt->instate == XML_PARSER_EOF) { @@ -4294,6 +4334,7 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) { buf[len++] = cur; count++; if (count > 50) { + SHRINK; GROW; count = 0; if (ctxt->instate == XML_PARSER_EOF) { @@ -4509,7 +4550,7 @@ get_more: if (ctxt->instate == XML_PARSER_EOF) return; in = ctxt->input->cur; - } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09)); + } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a)); nbchar = 0; } ctxt->input->line = line; @@ -4547,6 +4588,9 @@ xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) { } } COPY_BUF(l,buf,nbchar,cur); + /* move current position before possible calling of ctxt->sax->characters */ + NEXTL(l); + cur = CUR_CHAR(l); if (nbchar >= XML_PARSER_BIG_BUFFER_SIZE) { buf[nbchar] = 0; @@ -4574,13 +4618,12 @@ xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) { } count++; if (count > 50) { + SHRINK; GROW; count = 0; if (ctxt->instate == XML_PARSER_EOF) return; } - NEXTL(l); - cur = CUR_CHAR(l); } if (nbchar != 0) { buf[nbchar] = 0; @@ -4779,6 +4822,7 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, count++; if (count > 50) { + SHRINK; GROW; count = 0; if (ctxt->instate == XML_PARSER_EOF) { @@ -4938,7 +4982,7 @@ get_more: ctxt->input->cur = in; in++; ctxt->input->line++; ctxt->input->col = 1; - continue; /* while */ + goto get_more; } in--; } @@ -4990,7 +5034,7 @@ get_more: ctxt->input->col++; goto get_more; } - } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09)); + } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a)); xmlParseCommentComplex(ctxt, buf, len, size); ctxt->instate = state; return; @@ -5054,7 +5098,7 @@ xmlParsePITarget(xmlParserCtxtPtr ctxt) { * <?oasis-xml-catalog catalog="http://example.com/catalog.xml"?> * * Occurs only if allowed by the user and if happening in the Misc - * part of the document before any doctype informations + * part of the document before any doctype information * This will add the given catalog to the parsing context in order * to be used if there is a resolution need further down in the document */ @@ -5189,6 +5233,7 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { } count++; if (count > 50) { + SHRINK; GROW; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); @@ -6085,14 +6130,20 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { NEXT; if (elem == NULL) { ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); - if (ret == NULL) return(NULL); + if (ret == NULL) { + xmlFreeDocElementContent(ctxt->myDoc, cur); + return(NULL); + } ret->c1 = cur; if (cur != NULL) cur->parent = ret; cur = ret; } else { n = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); - if (n == NULL) return(NULL); + if (n == NULL) { + xmlFreeDocElementContent(ctxt->myDoc, ret); + return(NULL); + } n->c1 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (n->c1 != NULL) n->c1->parent = n; @@ -6195,6 +6246,8 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, SKIP_BLANKS; cur = ret = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, depth + 1); + if (cur == NULL) + return(NULL); SKIP_BLANKS; GROW; } else { @@ -6328,6 +6381,11 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, SKIP_BLANKS; last = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, depth + 1); + if (last == NULL) { + if (ret != NULL) + xmlFreeDocElementContent(ctxt->myDoc, ret); + return(NULL); + } SKIP_BLANKS; } else { elem = xmlParseName(ctxt); @@ -6853,6 +6911,7 @@ void xmlParseTextDecl(xmlParserCtxtPtr ctxt) { xmlChar *version; const xmlChar *encoding; + int oldstate; /* * We know that '<?xml' is here. @@ -6864,6 +6923,10 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { return; } + /* Avoid expansion of parameter entities when skipping blanks. */ + oldstate = ctxt->instate; + ctxt->instate = XML_PARSER_START; + if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space needed after '<?xml'\n"); @@ -6891,6 +6954,7 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { /* * The XML REC instructs us to stop parsing right here */ + ctxt->instate = oldstate; return; } if ((encoding == NULL) && (ctxt->errNo == XML_ERR_OK)) { @@ -6910,6 +6974,8 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { MOVETO_ENDTAG(CUR_PTR); NEXT; } + + ctxt->instate = oldstate; } /** @@ -7147,6 +7213,7 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { ent->checked |= 1; if (ret == XML_ERR_ENTITY_LOOP) { xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); xmlFreeNodeList(list); return; } @@ -7160,42 +7227,38 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY))&& (ent->children == NULL)) { ent->children = list; - if (ctxt->replaceEntities) { - /* - * Prune it directly in the generated document - * except for single text nodes. - */ - if (((list->type == XML_TEXT_NODE) && - (list->next == NULL)) || - (ctxt->parseMode == XML_PARSE_READER)) { - list->parent = (xmlNodePtr) ent; - list = NULL; - ent->owner = 1; - } else { - ent->owner = 0; - while (list != NULL) { - list->parent = (xmlNodePtr) ctxt->node; - list->doc = ctxt->myDoc; - if (list->next == NULL) - ent->last = list; - list = list->next; - } - list = ent->children; + /* + * Prune it directly in the generated document + * except for single text nodes. + */ + if ((ctxt->replaceEntities == 0) || + (ctxt->parseMode == XML_PARSE_READER) || + ((list->type == XML_TEXT_NODE) && + (list->next == NULL))) { + ent->owner = 1; + while (list != NULL) { + list->parent = (xmlNodePtr) ent; + xmlSetTreeDoc(list, ent->doc); + if (list->next == NULL) + ent->last = list; + list = list->next; + } + list = NULL; + } else { + ent->owner = 0; + while (list != NULL) { + list->parent = (xmlNodePtr) ctxt->node; + list->doc = ctxt->myDoc; + if (list->next == NULL) + ent->last = list; + list = list->next; + } + list = ent->children; #ifdef LIBXML_LEGACY_ENABLED - if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) - xmlAddEntityReference(ent, list, NULL); + if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) + xmlAddEntityReference(ent, list, NULL); #endif /* LIBXML_LEGACY_ENABLED */ - } - } else { - ent->owner = 1; - while (list != NULL) { - list->parent = (xmlNodePtr) ent; - xmlSetTreeDoc(list, ent->doc); - if (list->next == NULL) - ent->last = list; - list = list->next; - } - } + } } else { xmlFreeNodeList(list); list = NULL; @@ -7925,6 +7988,9 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) xmlChar start[4]; xmlCharEncoding enc; + if (xmlParserEntityCheck(ctxt, 0, entity, 0)) + return; + if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && ((ctxt->options & XML_PARSE_NOENT) == 0) && ((ctxt->options & XML_PARSE_DTDVALID) == 0) && @@ -8630,7 +8696,7 @@ xmlParseEndTag1(xmlParserCtxtPtr ctxt, int line) { * */ if (name != (xmlChar*)1) { - if (name == NULL) name = BAD_CAST "unparseable"; + if (name == NULL) name = BAD_CAST "unparsable"; xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH, "Opening and ending tag mismatch: %s line %d and %s\n", ctxt->name, line, name); @@ -8823,6 +8889,7 @@ xmlParseQNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *name, } if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { /* success */ + ctxt->input->col += in - ctxt->input->cur; ctxt->input->cur = in; return((const xmlChar*) 1); } @@ -9623,10 +9690,8 @@ done: */ static void -xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix, - const xmlChar *URI, int line, int nsNr, int tlen) { +xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlStartTag *tag) { const xmlChar *name; - size_t curLength; GROW; if ((RAW != '<') || (NXT(1) != '/')) { @@ -9635,24 +9700,10 @@ xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix, } SKIP(2); - curLength = ctxt->input->end - ctxt->input->cur; - if ((tlen > 0) && (curLength >= (size_t)tlen) && - (xmlStrncmp(ctxt->input->cur, ctxt->name, tlen) == 0)) { - if ((curLength >= (size_t)(tlen + 1)) && - (ctxt->input->cur[tlen] == '>')) { - ctxt->input->cur += tlen + 1; - ctxt->input->col += tlen + 1; - goto done; - } - ctxt->input->cur += tlen; - ctxt->input->col += tlen; - name = (xmlChar*)1; - } else { - if (prefix == NULL) - name = xmlParseNameAndCompare(ctxt, ctxt->name); - else - name = xmlParseQNameAndCompare(ctxt, ctxt->name, prefix); - } + if (tag->prefix == NULL) + name = xmlParseNameAndCompare(ctxt, ctxt->name); + else + name = xmlParseQNameAndCompare(ctxt, ctxt->name, tag->prefix); /* * We should definitely be at the ending "S? '>'" part @@ -9673,26 +9724,23 @@ xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix, * */ if (name != (xmlChar*)1) { - if (name == NULL) name = BAD_CAST "unparseable"; - if ((line == 0) && (ctxt->node != NULL)) - line = ctxt->node->line; + if (name == NULL) name = BAD_CAST "unparsable"; xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH, "Opening and ending tag mismatch: %s line %d and %s\n", - ctxt->name, line, name); + ctxt->name, tag->line, name); } /* * SAX: End of Tag */ -done: if ((ctxt->sax != NULL) && (ctxt->sax->endElementNs != NULL) && (!ctxt->disableSAX)) - ctxt->sax->endElementNs(ctxt->userData, ctxt->name, prefix, URI); + ctxt->sax->endElementNs(ctxt->userData, ctxt->name, tag->prefix, + tag->URI); spacePop(ctxt); - if (nsNr != 0) - nsPop(ctxt, nsNr); - return; + if (tag->nsNr != 0) + nsPop(ctxt, tag->nsNr); } /** @@ -9774,6 +9822,7 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { sl = l; count++; if (count > 50) { + SHRINK; GROW; if (ctxt->instate == XML_PARSER_EOF) { xmlFree(buf); @@ -9807,16 +9856,15 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { } /** - * xmlParseContent: + * xmlParseContentInternal: * @ctxt: an XML parser context * - * Parse a content: - * - * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + * Parse a content sequence. Stops at EOF or '</'. Leaves checking of + * unexpected EOF to the caller. */ -void -xmlParseContent(xmlParserCtxtPtr ctxt) { +static void +xmlParseContentInternal(xmlParserCtxtPtr ctxt) { int nameNr = ctxt->nameNr; GROW; @@ -9892,6 +9940,30 @@ xmlParseContent(xmlParserCtxtPtr ctxt) { } /** + * xmlParseContent: + * @ctxt: an XML parser context + * + * Parse a content sequence. Stops at EOF or '</'. + * + * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + */ + +void +xmlParseContent(xmlParserCtxtPtr ctxt) { + int nameNr = ctxt->nameNr; + + xmlParseContentInternal(ctxt); + + if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->nameNr > nameNr)) { + const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; + int line = ctxt->pushTab[ctxt->nameNr - 1].line; + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, + "Premature end of data in tag %s line %d\n", + name, line, NULL); + } +} + +/** * xmlParseElement: * @ctxt: an XML parser context * @@ -9909,9 +9981,20 @@ void xmlParseElement(xmlParserCtxtPtr ctxt) { if (xmlParseElementStart(ctxt) != 0) return; - xmlParseContent(ctxt); + + xmlParseContentInternal(ctxt); if (ctxt->instate == XML_PARSER_EOF) return; + + if (CUR == 0) { + const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; + int line = ctxt->pushTab[ctxt->nameNr - 1].line; + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, + "Premature end of data in tag %s line %d\n", + name, line, NULL); + return; + } + xmlParseElementEnd(ctxt); } @@ -9970,12 +10053,7 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) { spacePop(ctxt); return(-1); } - if (ctxt->sax2) - nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr); -#ifdef LIBXML_SAX1_ENABLED - else - namePush(ctxt, name); -#endif /* LIBXML_SAX1_ENABLED */ + nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr); ret = ctxt->node; #ifdef LIBXML_VALID_ENABLED @@ -10068,10 +10146,7 @@ xmlParseElementEnd(xmlParserCtxtPtr ctxt) { * parse the end of tag: '</' should be here. */ if (ctxt->sax2) { - const xmlChar *prefix = ctxt->pushTab[ctxt->nameNr * 3 - 3]; - const xmlChar *URI = ctxt->pushTab[ctxt->nameNr * 3 - 2]; - int nsNr = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 3 - 1]; - xmlParseEndTag2(ctxt, prefix, URI, 0, nsNr, 0); + xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]); namePop(ctxt); } #ifdef LIBXML_SAX1_ENABLED @@ -10584,16 +10659,16 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { void xmlParseMisc(xmlParserCtxtPtr ctxt) { - while ((ctxt->instate != XML_PARSER_EOF) && - (((RAW == '<') && (NXT(1) == '?')) || - (CMP4(CUR_PTR, '<', '!', '-', '-')) || - IS_BLANK_CH(CUR))) { + while (ctxt->instate != XML_PARSER_EOF) { + SKIP_BLANKS; + GROW; if ((RAW == '<') && (NXT(1) == '?')) { xmlParsePI(ctxt); - } else if (IS_BLANK_CH(CUR)) { - NEXT; - } else + } else if (CMP4(CUR_PTR, '<', '!', '-', '-')) { xmlParseComment(ctxt); + } else { + break; + } } } @@ -10699,7 +10774,6 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { /* * The Misc part of the Prolog */ - GROW; xmlParseMisc(ctxt); /* @@ -11346,6 +11420,7 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { const xmlChar *name; const xmlChar *prefix = NULL; const xmlChar *URI = NULL; + int line = ctxt->input->line; int nsNr = ctxt->nsNr; if ((avail < 2) && (ctxt->inputNr == 1)) @@ -11443,12 +11518,7 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { nodePop(ctxt); spacePop(ctxt); } - if (ctxt->sax2) - nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr); -#ifdef LIBXML_SAX1_ENABLED - else - namePush(ctxt, name); -#endif /* LIBXML_SAX1_ENABLED */ + nameNsPush(ctxt, name, prefix, URI, line, ctxt->nsNr - nsNr); ctxt->instate = XML_PARSER_CONTENT; ctxt->progressive = 1; @@ -11565,11 +11635,7 @@ 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) (ptrdiff_t) - ctxt->pushTab[ctxt->nameNr * 3 - 1], 0); + xmlParseEndTag2(ctxt, &ctxt->pushTab[ctxt->nameNr - 1]); nameNsPop(ctxt); } #ifdef LIBXML_SAX1_ENABLED @@ -12231,12 +12297,12 @@ xmldecl_done: } } res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); + xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur); if (res < 0) { ctxt->errNo = XML_PARSER_EOF; xmlHaltParser(ctxt); return (XML_PARSER_EOF); } - xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur); #ifdef DEBUG_PUSH xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); #endif @@ -12251,6 +12317,7 @@ xmldecl_done: size_t current = ctxt->input->cur - ctxt->input->base; nbchars = xmlCharEncInput(in, terminate); + xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current); if (nbchars < 0) { /* TODO 2.6.0 */ xmlGenericError(xmlGenericErrorContext, @@ -12258,7 +12325,6 @@ xmldecl_done: xmlHaltParser(ctxt); return(XML_ERR_INVALID_ENCODING); } - xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current); } } } @@ -12560,6 +12626,7 @@ xmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data, xmlFree(ctxt->sax); ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler)); if (ctxt->sax == NULL) { + xmlFreeParserInputBuffer(buf); xmlErrMemory(ctxt, NULL); xmlFreeParserCtxt(ctxt); return(NULL); @@ -12896,196 +12963,28 @@ xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) { int xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *lst) { - xmlParserCtxtPtr ctxt; - xmlDocPtr newDoc; - xmlNodePtr newRoot; - xmlSAXHandlerPtr oldsax = NULL; - int ret = 0; - xmlChar start[4]; - xmlCharEncoding enc; + void *userData; if (ctx == NULL) return(-1); - - if (((ctx->depth > 40) && ((ctx->options & XML_PARSE_HUGE) == 0)) || - (ctx->depth > 1024)) { - return(XML_ERR_ENTITY_LOOP); - } - - if (lst != NULL) - *lst = NULL; - if ((URL == NULL) && (ID == NULL)) - return(-1); - if (ctx->myDoc == NULL) /* @@ relax but check for dereferences */ - return(-1); - - ctxt = xmlCreateEntityParserCtxtInternal(URL, ID, NULL, ctx); - if (ctxt == NULL) { - return(-1); - } - - oldsax = ctxt->sax; - ctxt->sax = ctx->sax; - xmlDetectSAX2(ctxt); - newDoc = xmlNewDoc(BAD_CAST "1.0"); - if (newDoc == NULL) { - xmlFreeParserCtxt(ctxt); - return(-1); - } - newDoc->properties = XML_DOC_INTERNAL; - if (ctx->myDoc->dict) { - newDoc->dict = ctx->myDoc->dict; - xmlDictReference(newDoc->dict); - } - if (ctx->myDoc != NULL) { - newDoc->intSubset = ctx->myDoc->intSubset; - newDoc->extSubset = ctx->myDoc->extSubset; - } - if (ctx->myDoc->URL != NULL) { - newDoc->URL = xmlStrdup(ctx->myDoc->URL); - } - newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); - if (newRoot == NULL) { - ctxt->sax = oldsax; - xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - xmlFreeDoc(newDoc); - return(-1); - } - xmlAddChild((xmlNodePtr) newDoc, newRoot); - nodePush(ctxt, newDoc->children); - if (ctx->myDoc == NULL) { - ctxt->myDoc = newDoc; - } else { - ctxt->myDoc = ctx->myDoc; - newDoc->children->doc = ctx->myDoc; - } - /* - * Get the 4 first bytes and decode the charset - * if enc != XML_CHAR_ENCODING_NONE - * plug some encoding conversion routines. - */ - GROW - 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); - } - } - - /* - * Parse a possible text declaration first - */ - if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { - xmlParseTextDecl(ctxt); - /* - * An XML-1.0 document can't reference an entity not XML-1.0 - */ - if ((xmlStrEqual(ctx->version, BAD_CAST "1.0")) && - (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { - xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, - "Version mismatch between document and entity\n"); - } - } - - /* - * If the user provided its own SAX callbacks then reuse the - * useData callback field, otherwise the expected setup in a + * If the user provided their own SAX callbacks, then reuse the + * userData callback field, otherwise the expected setup in a * DOM builder is to have userData == ctxt */ if (ctx->userData == ctx) - ctxt->userData = ctxt; + userData = NULL; else - ctxt->userData = ctx->userData; - - /* - * Doing validity checking on chunk doesn't make sense - */ - ctxt->instate = XML_PARSER_CONTENT; - ctxt->validate = ctx->validate; - ctxt->valid = ctx->valid; - ctxt->loadsubset = ctx->loadsubset; - ctxt->depth = ctx->depth + 1; - ctxt->replaceEntities = ctx->replaceEntities; - if (ctxt->validate) { - ctxt->vctxt.error = ctx->vctxt.error; - ctxt->vctxt.warning = ctx->vctxt.warning; - } else { - ctxt->vctxt.error = NULL; - ctxt->vctxt.warning = NULL; - } - ctxt->vctxt.nodeTab = NULL; - ctxt->vctxt.nodeNr = 0; - ctxt->vctxt.nodeMax = 0; - ctxt->vctxt.node = NULL; - if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); - ctxt->dict = ctx->dict; - 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); - ctxt->dictNames = ctx->dictNames; - ctxt->attsDefault = ctx->attsDefault; - ctxt->attsSpecial = ctx->attsSpecial; - ctxt->linenumbers = ctx->linenumbers; - - xmlParseContent(ctxt); - - ctx->validate = ctxt->validate; - ctx->valid = ctxt->valid; - if ((RAW == '<') && (NXT(1) == '/')) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } else if (RAW != 0) { - xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); - } - if (ctxt->node != newDoc->children) { - xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); - } - - if (!ctxt->wellFormed) { - if (ctxt->errNo == 0) - ret = 1; - else - ret = ctxt->errNo; - } else { - if (lst != NULL) { - xmlNodePtr cur; - - /* - * Return the newly created nodeset after unlinking it from - * they pseudo parent. - */ - cur = newDoc->children->children; - *lst = cur; - while (cur != NULL) { - cur->parent = NULL; - cur = cur->next; - } - newDoc->children->children = NULL; - } - ret = 0; - } - ctxt->sax = oldsax; - ctxt->dict = NULL; - ctxt->attsDefault = NULL; - ctxt->attsSpecial = NULL; - xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - xmlFreeDoc(newDoc); - - return(ret); + userData = ctx->userData; + return xmlParseExternalEntityPrivate(ctx->myDoc, ctx, ctx->sax, + userData, ctx->depth + 1, + URL, ID, lst); } /** * xmlParseExternalEntityPrivate: * @doc: the document the chunk pertains to * @oldctxt: the previous parser context if available - * @sax: the SAX handler bloc (possibly NULL) + * @sax: the SAX handler block (possibly NULL) * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @URL: the URL for the entity to load @@ -13128,25 +13027,6 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, ctxt = xmlCreateEntityParserCtxtInternal(URL, ID, NULL, oldctxt); if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); ctxt->userData = ctxt; - if (oldctxt != NULL) { - ctxt->_private = oldctxt->_private; - ctxt->loadsubset = oldctxt->loadsubset; - ctxt->validate = oldctxt->validate; - ctxt->external = oldctxt->external; - ctxt->record_info = oldctxt->record_info; - ctxt->node_seq.maximum = oldctxt->node_seq.maximum; - ctxt->node_seq.length = oldctxt->node_seq.length; - ctxt->node_seq.buffer = oldctxt->node_seq.buffer; - } else { - /* - * Doing validity checking on chunk without context - * doesn't make sense - */ - ctxt->_private = NULL; - ctxt->validate = 0; - ctxt->external = 2; - ctxt->loadsubset = 0; - } if (sax != NULL) { oldsax = ctxt->sax; ctxt->sax = sax; @@ -13156,28 +13036,25 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, xmlDetectSAX2(ctxt); newDoc = xmlNewDoc(BAD_CAST "1.0"); if (newDoc == NULL) { - ctxt->node_seq.maximum = 0; - ctxt->node_seq.length = 0; - ctxt->node_seq.buffer = NULL; xmlFreeParserCtxt(ctxt); return(XML_ERR_INTERNAL_ERROR); } newDoc->properties = XML_DOC_INTERNAL; - newDoc->intSubset = doc->intSubset; - newDoc->extSubset = doc->extSubset; - newDoc->dict = doc->dict; - xmlDictReference(newDoc->dict); - - if (doc->URL != NULL) { - newDoc->URL = xmlStrdup(doc->URL); + if (doc) { + newDoc->intSubset = doc->intSubset; + newDoc->extSubset = doc->extSubset; + if (doc->dict) { + newDoc->dict = doc->dict; + xmlDictReference(newDoc->dict); + } + if (doc->URL != NULL) { + newDoc->URL = xmlStrdup(doc->URL); + } } newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); if (newRoot == NULL) { if (sax != NULL) ctxt->sax = oldsax; - ctxt->node_seq.maximum = 0; - ctxt->node_seq.length = 0; - ctxt->node_seq.buffer = NULL; xmlFreeParserCtxt(ctxt); newDoc->intSubset = NULL; newDoc->extSubset = NULL; @@ -13186,8 +13063,12 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, } xmlAddChild((xmlNodePtr) newDoc, newRoot); nodePush(ctxt, newDoc->children); - ctxt->myDoc = doc; - newRoot->doc = doc; + if (doc == NULL) { + ctxt->myDoc = newDoc; + } else { + ctxt->myDoc = doc; + newRoot->doc = doc; + } /* * Get the 4 first bytes and decode the charset @@ -13211,10 +13092,53 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, */ if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { xmlParseTextDecl(ctxt); + /* + * An XML-1.0 document can't reference an entity not XML-1.0 + */ + if ((xmlStrEqual(oldctxt->version, BAD_CAST "1.0")) && + (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { + xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, + "Version mismatch between document and entity\n"); + } } ctxt->instate = XML_PARSER_CONTENT; ctxt->depth = depth; + if (oldctxt != NULL) { + ctxt->_private = oldctxt->_private; + ctxt->loadsubset = oldctxt->loadsubset; + ctxt->validate = oldctxt->validate; + ctxt->valid = oldctxt->valid; + ctxt->replaceEntities = oldctxt->replaceEntities; + if (oldctxt->validate) { + ctxt->vctxt.error = oldctxt->vctxt.error; + ctxt->vctxt.warning = oldctxt->vctxt.warning; + ctxt->vctxt.userData = oldctxt->vctxt.userData; + } + ctxt->external = oldctxt->external; + if (ctxt->dict) xmlDictFree(ctxt->dict); + ctxt->dict = oldctxt->dict; + 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); + ctxt->dictNames = oldctxt->dictNames; + ctxt->attsDefault = oldctxt->attsDefault; + ctxt->attsSpecial = oldctxt->attsSpecial; + ctxt->linenumbers = oldctxt->linenumbers; + ctxt->record_info = oldctxt->record_info; + ctxt->node_seq.maximum = oldctxt->node_seq.maximum; + ctxt->node_seq.length = oldctxt->node_seq.length; + ctxt->node_seq.buffer = oldctxt->node_seq.buffer; + } else { + /* + * Doing validity checking on chunk without context + * doesn't make sense + */ + ctxt->_private = NULL; + ctxt->validate = 0; + ctxt->external = 2; + ctxt->loadsubset = 0; + } xmlParseContent(ctxt); @@ -13274,6 +13198,11 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, if (sax != NULL) ctxt->sax = oldsax; if (oldctxt != NULL) { + ctxt->dict = NULL; + ctxt->attsDefault = NULL; + ctxt->attsSpecial = NULL; + oldctxt->validate = ctxt->validate; + oldctxt->valid = ctxt->valid; oldctxt->node_seq.maximum = ctxt->node_seq.maximum; oldctxt->node_seq.length = ctxt->node_seq.length; oldctxt->node_seq.buffer = ctxt->node_seq.buffer; @@ -13293,7 +13222,7 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, /** * xmlParseExternalEntity: * @doc: the document the chunk pertains to - * @sax: the SAX handler bloc (possibly NULL) + * @sax: the SAX handler block (possibly NULL) * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @URL: the URL for the entity to load @@ -13319,8 +13248,8 @@ xmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, /** * xmlParseBalancedChunkMemory: - * @doc: the document the chunk pertains to - * @sax: the SAX handler bloc (possibly NULL) + * @doc: the document the chunk pertains to (must not be NULL) + * @sax: the SAX handler block (possibly NULL) * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @string: the input string in UTF8 or ISO-Latin (zero terminated) @@ -13771,8 +13700,8 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, #ifdef LIBXML_SAX1_ENABLED /** * xmlParseBalancedChunkMemoryRecover: - * @doc: the document the chunk pertains to - * @sax: the SAX handler bloc (possibly NULL) + * @doc: the document the chunk pertains to (must not be NULL) + * @sax: the SAX handler block (possibly NULL) * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @string: the input string in UTF8 or ISO-Latin (zero terminated) @@ -13843,6 +13772,7 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, } else { xmlCtxtUseOptionsInternal(ctxt, XML_PARSE_NODICT, NULL); } + /* doc == NULL is only supported for historic reasons */ if (doc != NULL) { newDoc->intSubset = doc->intSubset; newDoc->extSubset = doc->extSubset; @@ -13859,6 +13789,7 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, } xmlAddChild((xmlNodePtr) newDoc, newRoot); nodePush(ctxt, newRoot); + /* doc == NULL is only supported for historic reasons */ if (doc == NULL) { ctxt->myDoc = newDoc; } else { @@ -13928,8 +13859,8 @@ xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, xmlFreeParserCtxt(ctxt); newDoc->intSubset = NULL; newDoc->extSubset = NULL; - if(doc != NULL) - newDoc->oldNs = NULL; + /* This leaks the namespace list if doc == NULL */ + newDoc->oldNs = NULL; xmlFreeDoc(newDoc); return(ret); @@ -14211,7 +14142,7 @@ xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename, if ((ctxt->wellFormed) || recovery) { ret = ctxt->myDoc; - if (ret != NULL) { + if ((ret != NULL) && (ctxt->input->buf != NULL)) { if (ctxt->input->buf->compressed > 0) ret->compression = 9; else @@ -14742,6 +14673,11 @@ xmlInitParser(void) { if (xmlParserInitialized != 0) return; +#if defined(_WIN32) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) + if (xmlFree == free) + atexit(xmlCleanupParser); +#endif + #ifdef LIBXML_THREAD_ENABLED __xmlGlobalInitMutexLock(); if (xmlParserInitialized == 0) { @@ -14820,6 +14756,20 @@ xmlCleanupParser(void) { xmlParserInitialized = 0; } +#if defined(HAVE_ATTRIBUTE_DESTRUCTOR) && !defined(LIBXML_STATIC) && \ + !defined(_WIN32) +static void +ATTRIBUTE_DESTRUCTOR +xmlDestructor(void) { + /* + * Calling custom deallocation functions in a destructor can cause + * problems, for example with Nokogiri. + */ + if (xmlFree == free) + xmlCleanupParser(); +} +#endif + /************************************************************************ * * * New set (2.6.0) of simpler and more flexible APIs * @@ -14908,7 +14858,6 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) ctxt->vctxt.warning = xmlParserValidityWarning; #endif ctxt->record_info = 0; - ctxt->nbChars = 0; ctxt->checkIndex = 0; ctxt->inSubset = 0; ctxt->errNo = XML_ERR_OK; |