summaryrefslogtreecommitdiffstats
path: root/gnulib-local/lib/libxml/HTMLparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnulib-local/lib/libxml/HTMLparser.c')
-rw-r--r--gnulib-local/lib/libxml/HTMLparser.c1603
1 files changed, 1224 insertions, 379 deletions
diff --git a/gnulib-local/lib/libxml/HTMLparser.c b/gnulib-local/lib/libxml/HTMLparser.c
index 5e23ad7..b729197 100644
--- a/gnulib-local/lib/libxml/HTMLparser.c
+++ b/gnulib-local/lib/libxml/HTMLparser.c
@@ -44,6 +44,9 @@
#include <libxml/globals.h>
#include <libxml/uri.h>
+#include "buf.h"
+#include "enc.h"
+
#define HTML_MAX_NAMELEN 1000
#define HTML_PARSER_BIG_BUFFER_SIZE 1000
#define HTML_PARSER_BUFFER_SIZE 100
@@ -59,7 +62,7 @@ static void htmlParseComment(htmlParserCtxtPtr ctxt);
/************************************************************************
* *
- * Some factorized error routines *
+ * Some factorized error routines *
* *
************************************************************************/
@@ -147,7 +150,7 @@ htmlParseErrInt(xmlParserCtxtPtr ctxt, xmlParserErrors error,
/************************************************************************
* *
- * Parser stacks related functions and macros *
+ * Parser stacks related functions and macros *
* *
************************************************************************/
@@ -163,6 +166,10 @@ htmlParseErrInt(xmlParserCtxtPtr ctxt, xmlParserErrors error,
static int
htmlnamePush(htmlParserCtxtPtr ctxt, const xmlChar * value)
{
+ if ((ctxt->html < 3) && (xmlStrEqual(value, BAD_CAST "head")))
+ ctxt->html = 3;
+ if ((ctxt->html < 10) && (xmlStrEqual(value, BAD_CAST "body")))
+ ctxt->html = 10;
if (ctxt->nameNr >= ctxt->nameMax) {
ctxt->nameMax *= 2;
ctxt->nameTab = (const xmlChar * *)
@@ -205,6 +212,59 @@ htmlnamePop(htmlParserCtxtPtr ctxt)
return (ret);
}
+/**
+ * htmlNodeInfoPush:
+ * @ctxt: an HTML parser context
+ * @value: the node info
+ *
+ * Pushes a new element name on top of the node info stack
+ *
+ * Returns 0 in case of error, the index in the stack otherwise
+ */
+static int
+htmlNodeInfoPush(htmlParserCtxtPtr ctxt, htmlParserNodeInfo *value)
+{
+ if (ctxt->nodeInfoNr >= ctxt->nodeInfoMax) {
+ if (ctxt->nodeInfoMax == 0)
+ ctxt->nodeInfoMax = 5;
+ ctxt->nodeInfoMax *= 2;
+ ctxt->nodeInfoTab = (htmlParserNodeInfo *)
+ xmlRealloc((htmlParserNodeInfo *)ctxt->nodeInfoTab,
+ ctxt->nodeInfoMax *
+ sizeof(ctxt->nodeInfoTab[0]));
+ if (ctxt->nodeInfoTab == NULL) {
+ htmlErrMemory(ctxt, NULL);
+ return (0);
+ }
+ }
+ ctxt->nodeInfoTab[ctxt->nodeInfoNr] = *value;
+ ctxt->nodeInfo = &ctxt->nodeInfoTab[ctxt->nodeInfoNr];
+ return (ctxt->nodeInfoNr++);
+}
+
+/**
+ * htmlNodeInfoPop:
+ * @ctxt: an HTML parser context
+ *
+ * Pops the top element name from the node info stack
+ *
+ * Returns 0 in case of error, the pointer to NodeInfo otherwise
+ */
+static htmlParserNodeInfo *
+htmlNodeInfoPop(htmlParserCtxtPtr ctxt)
+{
+ if (ctxt->nodeInfoNr <= 0)
+ return (NULL);
+ ctxt->nodeInfoNr--;
+ if (ctxt->nodeInfoNr < 0)
+ return (NULL);
+ if (ctxt->nodeInfoNr > 0)
+ ctxt->nodeInfo = &ctxt->nodeInfoTab[ctxt->nodeInfoNr - 1];
+ else
+ ctxt->nodeInfo = NULL;
+ return &ctxt->nodeInfoTab[ctxt->nodeInfoNr];
+}
+
/*
* Macros for accessing the content. Those should be used only by the parser,
* and not exported.
@@ -263,8 +323,6 @@ htmlnamePop(htmlParserCtxtPtr ctxt)
#define NEXT xmlNextChar(ctxt)
#define RAW (ctxt->token ? -1 : (*ctxt->input->cur))
-#define NXT(val) ctxt->input->cur[(val)]
-#define CUR_PTR ctxt->input->cur
#define NEXTL(l) do { \
@@ -273,7 +331,7 @@ htmlnamePop(htmlParserCtxtPtr ctxt)
} else ctxt->input->col++; \
ctxt->token = 0; ctxt->input->cur += l; ctxt->nbChars++; \
} while (0)
-
+
/************
\
if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \
@@ -288,6 +346,58 @@ htmlnamePop(htmlParserCtxtPtr ctxt)
else i += xmlCopyChar(l,&b[i],v)
/**
+ * htmlFindEncoding:
+ * @the HTML parser context
+ *
+ * Ty to find and encoding in the current data available in the input
+ * buffer this is needed to try to switch to the proper encoding when
+ * one face a character error.
+ * That's an heuristic, since it's operating outside of parsing it could
+ * try to use a meta which had been commented out, that's the reason it
+ * should only be used in case of error, not as a default.
+ *
+ * Returns an encoding string or NULL if not found, the string need to
+ * be freed
+ */
+static xmlChar *
+htmlFindEncoding(xmlParserCtxtPtr ctxt) {
+ const xmlChar *start, *cur, *end;
+
+ if ((ctxt == NULL) || (ctxt->input == NULL) ||
+ (ctxt->input->encoding != NULL) || (ctxt->input->buf == NULL) ||
+ (ctxt->input->buf->encoder != NULL))
+ return(NULL);
+ if ((ctxt->input->cur == NULL) || (ctxt->input->end == NULL))
+ return(NULL);
+
+ start = ctxt->input->cur;
+ end = ctxt->input->end;
+ /* we also expect the input buffer to be zero terminated */
+ if (*end != 0)
+ return(NULL);
+
+ cur = xmlStrcasestr(start, BAD_CAST "HTTP-EQUIV");
+ if (cur == NULL)
+ return(NULL);
+ cur = xmlStrcasestr(cur, BAD_CAST "CONTENT");
+ if (cur == NULL)
+ return(NULL);
+ cur = xmlStrcasestr(cur, BAD_CAST "CHARSET=");
+ if (cur == NULL)
+ return(NULL);
+ cur += 8;
+ start = cur;
+ while (((*cur >= 'A') && (*cur <= 'Z')) ||
+ ((*cur >= 'a') && (*cur <= 'z')) ||
+ ((*cur >= '0') && (*cur <= '9')) ||
+ (*cur == '-') || (*cur == '_') || (*cur == ':') || (*cur == '/'))
+ cur++;
+ if (cur == start)
+ return(NULL);
+ return(xmlStrndup(start, cur - start));
+}
+
+/**
* htmlCurrentChar:
* @ctxt: the HTML parser context
* @len: pointer to the length of the char read
@@ -309,7 +419,7 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
if (ctxt->token != 0) {
*len = 0;
return(ctxt->token);
- }
+ }
if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
/*
* We are supposed to handle UTF8, check it's valid
@@ -318,7 +428,7 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
* 0000 0000-0000 007F 0xxxxxxx
* 0000 0080-0000 07FF 110xxxxx 10xxxxxx
- * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
+ * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
*
* Check for the 0x110000 limit too
*/
@@ -328,19 +438,25 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
c = *cur;
if (c & 0x80) {
- if (cur[1] == 0)
+ if (cur[1] == 0) {
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+ cur = ctxt->input->cur;
+ }
if ((cur[1] & 0xc0) != 0x80)
goto encoding_error;
if ((c & 0xe0) == 0xe0) {
- if (cur[2] == 0)
+ if (cur[2] == 0) {
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+ cur = ctxt->input->cur;
+ }
if ((cur[2] & 0xc0) != 0x80)
goto encoding_error;
if ((c & 0xf0) == 0xf0) {
- if (cur[3] == 0)
+ if (cur[3] == 0) {
xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+ cur = ctxt->input->cur;
+ }
if (((c & 0xf8) != 0xf0) ||
((cur[3] & 0xc0) != 0x80))
goto encoding_error;
@@ -366,9 +482,16 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
if (!IS_CHAR(val)) {
htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
"Char 0x%X out of allowed range\n", val);
- }
+ }
return(val);
} else {
+ if ((*ctxt->input->cur == 0) &&
+ (ctxt->input->cur < ctxt->input->end)) {
+ htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+ "Char 0x%X out of allowed range\n", 0);
+ *len = 1;
+ return(' ');
+ }
/* 1-byte code */
*len = 1;
return((int) *ctxt->input->cur);
@@ -386,8 +509,28 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
/*
* Humm this is bad, do an automatic flow conversion
*/
- xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
- ctxt->charset = XML_CHAR_ENCODING_UTF8;
+ {
+ xmlChar * guess;
+ xmlCharEncodingHandlerPtr handler;
+
+ guess = htmlFindEncoding(ctxt);
+ if (guess == NULL) {
+ xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
+ } else {
+ if (ctxt->input->encoding != NULL)
+ xmlFree((xmlChar *) ctxt->input->encoding);
+ ctxt->input->encoding = guess;
+ handler = xmlFindCharEncodingHandler((const char *) guess);
+ if (handler != NULL) {
+ xmlSwitchToEncoding(ctxt, handler);
+ } else {
+ htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
+ "Unsupported encoding %s", guess, NULL);
+ }
+ }
+ ctxt->charset = XML_CHAR_ENCODING_UTF8;
+ }
+
return(xmlCurrentChar(ctxt, len));
encoding_error:
@@ -401,15 +544,19 @@ encoding_error:
{
char buffer[150];
- snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
- ctxt->input->cur[0], ctxt->input->cur[1],
- ctxt->input->cur[2], ctxt->input->cur[3]);
+ if (ctxt->input->end - ctxt->input->cur >= 4) {
+ snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
+ ctxt->input->cur[0], ctxt->input->cur[1],
+ ctxt->input->cur[2], ctxt->input->cur[3]);
+ } else {
+ snprintf(buffer, 149, "Bytes: 0x%02X\n", ctxt->input->cur[0]);
+ }
htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
"Input is not proper UTF-8, indicate encoding !\n",
BAD_CAST buffer, NULL);
}
- ctxt->charset = XML_CHAR_ENCODING_8859_1;
+ ctxt->charset = XML_CHAR_ENCODING_8859_1;
*len = 1;
return((int) *ctxt->input->cur);
}
@@ -449,7 +596,7 @@ htmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
/************************************************************************
* *
- * The list of HTML elements and their properties *
+ * The list of HTML elements and their properties *
* *
************************************************************************/
@@ -472,11 +619,11 @@ htmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
#define NB_FONTSTYLE 8
#define PHRASE "em", "strong", "dfn", "code", "samp", "kbd", "var", "cite", "abbr", "acronym"
#define NB_PHRASE 10
-#define SPECIAL "a", "img", "applet", "object", "font", "basefont", "br", "script", "map", "q", "sub", "sup", "span", "bdo", "iframe"
-#define NB_SPECIAL 15
-#define INLINE PCDATA FONTSTYLE PHRASE SPECIAL FORMCTRL
+#define SPECIAL "a", "img", "applet", "embed", "object", "font", "basefont", "br", "script", "map", "q", "sub", "sup", "span", "bdo", "iframe"
+#define NB_SPECIAL 16
+#define INLINE FONTSTYLE, PHRASE, SPECIAL, FORMCTRL
#define NB_INLINE NB_PCDATA + NB_FONTSTYLE + NB_PHRASE + NB_SPECIAL + NB_FORMCTRL
-#define BLOCK HEADING, LIST "pre", "p", "dl", "div", "center", "noscript", "noframes", "blockquote", "form", "isindex", "hr", "table", "fieldset", "address"
+#define BLOCK HEADING, LIST, "pre", "p", "dl", "div", "center", "noscript", "noframes", "blockquote", "form", "isindex", "hr", "table", "fieldset", "address"
#define NB_BLOCK NB_HEADING + NB_LIST + 14
#define FORMCTRL "input", "select", "textarea", "label", "button"
#define NB_FORMCTRL 5
@@ -572,6 +719,7 @@ static const char* const version_attr[] = { "version", NULL } ;
static const char* const html_content[] = { "head", "body", "frameset", NULL } ;
static const char* const iframe_attrs[] = { COREATTRS, "longdesc", "name", "src", "frameborder", "marginwidth", "marginheight", "scrolling", "align", "height", "width", NULL } ;
static const char* const img_attrs[] = { ATTRS, "longdesc", "name", "height", "width", "usemap", "ismap", NULL } ;
+static const char* const embed_attrs[] = { COREATTRS, "align", "alt", "border", "code", "codebase", "frameborder", "height", "hidden", "hspace", "name", "palette", "pluginspace", "pluginurl", "src", "type", "units", "vspace", "width", NULL } ;
static const char* const input_attrs[] = { ATTRS, "type", "name", "value", "checked", "disabled", "readonly", "size", "maxlength", "src", "alt", "usemap", "ismap", "tabindex", "accesskey", "onfocus", "onblur", "onselect", "onchange", "accept", NULL } ;
static const char* const prompt_attrs[] = { COREATTRS, I18N, "prompt", NULL } ;
static const char* const label_attrs[] = { ATTRS, "for", "accesskey", "onfocus", "onblur", NULL } ;
@@ -582,7 +730,7 @@ static const char* const map_contents[] = { BLOCK, "area", NULL } ;
static const char* const name_attr[] = { "name", NULL } ;
static const char* const action_attr[] = { "action", NULL } ;
static const char* const blockli_elt[] = { BLOCK, "li", NULL } ;
-static const char* const meta_attrs[] = { I18N, "http-equiv", "name", "scheme", NULL } ;
+static const char* const meta_attrs[] = { I18N, "http-equiv", "name", "scheme", "charset", NULL } ;
static const char* const content_attr[] = { "content", NULL } ;
static const char* const type_attr[] = { "type", NULL } ;
static const char* const noframes_content[] = { "body", FLOW MODIFIER, NULL } ;
@@ -601,7 +749,7 @@ static const char* const language_attr[] = { "language", NULL } ;
static const char* const select_content[] = { "optgroup", "option", NULL } ;
static const char* const select_attrs[] = { ATTRS, "name", "size", "multiple", "disabled", "tabindex", "onfocus", "onblur", "onchange", NULL } ;
static const char* const style_attrs[] = { I18N, "media", "title", NULL } ;
-static const char* const table_attrs[] = { ATTRS "summary", "width", "border", "frame", "rules", "cellspacing", "cellpadding", "datapagesize", NULL } ;
+static const char* const table_attrs[] = { ATTRS, "summary", "width", "border", "frame", "rules", "cellspacing", "cellpadding", "datapagesize", NULL } ;
static const char* const table_depr[] = { "align", "bgcolor", NULL } ;
static const char* const table_contents[] = { "caption", "col", "colgroup", "thead", "tfoot", "tbody", "tr", NULL} ;
static const char* const tr_elt[] = { "tr", NULL } ;
@@ -698,7 +846,7 @@ html40ElementTable[] = {
DECL html_flow, NULL, DECL html_attrs, DECL align_attr, NULL
},
{ "dl", 0, 0, 0, 0, 0, 0, 0, "definition list ",
- DECL dl_contents , "dd" , html_attrs, DECL compact_attr, NULL
+ DECL dl_contents , "dd" , DECL html_attrs, DECL compact_attr, NULL
},
{ "dt", 0, 1, 0, 0, 0, 0, 0, "definition term ",
DECL html_inline, NULL, DECL html_attrs, NULL, NULL
@@ -706,6 +854,9 @@ html40ElementTable[] = {
{ "em", 0, 3, 0, 0, 0, 0, 1, "emphasis",
DECL html_inline, NULL, DECL html_attrs, NULL, NULL
},
+{ "embed", 0, 1, 0, 0, 1, 1, 1, "generic embedded object ",
+ EMPTY, NULL, DECL embed_attrs, NULL, NULL
+},
{ "fieldset", 0, 0, 0, 0, 0, 0, 0, "form control group ",
DECL fieldset_contents , NULL, DECL html_attrs, NULL, NULL
},
@@ -755,7 +906,7 @@ html40ElementTable[] = {
DECL html_flow, NULL, NULL, DECL iframe_attrs, NULL
},
{ "img", 0, 2, 2, 1, 0, 0, 1, "embedded image ",
- EMPTY, NULL, DECL img_attrs, DECL align_attr, src_alt_attrs
+ EMPTY, NULL, DECL img_attrs, DECL align_attr, DECL src_alt_attrs
},
{ "input", 0, 2, 2, 1, 0, 0, 1, "form control ",
EMPTY, NULL, DECL input_attrs , DECL align_attr, NULL
@@ -782,7 +933,7 @@ html40ElementTable[] = {
EMPTY, NULL, DECL link_attrs, DECL target_attr, NULL
},
{ "map", 0, 0, 0, 0, 0, 0, 2, "client-side image map ",
- DECL map_contents , NULL, DECL html_attrs , NULL, name_attr
+ DECL map_contents , NULL, DECL html_attrs , NULL, DECL name_attr
},
{ "menu", 0, 0, 0, 0, 1, 1, 0, "menu list ",
DECL blockli_elt , NULL, NULL, DECL compact_attrs, NULL
@@ -803,7 +954,7 @@ html40ElementTable[] = {
DECL li_elt , "li" , DECL html_attrs, DECL ol_attrs, NULL
},
{ "optgroup", 0, 0, 0, 0, 0, 0, 0, "option group ",
- option_elt , "option", DECL optgroup_attrs, NULL, DECL label_attr
+ DECL option_elt , "option", DECL optgroup_attrs, NULL, DECL label_attr
},
{ "option", 0, 1, 0, 0, 0, 0, 0, "selectable choice " ,
DECL html_pcdata, NULL, DECL option_attrs, NULL, NULL
@@ -812,7 +963,7 @@ html40ElementTable[] = {
DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
},
{ "param", 0, 2, 2, 1, 0, 0, 0, "named property value ",
- EMPTY, NULL, DECL param_attrs, NULL, name_attr
+ EMPTY, NULL, DECL param_attrs, NULL, DECL name_attr
},
{ "pre", 0, 0, 0, 0, 0, 0, 0, "preformatted text ",
DECL pre_content, NULL, DECL html_attrs, DECL width_attr, NULL
@@ -930,18 +1081,18 @@ static const char * const htmlStartClose[] = {
"listing", "xmp", NULL,
"ol", "p", "head", "ul", NULL,
"menu", "p", "head", "ul", NULL,
-"p", "p", "head", "h1", "h2", "h3", "h4", "h5", "h6", NULL,
+"p", "p", "head", "h1", "h2", "h3", "h4", "h5", "h6", FONTSTYLE, NULL,
"div", "p", "head", NULL,
-"noscript", "p", "head", NULL,
+"noscript", "p", NULL,
"center", "font", "b", "i", "p", "head", NULL,
-"a", "a", NULL,
+"a", "a", "head", NULL,
"caption", "p", NULL,
"colgroup", "caption", "colgroup", "col", "p", NULL,
"col", "caption", "col", "p", NULL,
"table", "p", "head", "h1", "h2", "h3", "h4", "h5", "h6", "pre",
"listing", "xmp", "a", NULL,
"th", "th", "td", "p", "span", "font", "a", "b", "i", "u", NULL,
-"td", "th", "td", "p", "span", "font", "a", "b", "i", "u", NULL,
+"td", "th", "td", "p", "span", "font", "a", "b", "i", "u", NULL,
"tr", "th", "td", "tr", "caption", "col", "colgroup", "p", NULL,
"thead", "caption", "col", "colgroup", NULL,
"tfoot", "th", "td", "tr", "caption", "col", "colgroup", "thead",
@@ -952,6 +1103,43 @@ static const char * const htmlStartClose[] = {
"option", "option", NULL,
"fieldset", "legend", "p", "head", "h1", "h2", "h3", "h4", "h5", "h6",
"pre", "listing", "xmp", "a", NULL,
+/* most tags in in FONTSTYLE, PHRASE and SPECIAL should close <head> */
+"tt", "head", NULL,
+"i", "head", NULL,
+"b", "head", NULL,
+"u", "head", NULL,
+"s", "head", NULL,
+"strike", "head", NULL,
+"big", "head", NULL,
+"small", "head", NULL,
+
+"em", "head", NULL,
+"strong", "head", NULL,
+"dfn", "head", NULL,
+"code", "head", NULL,
+"samp", "head", NULL,
+"kbd", "head", NULL,
+"var", "head", NULL,
+"cite", "head", NULL,
+"abbr", "head", NULL,
+"acronym", "head", NULL,
+
+/* "a" */
+"img", "head", NULL,
+/* "applet" */
+/* "embed" */
+/* "object" */
+"font", "head", NULL,
+/* "basefont" */
+"br", "head", NULL,
+/* "script" */
+"map", "head", NULL,
+"q", "head", NULL,
+"sub", "head", NULL,
+"sup", "head", NULL,
+"span", "head", NULL,
+"bdo", "head", NULL,
+"iframe", "head", NULL,
NULL
};
@@ -989,7 +1177,7 @@ static const char *const htmlScriptAttributes[] = {
"onfocus",
"onblur",
"onsubmit",
- "onrest",
+ "onreset",
"onchange",
"onselect"
};
@@ -1000,7 +1188,7 @@ static const char *const htmlScriptAttributes[] = {
* elements the parser can decide how to handle extra endtags.
* Endtags are only allowed to close elements with lower or equal
* priority.
- */
+ */
typedef struct {
const char *name;
@@ -1027,7 +1215,7 @@ static int htmlStartCloseIndexinitialized = 0;
/************************************************************************
* *
- * functions to handle HTML specific data *
+ * functions to handle HTML specific data *
* *
************************************************************************/
@@ -1077,7 +1265,7 @@ htmlTagLookup(const xmlChar *tag) {
/**
* htmlGetEndPriority:
* @name: The name of the element to look up the priority for.
- *
+ *
* Return value: The "endtag" priority.
**/
static int
@@ -1156,7 +1344,7 @@ htmlAutoCloseOnClose(htmlParserCtxtPtr ctxt, const xmlChar * newtag)
* A missplaced endtag can only close elements with lower
* or equal priority, so if we find an element with higher
* priority before we find an element with
- * matching name, we just ignore this endtag
+ * matching name, we just ignore this endtag
*/
if (htmlGetEndPriority(ctxt->nameTab[i]) > priority)
return;
@@ -1207,7 +1395,7 @@ htmlAutoCloseOnEnd(htmlParserCtxtPtr ctxt)
* called when a new tag has been detected and generates the
* appropriates closes if possible/needed.
* If newtag is NULL this mean we are at the end of the resource
- * and we should check
+ * and we should check
*/
static void
htmlAutoClose(htmlParserCtxtPtr ctxt, const xmlChar * newtag)
@@ -1295,6 +1483,10 @@ htmlIsAutoClosed(htmlDocPtr doc, htmlNodePtr elem) {
*/
static void
htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag) {
+ int i;
+
+ if (ctxt->options & HTML_PARSE_NOIMPLIED)
+ return;
if (!htmlOmittedDefaultValue)
return;
if (xmlStrEqual(newtag, BAD_CAST"html"))
@@ -1306,24 +1498,31 @@ htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag) {
}
if ((xmlStrEqual(newtag, BAD_CAST"body")) || (xmlStrEqual(newtag, BAD_CAST"head")))
return;
- if ((ctxt->nameNr <= 1) &&
+ if ((ctxt->nameNr <= 1) &&
((xmlStrEqual(newtag, BAD_CAST"script")) ||
(xmlStrEqual(newtag, BAD_CAST"style")) ||
(xmlStrEqual(newtag, BAD_CAST"meta")) ||
(xmlStrEqual(newtag, BAD_CAST"link")) ||
(xmlStrEqual(newtag, BAD_CAST"title")) ||
(xmlStrEqual(newtag, BAD_CAST"base")))) {
- /*
- * dropped OBJECT ... i you put it first BODY will be
- * assumed !
- */
- htmlnamePush(ctxt, BAD_CAST"head");
- if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
- ctxt->sax->startElement(ctxt->userData, BAD_CAST"head", NULL);
+ if (ctxt->html >= 3) {
+ /* we already saw or generated an <head> before */
+ return;
+ }
+ /*
+ * dropped OBJECT ... i you put it first BODY will be
+ * assumed !
+ */
+ htmlnamePush(ctxt, BAD_CAST"head");
+ if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
+ ctxt->sax->startElement(ctxt->userData, BAD_CAST"head", NULL);
} else if ((!xmlStrEqual(newtag, BAD_CAST"noframes")) &&
(!xmlStrEqual(newtag, BAD_CAST"frame")) &&
(!xmlStrEqual(newtag, BAD_CAST"frameset"))) {
- int i;
+ if (ctxt->html >= 10) {
+ /* we already saw or generated a <body> before */
+ return;
+ }
for (i = 0;i < ctxt->nameNr;i++) {
if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"body")) {
return;
@@ -1332,7 +1531,7 @@ htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag) {
return;
}
}
-
+
htmlnamePush(ctxt, BAD_CAST"body");
if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
ctxt->sax->startElement(ctxt->userData, BAD_CAST"body", NULL);
@@ -1394,12 +1593,12 @@ htmlIsScriptAttribute(const xmlChar *name) {
unsigned int i;
if (name == NULL)
- return(0);
+ return(0);
/*
* all script attributes start with 'on'
*/
if ((name[0] != 'o') || (name[1] != 'n'))
- return(0);
+ return(0);
for (i = 0;
i < sizeof(htmlScriptAttributes)/sizeof(htmlScriptAttributes[0]);
i++) {
@@ -1411,7 +1610,7 @@ htmlIsScriptAttribute(const xmlChar *name) {
/************************************************************************
* *
- * The list of HTML predefined entities *
+ * The list of HTML predefined entities *
* *
************************************************************************/
@@ -1825,7 +2024,7 @@ UTF8ToHtml(unsigned char* out, int *outlen,
if (inend - in < trailing) {
break;
- }
+ }
for ( ; trailing; trailing--) {
if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80))
@@ -1842,6 +2041,8 @@ UTF8ToHtml(unsigned char* out, int *outlen,
} else {
int len;
const htmlEntityDesc * ent;
+ const char *cp;
+ char nbuf[16];
/*
* Try to lookup a predefined HTML entity for it
@@ -1849,16 +2050,16 @@ UTF8ToHtml(unsigned char* out, int *outlen,
ent = htmlEntityValueLookup(c);
if (ent == NULL) {
- /* no chance for this in Ascii */
- *outlen = out - outstart;
- *inlen = processed - instart;
- return(-2);
+ snprintf(nbuf, sizeof(nbuf), "#%u", c);
+ cp = nbuf;
}
- len = strlen(ent->name);
+ else
+ cp = ent->name;
+ len = strlen(cp);
if (out + 2 + len >= outend)
break;
*out++ = '&';
- memcpy(out, ent->name, len);
+ memcpy(out, cp, len);
out += len;
*out++ = ';';
}
@@ -2013,7 +2214,7 @@ htmlNewInputStream(htmlParserCtxtPtr ctxt) {
* *
************************************************************************/
/*
- * all tags allowing pc data from the html 4.01 loose dtd
+ * all tags allowing pc data from the html 4.01 loose dtd
* NOTE: it might be more apropriate to integrate this information
* into the html40ElementTable array but I don't want to risk any
* binary incomptibility
@@ -2073,7 +2274,7 @@ static int areBlanks(htmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
if (lastChild == NULL) {
if ((ctxt->node->type != XML_ELEMENT_NODE) &&
(ctxt->node->content != NULL)) return(0);
- /* keep ws in constructs like ...<b> </b>...
+ /* keep ws in constructs like ...<b> </b>...
for all tags "b" allowing PCDATA */
for ( i = 0; i < sizeof(allowPCData)/sizeof(allowPCData[0]); i++ ) {
if ( xmlStrEqual(ctxt->name, BAD_CAST allowPCData[i]) ) {
@@ -2083,7 +2284,7 @@ static int areBlanks(htmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
} else if (xmlNodeIsText(lastChild)) {
return(0);
} else {
- /* keep ws in constructs like <p><b>xy</b> <i>z</i><p>
+ /* keep ws in constructs like <p><b>xy</b> <i>z</i><p>
for all tags "p" allowing PCDATA */
for ( i = 0; i < sizeof(allowPCData)/sizeof(allowPCData[0]); i++ ) {
if ( xmlStrEqual(lastChild->name, BAD_CAST allowPCData[i]) ) {
@@ -2123,7 +2324,7 @@ htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) {
cur->intSubset = NULL;
cur->doc = cur;
cur->name = NULL;
- cur->children = NULL;
+ cur->children = NULL;
cur->extSubset = NULL;
cur->oldNs = NULL;
cur->encoding = NULL;
@@ -2133,6 +2334,7 @@ htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) {
cur->refs = NULL;
cur->_private = NULL;
cur->charset = XML_CHAR_ENCODING_UTF8;
+ cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT;
if ((ExternalID != NULL) ||
(URI != NULL))
xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI);
@@ -2190,21 +2392,54 @@ htmlParseHTMLName(htmlParserCtxtPtr ctxt) {
xmlChar loc[HTML_PARSER_BUFFER_SIZE];
if (!IS_ASCII_LETTER(CUR) && (CUR != '_') &&
- (CUR != ':')) return(NULL);
+ (CUR != ':') && (CUR != '.')) return(NULL);
while ((i < HTML_PARSER_BUFFER_SIZE) &&
((IS_ASCII_LETTER(CUR)) || (IS_ASCII_DIGIT(CUR)) ||
- (CUR == ':') || (CUR == '-') || (CUR == '_'))) {
+ (CUR == ':') || (CUR == '-') || (CUR == '_') ||
+ (CUR == '.'))) {
if ((CUR >= 'A') && (CUR <= 'Z')) loc[i] = CUR + 0x20;
else loc[i] = CUR;
i++;
-
+
NEXT;
}
-
+
return(xmlDictLookup(ctxt->dict, loc, i));
}
+
+/**
+ * htmlParseHTMLName_nonInvasive:
+ * @ctxt: an HTML parser context
+ *
+ * parse an HTML tag or attribute name, note that we convert it to lowercase
+ * since HTML names are not case-sensitive, this doesn't consume the data
+ * from the stream, it's a look-ahead
+ *
+ * Returns the Tag Name parsed or NULL
+ */
+
+static const xmlChar *
+htmlParseHTMLName_nonInvasive(htmlParserCtxtPtr ctxt) {
+ int i = 0;
+ xmlChar loc[HTML_PARSER_BUFFER_SIZE];
+
+ if (!IS_ASCII_LETTER(NXT(1)) && (NXT(1) != '_') &&
+ (NXT(1) != ':')) return(NULL);
+
+ while ((i < HTML_PARSER_BUFFER_SIZE) &&
+ ((IS_ASCII_LETTER(NXT(1+i))) || (IS_ASCII_DIGIT(NXT(1+i))) ||
+ (NXT(1+i) == ':') || (NXT(1+i) == '-') || (NXT(1+i) == '_'))) {
+ if ((NXT(1+i) >= 'A') && (NXT(1+i) <= 'Z')) loc[i] = NXT(1+i) + 0x20;
+ else loc[i] = NXT(1+i);
+ i++;
+ }
+
+ return(xmlDictLookup(ctxt->dict, loc, i));
+}
+
+
/**
* htmlParseName:
* @ctxt: an HTML parser context
@@ -2268,7 +2503,7 @@ htmlParseNameComplex(xmlParserCtxtPtr ctxt) {
while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
((IS_LETTER(c)) || (IS_DIGIT(c)) ||
(c == '.') || (c == '-') ||
- (c == '_') || (c == ':') ||
+ (c == '_') || (c == ':') ||
(IS_COMBINING(c)) ||
(IS_EXTENDER(c)))) {
if (count++ > 100) {
@@ -2287,7 +2522,7 @@ htmlParseNameComplex(xmlParserCtxtPtr ctxt) {
* htmlParseHTMLAttribute:
* @ctxt: an HTML parser context
* @stop: a char stop value
- *
+ *
* parse an HTML attribute value till the stop (quote), if
* stop is 0 then it stops at the first space
*
@@ -2332,13 +2567,13 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) {
{ *out++ =((c >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (c < 0x10000)
{ *out++ =((c >> 12) & 0x0F) | 0xE0; bits= 6; }
- else
+ else
{ *out++ =((c >> 18) & 0x07) | 0xF0; bits= 12; }
-
+
for ( ; bits >= 0; bits-= 6) {
*out++ = ((c >> bits) & 0x3F) | 0x80;
}
-
+
if (out - buffer > buffer_size - 100) {
int indx = out - buffer;
@@ -2384,9 +2619,9 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) {
{ *out++ =((c >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (c < 0x10000)
{ *out++ =((c >> 12) & 0x0F) | 0xE0; bits= 6; }
- else
+ else
{ *out++ =((c >> 18) & 0x07) | 0xF0; bits= 12; }
-
+
for ( ; bits >= 0; bits-= 6) {
*out++ = ((c >> bits) & 0x3F) | 0x80;
}
@@ -2409,16 +2644,16 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) {
{ *out++ =((c >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (c < 0x10000)
{ *out++ =((c >> 12) & 0x0F) | 0xE0; bits= 6; }
- else
+ else
{ *out++ =((c >> 18) & 0x07) | 0xF0; bits= 12; }
-
+
for ( ; bits >= 0; bits-= 6) {
*out++ = ((c >> bits) & 0x3F) | 0x80;
}
NEXT;
}
}
- *out++ = 0;
+ *out = 0;
return(buffer);
}
@@ -2479,7 +2714,7 @@ htmlParseEntityRef(htmlParserCtxtPtr ctxt, const xmlChar **str) {
* parse a value for an attribute
* Note: the parser won't do substitution of entities here, this
* will be handled later in xmlStringGetNodeList, unless it was
- * asked for ctxt->replaceEntities != 0
+ * asked for ctxt->replaceEntities != 0
*
* Returns the AttValue parsed or NULL.
*/
@@ -2520,7 +2755,7 @@ htmlParseAttValue(htmlParserCtxtPtr ctxt) {
/**
* htmlParseSystemLiteral:
* @ctxt: an HTML parser context
- *
+ *
* parse an HTML Literal
*
* [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
@@ -2561,7 +2796,7 @@ htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) {
htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
" or ' expected\n", NULL, NULL);
}
-
+
return(ret);
}
@@ -2610,7 +2845,7 @@ htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) {
htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
"PubidLiteral \" or ' expected\n", NULL, NULL);
}
-
+
return(ret);
}
@@ -2644,23 +2879,7 @@ htmlParseScript(htmlParserCtxtPtr ctxt) {
SHRINK;
cur = CUR_CHAR(l);
while (IS_CHAR_CH(cur)) {
- if ((cur == '<') && (NXT(1) == '!') && (NXT(2) == '-') &&
- (NXT(3) == '-')) {
- if ((nbchar != 0) && (ctxt->sax != NULL) && (!ctxt->disableSAX)) {
- if (ctxt->sax->cdataBlock!= NULL) {
- /*
- * Insert as CDATA, which is the same as HTML_PRESERVE_NODE
- */
- ctxt->sax->cdataBlock(ctxt->userData, buf, nbchar);
- } else if (ctxt->sax->characters != NULL) {
- ctxt->sax->characters(ctxt->userData, buf, nbchar);
- }
- }
- nbchar = 0;
- htmlParseComment(ctxt);
- cur = CUR_CHAR(l);
- continue;
- } else if ((cur == '<') && (NXT(1) == '/')) {
+ if ((cur == '<') && (NXT(1) == '/')) {
/*
* One should break here, the specification is clear:
* Authors should therefore escape "</" within the content.
@@ -2673,8 +2892,8 @@ htmlParseScript(htmlParserCtxtPtr ctxt) {
* CDATA.
*/
if (ctxt->recovery) {
- if (xmlStrncasecmp(ctxt->name, ctxt->input->cur+2,
- xmlStrlen(ctxt->name)) == 0)
+ if (xmlStrncasecmp(ctxt->name, ctxt->input->cur+2,
+ xmlStrlen(ctxt->name)) == 0)
{
break; /* while */
} else {
@@ -2684,7 +2903,7 @@ htmlParseScript(htmlParserCtxtPtr ctxt) {
}
} else {
if (((NXT(2) >= 'A') && (NXT(2) <= 'Z')) ||
- ((NXT(2) >= 'a') && (NXT(2) <= 'z')))
+ ((NXT(2) >= 'a') && (NXT(2) <= 'z')))
{
break; /* while */
}
@@ -2708,9 +2927,11 @@ htmlParseScript(htmlParserCtxtPtr ctxt) {
}
if ((!(IS_CHAR_CH(cur))) && (!((cur == 0) && (ctxt->progressive)))) {
- htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
- "Invalid char in CDATA 0x%X\n", cur);
- NEXT;
+ htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+ "Invalid char in CDATA 0x%X\n", cur);
+ if (ctxt->input->cur < ctxt->input->end) {
+ NEXT;
+ }
}
if ((nbchar != 0) && (ctxt->sax != NULL) && (!ctxt->disableSAX)) {
@@ -2727,8 +2948,9 @@ htmlParseScript(htmlParserCtxtPtr ctxt) {
/**
- * htmlParseCharData:
+ * htmlParseCharDataInternal:
* @ctxt: an HTML parser context
+ * @readahead: optional read ahead character in ascii range
*
* parse a CharData section.
* if we are within a CDATA section ']]>' marks an end of section.
@@ -2737,26 +2959,40 @@ htmlParseScript(htmlParserCtxtPtr ctxt) {
*/
static void
-htmlParseCharData(htmlParserCtxtPtr ctxt) {
- xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 5];
+htmlParseCharDataInternal(htmlParserCtxtPtr ctxt, int readahead) {
+ xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 6];
int nbchar = 0;
int cur, l;
+ int chunk = 0;
+
+ if (readahead)
+ buf[nbchar++] = readahead;
SHRINK;
cur = CUR_CHAR(l);
while (((cur != '<') || (ctxt->token == '<')) &&
- ((cur != '&') || (ctxt->token == '&')) &&
- (IS_CHAR(cur))) {
- COPY_BUF(l,buf,nbchar,cur);
+ ((cur != '&') || (ctxt->token == '&')) &&
+ (cur != 0)) {
+ if (!(IS_CHAR(cur))) {
+ htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+ "Invalid char in CDATA 0x%X\n", cur);
+ } else {
+ COPY_BUF(l,buf,nbchar,cur);
+ }
if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) {
/*
* Ok the segment is to be consumed as chars.
*/
if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
if (areBlanks(ctxt, buf, nbchar)) {
- if (ctxt->sax->ignorableWhitespace != NULL)
- ctxt->sax->ignorableWhitespace(ctxt->userData,
- buf, nbchar);
+ if (ctxt->keepBlanks) {
+ if (ctxt->sax->characters != NULL)
+ ctxt->sax->characters(ctxt->userData, buf, nbchar);
+ } else {
+ if (ctxt->sax->ignorableWhitespace != NULL)
+ ctxt->sax->ignorableWhitespace(ctxt->userData,
+ buf, nbchar);
+ }
} else {
htmlCheckParagraph(ctxt);
if (ctxt->sax->characters != NULL)
@@ -2766,6 +3002,12 @@ htmlParseCharData(htmlParserCtxtPtr ctxt) {
nbchar = 0;
}
NEXTL(l);
+ chunk++;
+ if (chunk > HTML_PARSER_BUFFER_SIZE) {
+ chunk = 0;
+ SHRINK;
+ GROW;
+ }
cur = CUR_CHAR(l);
if (cur == 0) {
SHRINK;
@@ -2781,8 +3023,14 @@ htmlParseCharData(htmlParserCtxtPtr ctxt) {
*/
if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
if (areBlanks(ctxt, buf, nbchar)) {
- if (ctxt->sax->ignorableWhitespace != NULL)
- ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar);
+ if (ctxt->keepBlanks) {
+ if (ctxt->sax->characters != NULL)
+ ctxt->sax->characters(ctxt->userData, buf, nbchar);
+ } else {
+ if (ctxt->sax->ignorableWhitespace != NULL)
+ ctxt->sax->ignorableWhitespace(ctxt->userData,
+ buf, nbchar);
+ }
} else {
htmlCheckParagraph(ctxt);
if (ctxt->sax->characters != NULL)
@@ -2799,6 +3047,21 @@ htmlParseCharData(htmlParserCtxtPtr ctxt) {
}
/**
+ * htmlParseCharData:
+ * @ctxt: an HTML parser context
+ *
+ * parse a CharData section.
+ * if we are within a CDATA section ']]>' marks an end of section.
+ *
+ * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
+ */
+
+static void
+htmlParseCharData(htmlParserCtxtPtr ctxt) {
+ htmlParseCharDataInternal(ctxt, 0);
+}
+
+/**
* htmlParseExternalID:
* @ctxt: an HTML parser context
* @publicID: a xmlChar** receiving PubidLiteral
@@ -2960,7 +3223,7 @@ htmlParsePI(htmlParserCtxtPtr ctxt) {
}
xmlFree(buf);
} else {
- htmlParseErr(ctxt, XML_ERR_PI_NOT_STARTED,
+ htmlParseErr(ctxt, XML_ERR_PI_NOT_STARTED,
"PI is not started correctly", NULL, NULL);
}
ctxt->instate = state;
@@ -3001,12 +3264,17 @@ htmlParseComment(htmlParserCtxtPtr ctxt) {
ctxt->instate = state;
return;
}
+ len = 0;
+ buf[len] = 0;
q = CUR_CHAR(ql);
+ if (!IS_CHAR(q))
+ goto unfinished;
NEXTL(ql);
r = CUR_CHAR(rl);
+ if (!IS_CHAR(r))
+ goto unfinished;
NEXTL(rl);
cur = CUR_CHAR(l);
- len = 0;
while (IS_CHAR(cur) &&
((cur != '>') ||
(r != '-') || (q != '-'))) {
@@ -3037,18 +3305,20 @@ htmlParseComment(htmlParserCtxtPtr ctxt) {
}
}
buf[len] = 0;
- if (!IS_CHAR(cur)) {
- htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
- "Comment not terminated \n<!--%.50s\n", buf, NULL);
- xmlFree(buf);
- } else {
+ if (IS_CHAR(cur)) {
NEXT;
if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
(!ctxt->disableSAX))
ctxt->sax->comment(ctxt->userData, buf);
xmlFree(buf);
+ ctxt->instate = state;
+ return;
}
- ctxt->instate = state;
+
+unfinished:
+ htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
+ "Comment not terminated \n<!--%.50s\n", buf, NULL);
+ xmlFree(buf);
}
/**
@@ -3076,7 +3346,7 @@ htmlParseCharRef(htmlParserCtxtPtr ctxt) {
((NXT(2) == 'x') || NXT(2) == 'X')) {
SKIP(3);
while (CUR != ';') {
- if ((CUR >= '0') && (CUR <= '9'))
+ if ((CUR >= '0') && (CUR <= '9'))
val = val * 16 + (CUR - '0');
else if ((CUR >= 'a') && (CUR <= 'f'))
val = val * 16 + (CUR - 'a') + 10;
@@ -3084,9 +3354,9 @@ htmlParseCharRef(htmlParserCtxtPtr ctxt) {
val = val * 16 + (CUR - 'A') + 10;
else {
htmlParseErr(ctxt, XML_ERR_INVALID_HEX_CHARREF,
- "htmlParseCharRef: invalid hexadecimal value\n",
+ "htmlParseCharRef: missing semicolon\n",
NULL, NULL);
- return(0);
+ break;
}
NEXT;
}
@@ -3095,13 +3365,13 @@ htmlParseCharRef(htmlParserCtxtPtr ctxt) {
} else if ((CUR == '&') && (NXT(1) == '#')) {
SKIP(2);
while (CUR != ';') {
- if ((CUR >= '0') && (CUR <= '9'))
+ if ((CUR >= '0') && (CUR <= '9'))
val = val * 10 + (CUR - '0');
else {
htmlParseErr(ctxt, XML_ERR_INVALID_DEC_CHARREF,
- "htmlParseCharRef: invalid decimal value\n",
+ "htmlParseCharRef: missing semicolon\n",
NULL, NULL);
- return(0);
+ break;
}
NEXT;
}
@@ -3131,7 +3401,7 @@ htmlParseCharRef(htmlParserCtxtPtr ctxt) {
*
* parse a DOCTYPE declaration
*
- * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
+ * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
* ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
*/
@@ -3235,11 +3505,6 @@ htmlParseAttribute(htmlParserCtxtPtr ctxt, xmlChar **value) {
NEXT;
SKIP_BLANKS;
val = htmlParseAttValue(ctxt);
- } else if (htmlIsBooleanAttr(name)) {
- /*
- * assume a minimized attribute
- */
- val = xmlStrdup(name);
}
*value = val;
@@ -3247,34 +3512,26 @@ htmlParseAttribute(htmlParserCtxtPtr ctxt, xmlChar **value) {
}
/**
- * htmlCheckEncoding:
+ * htmlCheckEncodingDirect:
* @ctxt: an HTML parser context
* @attvalue: the attribute value
*
- * Checks an http-equiv attribute from a Meta tag to detect
+ * Checks an attribute value to detect
* the encoding
* If a new encoding is detected the parser is switched to decode
* it and pass UTF8
*/
static void
-htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
- const xmlChar *encoding;
+htmlCheckEncodingDirect(htmlParserCtxtPtr ctxt, const xmlChar *encoding) {
- if ((ctxt == NULL) || (attvalue == NULL))
+ if ((ctxt == NULL) || (encoding == NULL) ||
+ (ctxt->options & HTML_PARSE_IGNORE_ENC))
return;
- /* do not change encoding */
+ /* do not change encoding */
if (ctxt->input->encoding != NULL)
return;
- encoding = xmlStrcasestr(attvalue, BAD_CAST"charset=");
- if (encoding != NULL) {
- encoding += 8;
- } else {
- encoding = xmlStrcasestr(attvalue, BAD_CAST"charset =");
- if (encoding != NULL)
- encoding += 9;
- }
if (encoding != NULL) {
xmlCharEncoding enc;
xmlCharEncodingHandlerPtr handler;
@@ -3290,7 +3547,7 @@ htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
* registered set of known encodings
*/
if (enc != XML_CHAR_ENCODING_ERROR) {
- if (((enc == XML_CHAR_ENCODING_UTF16LE) ||
+ if (((enc == XML_CHAR_ENCODING_UTF16LE) ||
(enc == XML_CHAR_ENCODING_UTF16BE) ||
(enc == XML_CHAR_ENCODING_UCS4LE) ||
(enc == XML_CHAR_ENCODING_UCS4BE)) &&
@@ -3312,7 +3569,9 @@ htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
xmlSwitchToEncoding(ctxt, handler);
ctxt->charset = XML_CHAR_ENCODING_UTF8;
} else {
- ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+ htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
+ "htmlCheckEncoding: unknown encoding %s\n",
+ encoding, NULL);
}
}
@@ -3327,22 +3586,51 @@ htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
* convert as much as possible to the parser reading buffer.
*/
processed = ctxt->input->cur - ctxt->input->base;
- xmlBufferShrink(ctxt->input->buf->buffer, processed);
- nbchars = xmlCharEncInFunc(ctxt->input->buf->encoder,
- ctxt->input->buf->buffer,
- ctxt->input->buf->raw);
+ xmlBufShrink(ctxt->input->buf->buffer, processed);
+ nbchars = xmlCharEncInput(ctxt->input->buf, 1);
if (nbchars < 0) {
htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
"htmlCheckEncoding: encoder error\n",
NULL, NULL);
}
- ctxt->input->base =
- ctxt->input->cur = ctxt->input->buf->buffer->content;
+ xmlBufResetInput(ctxt->input->buf->buffer, ctxt->input);
}
}
}
/**
+ * htmlCheckEncoding:
+ * @ctxt: an HTML parser context
+ * @attvalue: the attribute value
+ *
+ * Checks an http-equiv attribute from a Meta tag to detect
+ * the encoding
+ * If a new encoding is detected the parser is switched to decode
+ * it and pass UTF8
+ */
+static void
+htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
+ const xmlChar *encoding;
+
+ if (!attvalue)
+ return;
+
+ encoding = xmlStrcasestr(attvalue, BAD_CAST"charset");
+ if (encoding != NULL) {
+ encoding += 7;
+ }
+ /*
+ * skip blank
+ */
+ if (encoding && IS_BLANK_CH(*encoding))
+ encoding = xmlStrcasestr(attvalue, BAD_CAST"=");
+ if (encoding && *encoding == '=') {
+ encoding ++;
+ htmlCheckEncodingDirect(ctxt, encoding);
+ }
+}
+
+/**
* htmlCheckMeta:
* @ctxt: an HTML parser context
* @atts: the attributes values
@@ -3366,6 +3654,8 @@ htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts) {
if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"http-equiv"))
&& (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
http = 1;
+ else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"charset")))
+ htmlCheckEncodingDirect(ctxt, value);
else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"content")))
content = value;
att = atts[i++];
@@ -3378,7 +3668,7 @@ htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts) {
/**
* htmlParseStartTag:
* @ctxt: an HTML parser context
- *
+ *
* parse a start of tag either for rule element or
* EmptyElement. In both case we don't parse the tag closing chars.
*
@@ -3392,7 +3682,7 @@ htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts) {
*
* [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
*
- * Returns 0 in case of success and -1 in case of error.
+ * Returns 0 in case of success, -1 in case of error and 1 if discarded
*/
static int
@@ -3405,12 +3695,15 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) {
int maxatts;
int meta = 0;
int i;
+ int discardtag = 0;
if ((ctxt == NULL) || (ctxt->input == NULL)) {
htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
"htmlParseStartTag: context error\n", NULL, NULL);
return -1;
}
+ if (ctxt->instate == XML_PARSER_EOF)
+ return(-1);
if (CUR != '<') return -1;
NEXT;
@@ -3423,8 +3716,17 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) {
htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
"htmlParseStartTag: invalid element name\n",
NULL, NULL);
+ /* if recover preserve text on classic misconstructs */
+ if ((ctxt->recovery) && ((IS_BLANK_CH(CUR)) || (CUR == '<') ||
+ (CUR == '=') || (CUR == '>') || (((CUR >= '0') && (CUR <= '9'))))) {
+ htmlParseCharDataInternal(ctxt, '<');
+ return(-1);
+ }
+
+
/* Dump the bogus tag like browsers do */
- while ((IS_CHAR_CH(CUR)) && (CUR != '>'))
+ while ((IS_CHAR_CH(CUR)) && (CUR != '>') &&
+ (ctxt->instate != XML_PARSER_EOF))
NEXT;
return -1;
}
@@ -3449,14 +3751,16 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) {
htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
"htmlParseStartTag: misplaced <html> tag\n",
name, NULL);
- return 0;
+ discardtag = 1;
+ ctxt->depth++;
}
- if ((ctxt->nameNr != 1) &&
+ if ((ctxt->nameNr != 1) &&
(xmlStrEqual(name, BAD_CAST"head"))) {
htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
"htmlParseStartTag: misplaced <head> tag\n",
name, NULL);
- return 0;
+ discardtag = 1;
+ ctxt->depth++;
}
if (xmlStrEqual(name, BAD_CAST"body")) {
int indx;
@@ -3465,9 +3769,8 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) {
htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
"htmlParseStartTag: misplaced <body> tag\n",
name, NULL);
- while ((IS_CHAR_CH(CUR)) && (CUR != '>'))
- NEXT;
- return 0;
+ discardtag = 1;
+ ctxt->depth++;
}
}
}
@@ -3479,7 +3782,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) {
*/
SKIP_BLANKS;
while ((IS_CHAR_CH(CUR)) &&
- (CUR != '>') &&
+ (CUR != '>') &&
((CUR != '/') || (NXT(1) != '>'))) {
long cons = ctxt->nbChars;
@@ -3560,18 +3863,20 @@ failed:
/*
* Handle specific association to the META tag
*/
- if (meta)
+ if (meta && (nbatts != 0))
htmlCheckMeta(ctxt, atts);
/*
* SAX: Start of Element !
*/
- htmlnamePush(ctxt, name);
- if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL)) {
- if (nbatts != 0)
- ctxt->sax->startElement(ctxt->userData, name, atts);
- else
- ctxt->sax->startElement(ctxt->userData, name, NULL);
+ if (!discardtag) {
+ htmlnamePush(ctxt, name);
+ if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL)) {
+ if (nbatts != 0)
+ ctxt->sax->startElement(ctxt->userData, name, atts);
+ else
+ ctxt->sax->startElement(ctxt->userData, name, NULL);
+ }
}
if (atts != NULL) {
@@ -3581,7 +3886,7 @@ failed:
}
}
- return 0;
+ return(discardtag);
}
/**
@@ -3616,7 +3921,6 @@ htmlParseEndTag(htmlParserCtxtPtr ctxt)
name = htmlParseHTMLName(ctxt);
if (name == NULL)
return (0);
-
/*
* We should definitely be at the ending "S? '>'" part
*/
@@ -3637,6 +3941,18 @@ htmlParseEndTag(htmlParserCtxtPtr ctxt)
NEXT;
/*
+ * if we ignored misplaced tags in htmlParseStartTag don't pop them
+ * out now.
+ */
+ if ((ctxt->depth > 0) &&
+ (xmlStrEqual(name, BAD_CAST "html") ||
+ xmlStrEqual(name, BAD_CAST "body") ||
+ xmlStrEqual(name, BAD_CAST "head"))) {
+ ctxt->depth--;
+ return (0);
+ }
+
+ /*
* If the name read is not one of the element in the parsing stack
* then return, it's just an error.
*/
@@ -3677,6 +3993,7 @@ htmlParseEndTag(htmlParserCtxtPtr ctxt)
if ((oldname != NULL) && (xmlStrEqual(oldname, name))) {
if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
ctxt->sax->endElement(ctxt->userData, name);
+ htmlNodeInfoPop(ctxt);
htmlnamePop(ctxt);
ret = 1;
} else {
@@ -3690,7 +4007,7 @@ htmlParseEndTag(htmlParserCtxtPtr ctxt)
/**
* htmlParseReference:
* @ctxt: an HTML parser context
- *
+ *
* parse and handle entity references in content,
* this will end-up in a call to character() since this is either a
* CharRef, or a predefined entity.
@@ -3714,7 +4031,7 @@ htmlParseReference(htmlParserCtxtPtr ctxt) {
else if (c < 0x800) { out[i++]=((c >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (c < 0x10000) { out[i++]=((c >> 12) & 0x0F) | 0xE0; bits= 6; }
else { out[i++]=((c >> 18) & 0x07) | 0xF0; bits= 12; }
-
+
for ( ; bits >= 0; bits-= 6) {
out[i++]= ((c >> bits) & 0x3F) | 0x80;
}
@@ -3749,9 +4066,9 @@ htmlParseReference(htmlParserCtxtPtr ctxt) {
{ out[i++]=((c >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (c < 0x10000)
{ out[i++]=((c >> 12) & 0x0F) | 0xE0; bits= 6; }
- else
+ else
{ out[i++]=((c >> 18) & 0x07) | 0xF0; bits= 12; }
-
+
for ( ; bits >= 0; bits-= 6) {
out[i++]= ((c >> bits) & 0x3F) | 0x80;
}
@@ -3769,12 +4086,14 @@ htmlParseReference(htmlParserCtxtPtr ctxt) {
* @ctxt: an HTML parser context
*
* Parse a content: comment, sub-element, reference or text.
+ * Kept for compatibility with old code
*/
static void
htmlParseContent(htmlParserCtxtPtr ctxt) {
xmlChar *currentNode;
int depth;
+ const xmlChar *name;
currentNode = xmlStrdup(ctxt->name);
depth = ctxt->nameNr;
@@ -3782,6 +4101,10 @@ htmlParseContent(htmlParserCtxtPtr ctxt) {
long cons = ctxt->nbChars;
GROW;
+
+ if (ctxt->instate == XML_PARSER_EOF)
+ break;
+
/*
* Our tag or one of it's parent or children is ending.
*/
@@ -3795,6 +4118,31 @@ htmlParseContent(htmlParserCtxtPtr ctxt) {
continue; /* while */
}
+ else if ((CUR == '<') &&
+ ((IS_ASCII_LETTER(NXT(1))) ||
+ (NXT(1) == '_') || (NXT(1) == ':'))) {
+ name = htmlParseHTMLName_nonInvasive(ctxt);
+ if (name == NULL) {
+ htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
+ "htmlParseStartTag: invalid element name\n",
+ NULL, NULL);
+ /* Dump the bogus tag like browsers do */
+ while ((IS_CHAR_CH(CUR)) && (CUR != '>'))
+ NEXT;
+
+ if (currentNode != NULL)
+ xmlFree(currentNode);
+ return;
+ }
+
+ if (ctxt->name != NULL) {
+ if (htmlCheckAutoClose(name, ctxt->name) == 1) {
+ htmlAutoClose(ctxt, name);
+ continue;
+ }
+ }
+ }
+
/*
* Has this node been popped out during parsing of
* the next element
@@ -3851,7 +4199,7 @@ htmlParseContent(htmlParserCtxtPtr ctxt) {
/*
* Fourth case : a reference. If if has not been resolved,
- * parsing returns it's Name, create the node
+ * parsing returns it's Name, create the node
*/
else if (CUR == '&') {
htmlParseReference(ctxt);
@@ -3887,23 +4235,11 @@ htmlParseContent(htmlParserCtxtPtr ctxt) {
}
/**
- * htmlParseContent:
- * @ctxt: an HTML parser context
- *
- * Parse a content: comment, sub-element, reference or text.
- */
-
-void
-__htmlParseContent(void *ctxt) {
- if (ctxt != NULL)
- htmlParseContent((htmlParserCtxtPtr) ctxt);
-}
-
-/**
* htmlParseElement:
* @ctxt: an HTML parser context
*
* parse an HTML element, this is highly recursive
+ * this is kept for compatibility with previous code versions
*
* [39] element ::= EmptyElemTag | STag content ETag
*
@@ -3925,6 +4261,10 @@ htmlParseElement(htmlParserCtxtPtr ctxt) {
"htmlParseElement: context error\n", NULL, NULL);
return;
}
+
+ if (ctxt->instate == XML_PARSER_EOF)
+ return;
+
/* Capture start position */
if (ctxt->record_info) {
node_info.begin_pos = ctxt->input->consumed +
@@ -3934,7 +4274,7 @@ htmlParseElement(htmlParserCtxtPtr ctxt) {
failed = htmlParseStartTag(ctxt);
name = ctxt->name;
- if (failed || (name == NULL)) {
+ if ((failed == -1) || (name == NULL)) {
if (CUR == '>')
NEXT;
return;
@@ -3969,10 +4309,10 @@ htmlParseElement(htmlParserCtxtPtr ctxt) {
/*
* end of parsing of this node.
*/
- if (xmlStrEqual(name, ctxt->name)) {
+ if (xmlStrEqual(name, ctxt->name)) {
nodePop(ctxt);
htmlnamePop(ctxt);
- }
+ }
/*
* Capture end position and add node
@@ -4006,8 +4346,8 @@ htmlParseElement(htmlParserCtxtPtr ctxt) {
oldptr = ctxt->input->cur;
htmlParseContent(ctxt);
if (oldptr==ctxt->input->cur) break;
- if (ctxt->nameNr < depth) break;
- }
+ if (ctxt->nameNr < depth) break;
+ }
/*
* Capture end position and add node
@@ -4027,10 +4367,305 @@ htmlParseElement(htmlParserCtxtPtr ctxt) {
xmlFree(currentNode);
}
+static void
+htmlParserFinishElementParsing(htmlParserCtxtPtr ctxt) {
+ /*
+ * Capture end position and add node
+ */
+ if ( ctxt->node != NULL && ctxt->record_info ) {
+ ctxt->nodeInfo->end_pos = ctxt->input->consumed +
+ (CUR_PTR - ctxt->input->base);
+ ctxt->nodeInfo->end_line = ctxt->input->line;
+ ctxt->nodeInfo->node = ctxt->node;
+ xmlParserAddNodeInfo(ctxt, ctxt->nodeInfo);
+ htmlNodeInfoPop(ctxt);
+ }
+ if (!IS_CHAR_CH(CUR)) {
+ htmlAutoCloseOnEnd(ctxt);
+ }
+}
+
+/**
+ * htmlParseElementInternal:
+ * @ctxt: an HTML parser context
+ *
+ * parse an HTML element, new version, non recursive
+ *
+ * [39] element ::= EmptyElemTag | STag content ETag
+ *
+ * [41] Attribute ::= Name Eq AttValue
+ */
+
+static void
+htmlParseElementInternal(htmlParserCtxtPtr ctxt) {
+ const xmlChar *name;
+ const htmlElemDesc * info;
+ htmlParserNodeInfo node_info = { 0, };
+ int failed;
+
+ if ((ctxt == NULL) || (ctxt->input == NULL)) {
+ htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
+ "htmlParseElementInternal: context error\n", NULL, NULL);
+ return;
+ }
+
+ if (ctxt->instate == XML_PARSER_EOF)
+ return;
+
+ /* Capture start position */
+ if (ctxt->record_info) {
+ node_info.begin_pos = ctxt->input->consumed +
+ (CUR_PTR - ctxt->input->base);
+ node_info.begin_line = ctxt->input->line;
+ }
+
+ failed = htmlParseStartTag(ctxt);
+ name = ctxt->name;
+ if ((failed == -1) || (name == NULL)) {
+ if (CUR == '>')
+ NEXT;
+ return;
+ }
+
+ /*
+ * Lookup the info for that element.
+ */
+ info = htmlTagLookup(name);
+ if (info == NULL) {
+ htmlParseErr(ctxt, XML_HTML_UNKNOWN_TAG,
+ "Tag %s invalid\n", name, NULL);
+ }
+
+ /*
+ * Check for an Empty Element labeled the XML/SGML way
+ */
+ if ((CUR == '/') && (NXT(1) == '>')) {
+ SKIP(2);
+ if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+ ctxt->sax->endElement(ctxt->userData, name);
+ htmlnamePop(ctxt);
+ return;
+ }
+
+ if (CUR == '>') {
+ NEXT;
+ } else {
+ htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
+ "Couldn't find end of Start Tag %s\n", name, NULL);
+
+ /*
+ * end of parsing of this node.
+ */
+ if (xmlStrEqual(name, ctxt->name)) {
+ nodePop(ctxt);
+ htmlnamePop(ctxt);
+ }
+
+ if (ctxt->record_info)
+ htmlNodeInfoPush(ctxt, &node_info);
+ htmlParserFinishElementParsing(ctxt);
+ return;
+ }
+
+ /*
+ * Check for an Empty Element from DTD definition
+ */
+ if ((info != NULL) && (info->empty)) {
+ if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+ ctxt->sax->endElement(ctxt->userData, name);
+ htmlnamePop(ctxt);
+ return;
+ }
+
+ if (ctxt->record_info)
+ htmlNodeInfoPush(ctxt, &node_info);
+}
+
+/**
+ * htmlParseContentInternal:
+ * @ctxt: an HTML parser context
+ *
+ * Parse a content: comment, sub-element, reference or text.
+ * New version for non recursive htmlParseElementInternal
+ */
+
+static void
+htmlParseContentInternal(htmlParserCtxtPtr ctxt) {
+ xmlChar *currentNode;
+ int depth;
+ const xmlChar *name;
+
+ currentNode = xmlStrdup(ctxt->name);
+ depth = ctxt->nameNr;
+ while (1) {
+ long cons = ctxt->nbChars;
+
+ GROW;
+
+ if (ctxt->instate == XML_PARSER_EOF)
+ break;
+
+ /*
+ * Our tag or one of it's parent or children is ending.
+ */
+ if ((CUR == '<') && (NXT(1) == '/')) {
+ if (htmlParseEndTag(ctxt) &&
+ ((currentNode != NULL) || (ctxt->nameNr == 0))) {
+ if (currentNode != NULL)
+ xmlFree(currentNode);
+
+ currentNode = xmlStrdup(ctxt->name);
+ depth = ctxt->nameNr;
+ }
+ continue; /* while */
+ }
+
+ else if ((CUR == '<') &&
+ ((IS_ASCII_LETTER(NXT(1))) ||
+ (NXT(1) == '_') || (NXT(1) == ':'))) {
+ name = htmlParseHTMLName_nonInvasive(ctxt);
+ if (name == NULL) {
+ htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
+ "htmlParseStartTag: invalid element name\n",
+ NULL, NULL);
+ /* Dump the bogus tag like browsers do */
+ while ((IS_CHAR_CH(CUR)) && (CUR != '>'))
+ NEXT;
+
+ htmlParserFinishElementParsing(ctxt);
+ if (currentNode != NULL)
+ xmlFree(currentNode);
+
+ currentNode = xmlStrdup(ctxt->name);
+ depth = ctxt->nameNr;
+ continue;
+ }
+
+ if (ctxt->name != NULL) {
+ if (htmlCheckAutoClose(name, ctxt->name) == 1) {
+ htmlAutoClose(ctxt, name);
+ continue;
+ }
+ }
+ }
+
+ /*
+ * Has this node been popped out during parsing of
+ * the next element
+ */
+ if ((ctxt->nameNr > 0) && (depth >= ctxt->nameNr) &&
+ (!xmlStrEqual(currentNode, ctxt->name)))
+ {
+ htmlParserFinishElementParsing(ctxt);
+ if (currentNode != NULL) xmlFree(currentNode);
+
+ currentNode = xmlStrdup(ctxt->name);
+ depth = ctxt->nameNr;
+ continue;
+ }
+
+ if ((CUR != 0) && ((xmlStrEqual(currentNode, BAD_CAST"script")) ||
+ (xmlStrEqual(currentNode, BAD_CAST"style")))) {
+ /*
+ * Handle SCRIPT/STYLE separately
+ */
+ htmlParseScript(ctxt);
+ } else {
+ /*
+ * Sometimes DOCTYPE arrives in the middle of the document
+ */
+ if ((CUR == '<') && (NXT(1) == '!') &&
+ (UPP(2) == 'D') && (UPP(3) == 'O') &&
+ (UPP(4) == 'C') && (UPP(5) == 'T') &&
+ (UPP(6) == 'Y') && (UPP(7) == 'P') &&
+ (UPP(8) == 'E')) {
+ htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
+ "Misplaced DOCTYPE declaration\n",
+ BAD_CAST "DOCTYPE" , NULL);
+ htmlParseDocTypeDecl(ctxt);
+ }
+
+ /*
+ * First case : a comment
+ */
+ if ((CUR == '<') && (NXT(1) == '!') &&
+ (NXT(2) == '-') && (NXT(3) == '-')) {
+ htmlParseComment(ctxt);
+ }
+
+ /*
+ * Second case : a Processing Instruction.
+ */
+ else if ((CUR == '<') && (NXT(1) == '?')) {
+ htmlParsePI(ctxt);
+ }
+
+ /*
+ * Third case : a sub-element.
+ */
+ else if (CUR == '<') {
+ htmlParseElementInternal(ctxt);
+ if (currentNode != NULL) xmlFree(currentNode);
+
+ currentNode = xmlStrdup(ctxt->name);
+ depth = ctxt->nameNr;
+ }
+
+ /*
+ * Fourth case : a reference. If if has not been resolved,
+ * parsing returns it's Name, create the node
+ */
+ else if (CUR == '&') {
+ htmlParseReference(ctxt);
+ }
+
+ /*
+ * Fifth case : end of the resource
+ */
+ else if (CUR == 0) {
+ htmlAutoCloseOnEnd(ctxt);
+ break;
+ }
+
+ /*
+ * Last case, text. Note that References are handled directly.
+ */
+ else {
+ htmlParseCharData(ctxt);
+ }
+
+ if (cons == ctxt->nbChars) {
+ if (ctxt->node != NULL) {
+ htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
+ "detected an error in element content\n",
+ NULL, NULL);
+ }
+ break;
+ }
+ }
+ GROW;
+ }
+ if (currentNode != NULL) xmlFree(currentNode);
+}
+
+/**
+ * htmlParseContent:
+ * @ctxt: an HTML parser context
+ *
+ * Parse a content: comment, sub-element, reference or text.
+ * This is the entry point when called from parser.c
+ */
+
+void
+__htmlParseContent(void *ctxt) {
+ if (ctxt != NULL)
+ htmlParseContentInternal((htmlParserCtxtPtr) ctxt);
+}
+
/**
* htmlParseDocument:
* @ctxt: an HTML parser context
- *
+ *
* parse an HTML document (and build a tree if using the standard SAX
* interface).
*
@@ -4040,6 +4675,8 @@ htmlParseElement(htmlParserCtxtPtr ctxt) {
int
htmlParseDocument(htmlParserCtxtPtr ctxt) {
+ xmlChar start[4];
+ xmlCharEncoding enc;
xmlDtdPtr dtd;
xmlInitParser();
@@ -4052,6 +4689,7 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) {
return(XML_ERR_INTERNAL_ERROR);
}
ctxt->html = 1;
+ ctxt->linenumbers = 1;
GROW;
/*
* SAX: beginning of the document processing.
@@ -4059,12 +4697,29 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) {
if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
+ if ((ctxt->encoding == (const xmlChar *)XML_CHAR_ENCODING_NONE) &&
+ ((ctxt->input->end - ctxt->input->cur) >= 4)) {
+ /*
+ * Get the 4 first bytes and decode the charset
+ * if enc != XML_CHAR_ENCODING_NONE
+ * plug some encoding conversion routines.
+ */
+ start[0] = RAW;
+ start[1] = NXT(1);
+ start[2] = NXT(2);
+ start[3] = NXT(3);
+ enc = xmlDetectCharEncoding(&start[0], 4);
+ if (enc != XML_CHAR_ENCODING_NONE) {
+ xmlSwitchEncoding(ctxt, enc);
+ }
+ }
+
/*
* Wipe out everything which is before the first '<'
*/
SKIP_BLANKS;
if (CUR == 0) {
- htmlParseErr(ctxt, XML_ERR_DOCUMENT_EMPTY,
+ htmlParseErr(ctxt, XML_ERR_DOCUMENT_EMPTY,
"Document is empty\n", NULL, NULL);
}
@@ -4078,10 +4733,10 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) {
while (((CUR == '<') && (NXT(1) == '!') &&
(NXT(2) == '-') && (NXT(3) == '-')) ||
((CUR == '<') && (NXT(1) == '?'))) {
- htmlParseComment(ctxt);
- htmlParsePI(ctxt);
+ htmlParseComment(ctxt);
+ htmlParsePI(ctxt);
SKIP_BLANKS;
- }
+ }
/*
@@ -4103,15 +4758,15 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) {
while (((CUR == '<') && (NXT(1) == '!') &&
(NXT(2) == '-') && (NXT(3) == '-')) ||
((CUR == '<') && (NXT(1) == '?'))) {
- htmlParseComment(ctxt);
- htmlParsePI(ctxt);
+ htmlParseComment(ctxt);
+ htmlParsePI(ctxt);
SKIP_BLANKS;
- }
+ }
/*
* Time to start parsing the tree itself
*/
- htmlParseContent(ctxt);
+ htmlParseContentInternal(ctxt);
/*
* autoclose
@@ -4126,11 +4781,11 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) {
if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
ctxt->sax->endDocument(ctxt->userData);
- if (ctxt->myDoc != NULL) {
+ if ((!(ctxt->options & HTML_PARSE_NODEFDTD)) && (ctxt->myDoc != NULL)) {
dtd = xmlGetIntSubset(ctxt->myDoc);
if (dtd == NULL)
- ctxt->myDoc->intSubset =
- xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
+ ctxt->myDoc->intSubset =
+ xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
}
@@ -4176,7 +4831,7 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt)
memset(sax, 0, sizeof(htmlSAXHandler));
/* Allocate the Input stack */
- ctxt->inputTab = (htmlParserInputPtr *)
+ ctxt->inputTab = (htmlParserInputPtr *)
xmlMalloc(5 * sizeof(htmlParserInputPtr));
if (ctxt->inputTab == NULL) {
htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
@@ -4214,7 +4869,7 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt)
if (ctxt->nameTab == NULL) {
htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
ctxt->nameNr = 0;
- ctxt->nameMax = 10;
+ ctxt->nameMax = 0;
ctxt->name = NULL;
ctxt->nodeNr = 0;
ctxt->nodeMax = 0;
@@ -4228,6 +4883,10 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt)
ctxt->nameMax = 10;
ctxt->name = NULL;
+ ctxt->nodeInfoTab = NULL;
+ ctxt->nodeInfoNr = 0;
+ ctxt->nodeInfoMax = 0;
+
if (sax == NULL) ctxt->sax = (xmlSAXHandlerPtr) &htmlDefaultSAXHandler;
else {
ctxt->sax = sax;
@@ -4327,9 +4986,7 @@ htmlCreateMemoryParserCtxt(const char *buffer, int size) {
input->filename = NULL;
input->buf = buf;
- input->base = input->buf->buffer->content;
- input->cur = input->buf->buffer->content;
- input->end = &input->buf->buffer->content[input->buf->buffer->use];
+ xmlBufResetInput(buf->buffer, input);
inputPush(ctxt, input);
return(ctxt);
@@ -4347,8 +5004,7 @@ htmlCreateMemoryParserCtxt(const char *buffer, int size) {
* Returns the new parser context or NULL
*/
static htmlParserCtxtPtr
-htmlCreateDocParserCtxt(const xmlChar *cur,
- const char *encoding ATTRIBUTE_UNUSED) {
+htmlCreateDocParserCtxt(const xmlChar *cur, const char *encoding) {
int len;
htmlParserCtxtPtr ctxt;
@@ -4356,6 +5012,8 @@ htmlCreateDocParserCtxt(const xmlChar *cur,
return(NULL);
len = xmlStrlen(cur);
ctxt = htmlCreateMemoryParserCtxt((char *)cur, len);
+ if (ctxt == NULL)
+ return(NULL);
if (encoding != NULL) {
xmlCharEncoding enc;
@@ -4373,7 +5031,7 @@ htmlCreateDocParserCtxt(const xmlChar *cur,
xmlSwitchEncoding(ctxt, enc);
if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
- "Unsupported encoding %s\n",
+ "Unsupported encoding %s\n",
(const xmlChar *) encoding, NULL);
}
} else {
@@ -4396,7 +5054,7 @@ htmlCreateDocParserCtxt(const xmlChar *cur,
#ifdef LIBXML_PUSH_ENABLED
/************************************************************************
* *
- * Progressive parsing interfaces *
+ * Progressive parsing interfaces *
* *
************************************************************************/
@@ -4420,85 +5078,190 @@ htmlCreateDocParserCtxt(const xmlChar *cur,
*/
static int
htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
- xmlChar next, xmlChar third, int iscomment) {
+ xmlChar next, xmlChar third, int iscomment,
+ int ignoreattrval)
+{
int base, len;
htmlParserInputPtr in;
const xmlChar *buf;
int incomment = 0;
+ int invalue = 0;
+ char valdellim = 0x0;
in = ctxt->input;
- if (in == NULL) return(-1);
+ if (in == NULL)
+ return (-1);
+
base = in->cur - in->base;
- if (base < 0) return(-1);
+ if (base < 0)
+ return (-1);
+
if (ctxt->checkIndex > base)
base = ctxt->checkIndex;
+
if (in->buf == NULL) {
- buf = in->base;
- len = in->length;
+ buf = in->base;
+ len = in->length;
} else {
- buf = in->buf->buffer->content;
- len = in->buf->buffer->use;
+ buf = xmlBufContent(in->buf->buffer);
+ len = xmlBufUse(in->buf->buffer);
}
+
/* take into account the sequence length */
- if (third) len -= 2;
- else if (next) len --;
- for (;base < len;base++) {
- if (!incomment && (base + 4 < len) && !iscomment) {
- if ((buf[base] == '<') && (buf[base + 1] == '!') &&
- (buf[base + 2] == '-') && (buf[base + 3] == '-')) {
- incomment = 1;
- /* do not increment past <! - some people use <!--> */
- base += 2;
- }
- }
- if (incomment) {
- if (base + 3 > len)
- return(-1);
- if ((buf[base] == '-') && (buf[base + 1] == '-') &&
- (buf[base + 2] == '>')) {
- incomment = 0;
- base += 2;
- }
- continue;
- }
+ if (third)
+ len -= 2;
+ else if (next)
+ len--;
+ for (; base < len; base++) {
+ if ((!incomment) && (base + 4 < len) && (!iscomment)) {
+ if ((buf[base] == '<') && (buf[base + 1] == '!') &&
+ (buf[base + 2] == '-') && (buf[base + 3] == '-')) {
+ incomment = 1;
+ /* do not increment past <! - some people use <!--> */
+ base += 2;
+ }
+ }
+ if (ignoreattrval) {
+ if (buf[base] == '"' || buf[base] == '\'') {
+ if (invalue) {
+ if (buf[base] == valdellim) {
+ invalue = 0;
+ continue;
+ }
+ } else {
+ valdellim = buf[base];
+ invalue = 1;
+ continue;
+ }
+ } else if (invalue) {
+ continue;
+ }
+ }
+ if (incomment) {
+ if (base + 3 > len)
+ return (-1);
+ if ((buf[base] == '-') && (buf[base + 1] == '-') &&
+ (buf[base + 2] == '>')) {
+ incomment = 0;
+ base += 2;
+ }
+ continue;
+ }
if (buf[base] == first) {
- if (third != 0) {
- if ((buf[base + 1] != next) ||
- (buf[base + 2] != third)) continue;
- } else if (next != 0) {
- if (buf[base + 1] != next) continue;
- }
- ctxt->checkIndex = 0;
+ if (third != 0) {
+ if ((buf[base + 1] != next) || (buf[base + 2] != third))
+ continue;
+ } else if (next != 0) {
+ if (buf[base + 1] != next)
+ continue;
+ }
+ ctxt->checkIndex = 0;
#ifdef DEBUG_PUSH
- if (next == 0)
- xmlGenericError(xmlGenericErrorContext,
- "HPP: lookup '%c' found at %d\n",
- first, base);
- else if (third == 0)
- xmlGenericError(xmlGenericErrorContext,
- "HPP: lookup '%c%c' found at %d\n",
- first, next, base);
- else
- xmlGenericError(xmlGenericErrorContext,
- "HPP: lookup '%c%c%c' found at %d\n",
- first, next, third, base);
+ if (next == 0)
+ xmlGenericError(xmlGenericErrorContext,
+ "HPP: lookup '%c' found at %d\n",
+ first, base);
+ else if (third == 0)
+ xmlGenericError(xmlGenericErrorContext,
+ "HPP: lookup '%c%c' found at %d\n",
+ first, next, base);
+ else
+ xmlGenericError(xmlGenericErrorContext,
+ "HPP: lookup '%c%c%c' found at %d\n",
+ first, next, third, base);
#endif
- return(base - (in->cur - in->base));
- }
+ return (base - (in->cur - in->base));
+ }
}
- ctxt->checkIndex = base;
+ if ((!incomment) && (!invalue))
+ ctxt->checkIndex = base;
#ifdef DEBUG_PUSH
if (next == 0)
- xmlGenericError(xmlGenericErrorContext,
- "HPP: lookup '%c' failed\n", first);
+ xmlGenericError(xmlGenericErrorContext,
+ "HPP: lookup '%c' failed\n", first);
else if (third == 0)
- xmlGenericError(xmlGenericErrorContext,
- "HPP: lookup '%c%c' failed\n", first, next);
- else
- xmlGenericError(xmlGenericErrorContext,
- "HPP: lookup '%c%c%c' failed\n", first, next, third);
+ xmlGenericError(xmlGenericErrorContext,
+ "HPP: lookup '%c%c' failed\n", first, next);
+ else
+ xmlGenericError(xmlGenericErrorContext,
+ "HPP: lookup '%c%c%c' failed\n", first, next,
+ third);
#endif
- return(-1);
+ return (-1);
+}
+
+/**
+ * htmlParseLookupChars:
+ * @ctxt: an HTML parser context
+ * @stop: Array of chars, which stop the lookup.
+ * @stopLen: Length of stop-Array
+ *
+ * Try to find if any char of the stop-Array is available in the input
+ * stream.
+ * This function has a side effect of (possibly) incrementing ctxt->checkIndex
+ * to avoid rescanning sequences of bytes, it DOES change the state of the
+ * parser, do not use liberally.
+ *
+ * Returns the index to the current parsing point if a stopChar
+ * is available, -1 otherwise.
+ */
+static int
+htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
+ int stopLen)
+{
+ int base, len;
+ htmlParserInputPtr in;
+ const xmlChar *buf;
+ int incomment = 0;
+ int i;
+
+ in = ctxt->input;
+ if (in == NULL)
+ return (-1);
+
+ base = in->cur - in->base;
+ if (base < 0)
+ return (-1);
+
+ if (ctxt->checkIndex > base)
+ base = ctxt->checkIndex;
+
+ if (in->buf == NULL) {
+ buf = in->base;
+ len = in->length;
+ } else {
+ buf = xmlBufContent(in->buf->buffer);
+ len = xmlBufUse(in->buf->buffer);
+ }
+
+ for (; base < len; base++) {
+ if (!incomment && (base + 4 < len)) {
+ if ((buf[base] == '<') && (buf[base + 1] == '!') &&
+ (buf[base + 2] == '-') && (buf[base + 3] == '-')) {
+ incomment = 1;
+ /* do not increment past <! - some people use <!--> */
+ base += 2;
+ }
+ }
+ if (incomment) {
+ if (base + 3 > len)
+ return (-1);
+ if ((buf[base] == '-') && (buf[base + 1] == '-') &&
+ (buf[base + 2] == '>')) {
+ incomment = 0;
+ base += 2;
+ }
+ continue;
+ }
+ for (i = 0; i < stopLen; ++i) {
+ if (buf[base] == stop[i]) {
+ ctxt->checkIndex = 0;
+ return (base - (in->cur - in->base));
+ }
+ }
+ }
+ ctxt->checkIndex = base;
+ return (-1);
}
/**
@@ -4517,6 +5280,8 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
int avail = 0;
xmlChar cur, next;
+ htmlParserNodeInfo node_info;
+
#ifdef DEBUG_PUSH
switch (ctxt->instate) {
case XML_PARSER_EOF:
@@ -4577,10 +5342,10 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if (in->buf == NULL)
avail = in->length - (in->cur - in->base);
else
- avail = in->buf->buffer->use - (in->cur - in->base);
+ avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
if ((avail == 0) && (terminate)) {
htmlAutoCloseOnEnd(ctxt);
- if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
+ if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
/*
* SAX: end of the document processing.
*/
@@ -4613,7 +5378,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if (in->buf == NULL)
avail = in->length - (in->cur - in->base);
else
- avail = in->buf->buffer->use - (in->cur - in->base);
+ avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
}
if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
ctxt->sax->setDocumentLocator(ctxt->userData,
@@ -4630,7 +5395,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
(UPP(6) == 'Y') && (UPP(7) == 'P') &&
(UPP(8) == 'E')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4655,15 +5420,28 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if (in->buf == NULL)
avail = in->length - (in->cur - in->base);
else
- avail = in->buf->buffer->use - (in->cur - in->base);
- if (avail < 2)
+ avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
+ /*
+ * no chars in buffer
+ */
+ if (avail < 1)
goto done;
+ /*
+ * not enouth chars in buffer
+ */
+ if (avail < 2) {
+ if (!terminate)
+ goto done;
+ else
+ next = ' ';
+ } else {
+ next = in->cur[1];
+ }
cur = in->cur[0];
- next = in->cur[1];
if ((cur == '<') && (next == '!') &&
(in->cur[2] == '-') && (in->cur[3] == '-')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '-', '-', '>', 1) < 0))
+ (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4673,7 +5451,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->instate = XML_PARSER_MISC;
} else if ((cur == '<') && (next == '?')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4687,7 +5465,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
(UPP(6) == 'Y') && (UPP(7) == 'P') &&
(UPP(8) == 'E')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4715,15 +5493,15 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if (in->buf == NULL)
avail = in->length - (in->cur - in->base);
else
- avail = in->buf->buffer->use - (in->cur - in->base);
- if (avail < 2)
+ avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
+ if (avail < 2)
goto done;
cur = in->cur[0];
next = in->cur[1];
if ((cur == '<') && (next == '!') &&
(in->cur[2] == '-') && (in->cur[3] == '-')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '-', '-', '>', 1) < 0))
+ (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4733,7 +5511,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->instate = XML_PARSER_PROLOG;
} else if ((cur == '<') && (next == '?')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4756,7 +5534,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if (in->buf == NULL)
avail = in->length - (in->cur - in->base);
else
- avail = in->buf->buffer->use - (in->cur - in->base);
+ avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
if (avail < 1)
goto done;
cur = in->cur[0];
@@ -4770,7 +5548,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if ((cur == '<') && (next == '!') &&
(in->cur[2] == '-') && (in->cur[3] == '-')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '-', '-', '>', 1) < 0))
+ (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4780,7 +5558,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->instate = XML_PARSER_EPILOG;
} else if ((cur == '<') && (next == '?')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4809,8 +5587,22 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
int failed;
const htmlElemDesc * info;
- if (avail < 2)
+ /*
+ * no chars in buffer
+ */
+ if (avail < 1)
goto done;
+ /*
+ * not enouth chars in buffer
+ */
+ if (avail < 2) {
+ if (!terminate)
+ goto done;
+ else
+ next = ' ';
+ } else {
+ next = in->cur[1];
+ }
cur = in->cur[0];
if (cur != '<') {
ctxt->instate = XML_PARSER_CONTENT;
@@ -4820,7 +5612,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
#endif
break;
}
- if (in->cur[1] == '/') {
+ if (next == '/') {
ctxt->instate = XML_PARSER_END_TAG;
ctxt->checkIndex = 0;
#ifdef DEBUG_PUSH
@@ -4830,12 +5622,20 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
break;
}
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
+ /* Capture start position */
+ if (ctxt->record_info) {
+ node_info.begin_pos = ctxt->input->consumed +
+ (CUR_PTR - ctxt->input->base);
+ node_info.begin_line = ctxt->input->line;
+ }
+
+
failed = htmlParseStartTag(ctxt);
name = ctxt->name;
- if (failed ||
+ if ((failed == -1) ||
(name == NULL)) {
if (CUR == '>')
NEXT;
@@ -4877,10 +5677,13 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
/*
* end of parsing of this node.
*/
- if (xmlStrEqual(name, ctxt->name)) {
+ if (xmlStrEqual(name, ctxt->name)) {
nodePop(ctxt);
htmlnamePop(ctxt);
- }
+ }
+
+ if (ctxt->record_info)
+ htmlNodeInfoPush(ctxt, &node_info);
ctxt->instate = XML_PARSER_CONTENT;
#ifdef DEBUG_PUSH
@@ -4898,6 +5701,10 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->sax->endElement(ctxt->userData, name);
htmlnamePop(ctxt);
}
+
+ if (ctxt->record_info)
+ htmlNodeInfoPush(ctxt, &node_info);
+
ctxt->instate = XML_PARSER_CONTENT;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -4925,14 +5732,20 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if ((cur != '<') && (cur != '&')) {
if (ctxt->sax != NULL) {
if (IS_BLANK_CH(cur)) {
- if (ctxt->sax->ignorableWhitespace != NULL)
- ctxt->sax->ignorableWhitespace(
- ctxt->userData, &cur, 1);
+ if (ctxt->keepBlanks) {
+ if (ctxt->sax->characters != NULL)
+ ctxt->sax->characters(
+ ctxt->userData, &in->cur[0], 1);
+ } else {
+ if (ctxt->sax->ignorableWhitespace != NULL)
+ ctxt->sax->ignorableWhitespace(
+ ctxt->userData, &in->cur[0], 1);
+ }
} else {
htmlCheckParagraph(ctxt);
if (ctxt->sax->characters != NULL)
ctxt->sax->characters(
- ctxt->userData, &cur, 1);
+ ctxt->userData, &in->cur[0], 1);
}
}
ctxt->token = 0;
@@ -4955,7 +5768,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
int idx;
xmlChar val;
- idx = htmlParseLookupSequence(ctxt, '<', '/', 0, 0);
+ idx = htmlParseLookupSequence(ctxt, '<', '/', 0, 0, 0);
if (idx < 0)
goto done;
val = in->cur[idx + 2];
@@ -4982,7 +5795,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
(UPP(6) == 'Y') && (UPP(7) == 'P') &&
(UPP(8) == 'E')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
"Misplaced DOCTYPE declaration\n",
@@ -4992,7 +5805,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
(in->cur[2] == '-') && (in->cur[3] == '-')) {
if ((!terminate) &&
(htmlParseLookupSequence(
- ctxt, '-', '-', '>', 1) < 0))
+ ctxt, '-', '-', '>', 1, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5002,7 +5815,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
ctxt->instate = XML_PARSER_CONTENT;
} else if ((cur == '<') && (next == '?')) {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5030,7 +5843,8 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
break;
} else if (cur == '&') {
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, ';', 0, 0, 0) < 0))
+ (htmlParseLookupChars(ctxt,
+ BAD_CAST "; >/", 4) < 0))
goto done;
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext,
@@ -5046,7 +5860,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
* data detection.
*/
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '<', 0, 0, 0) < 0))
+ (htmlParseLookupChars(ctxt, BAD_CAST "<&", 2) < 0))
goto done;
ctxt->checkIndex = 0;
#ifdef DEBUG_PUSH
@@ -5072,7 +5886,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
if (avail < 2)
goto done;
if ((!terminate) &&
- (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
+ (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
goto done;
htmlParseEndTag(ctxt);
if (ctxt->nameNr == 0) {
@@ -5199,10 +6013,10 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
}
}
-done:
+done:
if ((avail == 0) && (terminate)) {
htmlAutoCloseOnEnd(ctxt);
- if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
+ if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
/*
* SAX: end of the document processing.
*/
@@ -5211,14 +6025,14 @@ done:
ctxt->sax->endDocument(ctxt->userData);
}
}
- if ((ctxt->myDoc != NULL) &&
+ if ((!(ctxt->options & HTML_PARSE_NODEFDTD)) && (ctxt->myDoc != NULL) &&
((terminate) || (ctxt->instate == XML_PARSER_EOF) ||
(ctxt->instate == XML_PARSER_EPILOG))) {
xmlDtdPtr dtd;
dtd = xmlGetIntSubset(ctxt->myDoc);
if (dtd == NULL)
- ctxt->myDoc->intSubset =
- xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
+ ctxt->myDoc->intSubset =
+ xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
}
@@ -5249,20 +6063,17 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
}
if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
(ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) {
- int base = ctxt->input->base - ctxt->input->buf->buffer->content;
- int cur = ctxt->input->cur - ctxt->input->base;
+ size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input);
+ size_t cur = ctxt->input->cur - ctxt->input->base;
int res;
-
- res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
+
+ res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
if (res < 0) {
ctxt->errNo = XML_PARSER_EOF;
ctxt->disableSAX = 1;
return (XML_PARSER_EOF);
}
- ctxt->input->base = ctxt->input->buf->buffer->content + base;
- ctxt->input->cur = ctxt->input->base + cur;
- ctxt->input->end =
- &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use];
+ xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
#endif
@@ -5277,13 +6088,16 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
if ((in->encoder != NULL) && (in->buffer != NULL) &&
(in->raw != NULL)) {
int nbchars;
-
- nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
+ size_t base = xmlBufGetInputBase(in->buffer, ctxt->input);
+ size_t current = ctxt->input->cur - ctxt->input->base;
+
+ nbchars = xmlCharEncInput(in, terminate);
if (nbchars < 0) {
htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
"encoder error\n", NULL, NULL);
return(XML_ERR_INVALID_ENCODING);
}
+ xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
}
}
}
@@ -5294,14 +6108,14 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
(ctxt->instate != XML_PARSER_MISC)) {
ctxt->errNo = XML_ERR_DOCUMENT_END;
ctxt->wellFormed = 0;
- }
+ }
if (ctxt->instate != XML_PARSER_EOF) {
if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
ctxt->sax->endDocument(ctxt->userData);
}
ctxt->instate = XML_PARSER_EOF;
}
- return((xmlParserErrors) ctxt->errNo);
+ return((xmlParserErrors) ctxt->errNo);
}
/************************************************************************
@@ -5326,7 +6140,7 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
* Returns the new parser context or NULL
*/
htmlParserCtxtPtr
-htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
+htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
const char *chunk, int size, const char *filename,
xmlCharEncoding enc) {
htmlParserCtxtPtr ctxt;
@@ -5357,7 +6171,7 @@ htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
memcpy(ctxt->sax, sax, sizeof(htmlSAXHandler));
if (user_data != NULL)
ctxt->userData = user_data;
- }
+ }
if (filename == NULL) {
ctxt->directory = NULL;
} else {
@@ -5377,24 +6191,18 @@ htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
inputStream->filename = (char *)
xmlCanonicPath((const xmlChar *) filename);
inputStream->buf = buf;
- inputStream->base = inputStream->buf->buffer->content;
- inputStream->cur = inputStream->buf->buffer->content;
- inputStream->end =
- &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
+ xmlBufResetInput(buf->buffer, inputStream);
inputPush(ctxt, inputStream);
if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
- (ctxt->input->buf != NULL)) {
- int base = ctxt->input->base - ctxt->input->buf->buffer->content;
- int cur = ctxt->input->cur - ctxt->input->base;
+ (ctxt->input->buf != NULL)) {
+ size_t base = xmlBufGetInputBase(ctxt->input->buf->buffer, ctxt->input);
+ size_t cur = ctxt->input->cur - ctxt->input->base;
- xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
+ xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
- ctxt->input->base = ctxt->input->buf->buffer->content + base;
- ctxt->input->cur = ctxt->input->base + cur;
- ctxt->input->end =
- &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use];
+ xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
#ifdef DEBUG_PUSH
xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
#endif
@@ -5410,12 +6218,12 @@ htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
* @cur: a pointer to an array of xmlChar
* @encoding: a free form C string describing the HTML document encoding, or NULL
* @sax: the SAX handler block
- * @userData: if using SAX, this pointer will be provided on callbacks.
+ * @userData: if using SAX, this pointer will be provided on callbacks.
*
* Parse an HTML in-memory document. If sax is not NULL, use the SAX callbacks
* to handle parse events. If sax is NULL, fallback to the default DOM
* behavior and return a tree.
- *
+ *
* Returns the resulting document tree unless SAX is NULL or the document is
* not well formed.
*/
@@ -5432,7 +6240,7 @@ htmlSAXParseDoc(xmlChar *cur, const char *encoding, htmlSAXHandlerPtr sax, void
ctxt = htmlCreateDocParserCtxt(cur, encoding);
if (ctxt == NULL) return(NULL);
- if (sax != NULL) {
+ if (sax != NULL) {
if (ctxt->sax != NULL) xmlFree (ctxt->sax);
ctxt->sax = sax;
ctxt->userData = userData;
@@ -5445,7 +6253,7 @@ htmlSAXParseDoc(xmlChar *cur, const char *encoding, htmlSAXHandlerPtr sax, void
ctxt->userData = NULL;
}
htmlFreeParserCtxt(ctxt);
-
+
return(ret);
}
@@ -5455,7 +6263,7 @@ htmlSAXParseDoc(xmlChar *cur, const char *encoding, htmlSAXHandlerPtr sax, void
* @encoding: a free form C string describing the HTML document encoding, or NULL
*
* parse an HTML in-memory document and build a tree.
- *
+ *
* Returns the resulting document tree
*/
@@ -5470,7 +6278,7 @@ htmlParseDoc(xmlChar *cur, const char *encoding) {
* @filename: the filename
* @encoding: a free form C string describing the HTML document encoding, or NULL
*
- * Create a parser context for a file content.
+ * Create a parser context for a file content.
* Automatic support for ZLIB/Compress compressed document is provided
* by default if found at compile-time.
*
@@ -5502,7 +6310,7 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding)
xmlFreeParserCtxt(ctxt);
return(NULL);
}
-
+
inputStream = xmlLoadExternalEntity(canonicFilename, NULL, ctxt);
xmlFree(canonicFilename);
if (inputStream == NULL) {
@@ -5514,15 +6322,19 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding)
/* set encoding */
if (encoding) {
- content = xmlMallocAtomic (xmlStrlen(content_line) + strlen(encoding) + 1);
- if (content) {
- strcpy ((char *)content, (char *)content_line);
- strcat ((char *)content, (char *)encoding);
- htmlCheckEncoding (ctxt, content);
- xmlFree (content);
+ size_t l = strlen(encoding);
+
+ if (l < 1000) {
+ content = xmlMallocAtomic (xmlStrlen(content_line) + l + 1);
+ if (content) {
+ strcpy ((char *)content, (char *)content_line);
+ strcat ((char *)content, (char *)encoding);
+ htmlCheckEncoding (ctxt, content);
+ xmlFree (content);
+ }
}
}
-
+
return(ctxt);
}
@@ -5531,7 +6343,7 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding)
* @filename: the filename
* @encoding: a free form C string describing the HTML document encoding, or NULL
* @sax: the SAX handler block
- * @userData: if using SAX, this pointer will be provided on callbacks.
+ * @userData: if using SAX, this pointer will be provided on callbacks.
*
* parse an HTML file and build a tree. Automatic support for ZLIB/Compress
* compressed document is provided by default if found at compile-time.
@@ -5543,7 +6355,7 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding)
*/
htmlDocPtr
-htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr sax,
+htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr sax,
void *userData) {
htmlDocPtr ret;
htmlParserCtxtPtr ctxt;
@@ -5567,7 +6379,7 @@ htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr s
ctxt->userData = NULL;
}
htmlFreeParserCtxt(ctxt);
-
+
return(ret);
}
@@ -5589,7 +6401,7 @@ htmlParseFile(const char *filename, const char *encoding) {
/**
* htmlHandleOmittedElem:
- * @val: int 0 or 1
+ * @val: int 0 or 1
*
* Set and return the previous value for handling HTML omitted tags.
*
@@ -5729,7 +6541,7 @@ htmlNodeStatus(const htmlNodePtr node, int legacy) {
* current scope
*/
#define DICT_FREE(str) \
- if ((str) && ((!dict) || \
+ if ((str) && ((!dict) || \
(xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
xmlFree((char *)(str));
@@ -5744,7 +6556,7 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt)
{
xmlParserInputPtr input;
xmlDictPtr dict;
-
+
if (ctxt == NULL)
return;
@@ -5796,6 +6608,7 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt)
ctxt->wellFormed = 1;
ctxt->nsWellFormed = 1;
+ ctxt->disableSAX = 0;
ctxt->valid = 1;
ctxt->vctxt.userData = ctxt;
ctxt->vctxt.error = xmlParserValidityError;
@@ -5806,7 +6619,7 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt)
ctxt->inSubset = 0;
ctxt->errNo = XML_ERR_OK;
ctxt->depth = 0;
- ctxt->charset = XML_CHAR_ENCODING_UTF8;
+ ctxt->charset = XML_CHAR_ENCODING_NONE;
ctxt->catalogs = NULL;
xmlInitNodeInfoSeq(&ctxt->node_seq);
@@ -5871,6 +6684,22 @@ htmlCtxtUseOptions(htmlParserCtxtPtr ctxt, int options)
ctxt->options |= HTML_PARSE_COMPACT;
options -= HTML_PARSE_COMPACT;
}
+ if (options & XML_PARSE_HUGE) {
+ ctxt->options |= XML_PARSE_HUGE;
+ options -= XML_PARSE_HUGE;
+ }
+ if (options & HTML_PARSE_NODEFDTD) {
+ ctxt->options |= HTML_PARSE_NODEFDTD;
+ options -= HTML_PARSE_NODEFDTD;
+ }
+ if (options & HTML_PARSE_IGNORE_ENC) {
+ ctxt->options |= HTML_PARSE_IGNORE_ENC;
+ options -= HTML_PARSE_IGNORE_ENC;
+ }
+ if (options & HTML_PARSE_NOIMPLIED) {
+ ctxt->options |= HTML_PARSE_NOIMPLIED;
+ options -= HTML_PARSE_NOIMPLIED;
+ }
ctxt->dictNames = 0;
return (options);
}
@@ -5884,7 +6713,7 @@ htmlCtxtUseOptions(htmlParserCtxtPtr ctxt, int options)
* @reuse: keep the context for reuse
*
* Common front-end for the htmlRead functions
- *
+ *
* Returns the resulting document tree or NULL
*/
static htmlDocPtr
@@ -5892,15 +6721,19 @@ htmlDoRead(htmlParserCtxtPtr ctxt, const char *URL, const char *encoding,
int options, int reuse)
{
htmlDocPtr ret;
-
+
htmlCtxtUseOptions(ctxt, options);
ctxt->html = 1;
if (encoding != NULL) {
xmlCharEncodingHandlerPtr hdlr;
hdlr = xmlFindCharEncodingHandler(encoding);
- if (hdlr != NULL)
+ if (hdlr != NULL) {
xmlSwitchToEncoding(ctxt, hdlr);
+ if (ctxt->input->encoding != NULL)
+ xmlFree((xmlChar *) ctxt->input->encoding);
+ ctxt->input->encoding = xmlStrdup((xmlChar *)encoding);
+ }
}
if ((URL != NULL) && (ctxt->input != NULL) &&
(ctxt->input->filename == NULL))
@@ -5926,7 +6759,7 @@ htmlDoRead(htmlParserCtxtPtr ctxt, const char *URL, const char *encoding,
* @options: a combination of htmlParserOption(s)
*
* parse an XML in-memory document and build a tree.
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -5951,7 +6784,7 @@ htmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int opti
* @options: a combination of htmlParserOption(s)
*
* parse an XML file from the filesystem or the network.
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -5975,7 +6808,7 @@ htmlReadFile(const char *filename, const char *encoding, int options)
* @options: a combination of htmlParserOption(s)
*
* parse an XML in-memory document and build a tree.
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -6001,7 +6834,7 @@ htmlReadMemory(const char *buffer, int size, const char *URL, const char *encodi
* @options: a combination of htmlParserOption(s)
*
* parse an XML from a file descriptor and build a tree.
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -6013,6 +6846,7 @@ htmlReadFd(int fd, const char *URL, const char *encoding, int options)
if (fd < 0)
return (NULL);
+ xmlInitParser();
xmlInitParser();
input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
@@ -6043,7 +6877,7 @@ htmlReadFd(int fd, const char *URL, const char *encoding, int options)
* @options: a combination of htmlParserOption(s)
*
* parse an HTML document from I/O functions and source and build a tree.
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -6060,8 +6894,11 @@ htmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
XML_CHAR_ENCODING_NONE);
- if (input == NULL)
+ if (input == NULL) {
+ if (ioclose != NULL)
+ ioclose(ioctx);
return (NULL);
+ }
ctxt = htmlNewParserCtxt();
if (ctxt == NULL) {
xmlFreeParserInputBuffer(input);
@@ -6087,7 +6924,7 @@ htmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
*
* parse an XML in-memory document and build a tree.
* This reuses the existing @ctxt parser context
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -6100,6 +6937,7 @@ htmlCtxtReadDoc(htmlParserCtxtPtr ctxt, const xmlChar * cur,
return (NULL);
if (ctxt == NULL)
return (NULL);
+ xmlInitParser();
htmlCtxtReset(ctxt);
@@ -6120,7 +6958,7 @@ htmlCtxtReadDoc(htmlParserCtxtPtr ctxt, const xmlChar * cur,
*
* parse an XML file from the filesystem or the network.
* This reuses the existing @ctxt parser context
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -6133,6 +6971,7 @@ htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename,
return (NULL);
if (ctxt == NULL)
return (NULL);
+ xmlInitParser();
htmlCtxtReset(ctxt);
@@ -6155,7 +6994,7 @@ htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename,
*
* parse an XML in-memory document and build a tree.
* This reuses the existing @ctxt parser context
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -6169,6 +7008,7 @@ htmlCtxtReadMemory(htmlParserCtxtPtr ctxt, const char *buffer, int size,
return (NULL);
if (buffer == NULL)
return (NULL);
+ xmlInitParser();
htmlCtxtReset(ctxt);
@@ -6197,7 +7037,7 @@ htmlCtxtReadMemory(htmlParserCtxtPtr ctxt, const char *buffer, int size,
*
* parse an XML from a file descriptor and build a tree.
* This reuses the existing @ctxt parser context
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -6211,6 +7051,7 @@ htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd,
return (NULL);
if (ctxt == NULL)
return (NULL);
+ xmlInitParser();
htmlCtxtReset(ctxt);
@@ -6239,7 +7080,7 @@ htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd,
*
* parse an HTML document from I/O functions and source and build a tree.
* This reuses the existing @ctxt parser context
- *
+ *
* Returns the resulting document tree
*/
htmlDocPtr
@@ -6255,13 +7096,17 @@ htmlCtxtReadIO(htmlParserCtxtPtr ctxt, xmlInputReadCallback ioread,
return (NULL);
if (ctxt == NULL)
return (NULL);
+ xmlInitParser();
htmlCtxtReset(ctxt);
input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
XML_CHAR_ENCODING_NONE);
- if (input == NULL)
+ if (input == NULL) {
+ if (ioclose != NULL)
+ ioclose(ioctx);
return (NULL);
+ }
stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
if (stream == NULL) {
xmlFreeParserInputBuffer(input);