Imported Upstream version 0.19.7
[platform/upstream/gettext.git] / gnulib-local / lib / libxml / HTMLparser.c
index 5e23ad7..b729197 100644 (file)
@@ -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,16 +4261,20 @@ htmlParseElement(htmlParserCtxtPtr ctxt) {
                     "htmlParseElement: context error\n", NULL, NULL);
        return;
     }
-    /* Capture start position */
-    if (ctxt->record_info) {
-        node_info.begin_pos = ctxt->input->consumed +
+
+    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 || (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);