Roll libxml to 0b3c64d9f2f3e9ce1a98d8f19ee7a763c87e27d5

This patch rolls libxml from e4fb36841800038c289997432ca547c9bfef9db1 to
0b3c64d9f2f3e9ce1a98d8f19ee7a763c87e27d5

add-missing-ifdef-in-xml-reader.patch was merged upstream.

add-fuzz-target.patch was added in order to prevent autoreconf failure
on mac.

config.h was generated in a different spot than the script looks for on
my windows machine, so I changed the path for it.

Bug: 934413
Change-Id: I8ddbdd9b36210942730b6b3b78051cff0c17d125
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2444429
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816473}
GitOrigin-RevId: be448ceae9ff5126b82c3e438a0f77ef891ba133
diff --git a/README.chromium b/README.chromium
index 638320e..f84cc64 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,6 +1,6 @@
 Name: libxml
 URL: http://xmlsoft.org
-Version: e4fb36841800038c289997432ca547c9bfef9db1
+Version: 0b3c64d9f2f3e9ce1a98d8f19ee7a763c87e27d5
 CPEPrefix: cpe:/a:xmlsoft:libxml2:2.9.9
 License: MIT
 License File: src/Copyright
@@ -22,8 +22,8 @@
 - chromium-issue-708434.patch: Guard against input counter overflow.
 - revert-non-recursive-xml-parsing.patch: Making parts of the XML parser
     non-recursive broke a few web platform tests.
-- add-missing-ifdef-in-xml-reader.patch: Bug fix forgot to guard functionality
-    with appropriate #ifdef.
+- add-fuzz-target.patch: Prevents autoreconf from failing on mac due to a
+    missing makefile for fuzz.
 - Add helper classes in the chromium/ subdirectory.
 - Delete various unused files, see chromium/roll.py
 
diff --git a/chromium/add-fuzz-target.patch b/chromium/add-fuzz-target.patch
new file mode 100644
index 0000000..420d5c7
--- /dev/null
+++ b/chromium/add-fuzz-target.patch
@@ -0,0 +1,13 @@
+diff --git a/Makefile.am b/Makefile.am
+index 76a834ef..4ef0eb92 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -4,7 +4,7 @@ ACLOCAL_AMFLAGS = -I m4
+ 
+ SUBDIRS = include . doc example fuzz xstc $(PYTHON_SUBDIR)
+ 
+-DIST_SUBDIRS = include . doc example python xstc
++DIST_SUBDIRS = include . doc example python xstc fuzz
+ 
+ AM_CPPFLAGS = -I$(top_builddir)/include -I$(srcdir)/include
+ 
diff --git a/chromium/add-missing-ifdef-in-xml-reader.patch b/chromium/add-missing-ifdef-in-xml-reader.patch
deleted file mode 100644
index 17cd15a..0000000
--- a/chromium/add-missing-ifdef-in-xml-reader.patch
+++ /dev/null
@@ -1,13 +0,0 @@
---- a/xmlreader.c
-+++ b/xmlreader.c
-@@ -2262,8 +2262,10 @@ xmlFreeTextReader(xmlTextReaderPtr reader) {
- 	    reader->dict = NULL;
- 	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
- 	    (reader->ctxt->vctxt.vstateMax > 0)){
-+#ifdef LIBXML_REGEXP_ENABLED
-             while (reader->ctxt->vctxt.vstateNr > 0)
-                 xmlValidatePopElement(&reader->ctxt->vctxt, NULL, NULL, NULL);
-+#endif /* LIBXML_REGEXP_ENABLED */
- 	    xmlFree(reader->ctxt->vctxt.vstateTab);
- 	    reader->ctxt->vctxt.vstateTab = NULL;
- 	    reader->ctxt->vctxt.vstateMax = 0;
diff --git a/chromium/roll.py b/chromium/roll.py
index a75c3bb..1c5f58a 100755
--- a/chromium/roll.py
+++ b/chromium/roll.py
@@ -34,12 +34,6 @@
 # 3. On Mac, install these packages with brew:
 #      autoconf automake libtool pkgconfig icu4c
 #
-#    Important! Before running roll.py, set these environmental variables so the
-#    configure script can find ICU:
-#      export LDFLAGS="-L/path/to/homebrew/opt/icu4c/lib"
-#      export CPPFLAGS="-I/path/to/homebrew/opt/icu4c/include"
-#      export PKG_CONFIG_PATH="/path/to/homebrew/opt/icu4c/lib/pkgconfig"
-#
 # Procedure:
 #
 # Warning: This process is destructive. Run it on a clean branch.
@@ -66,7 +60,7 @@
 #
 # 3. On Mac, in the Chromium src directory:
 #    a. git cl patch <Gerrit Issue ID>
-#    b. third_party/libxml/chromium/roll.py --mac
+#    b. third_party/libxml/chromium/roll.py --mac --icu4c_path=~/homebrew/opt/icu4c
 #    c. Make and commit any final changes to README.chromium, BUILD.gn, etc.
 #    d. git cl upload
 #    e. Complete the review as usual
@@ -78,8 +72,8 @@
     'chromium-issue-628581.patch',
     'libxml2-2.9.4-security-xpath-nodetab-uaf.patch',
     'chromium-issue-708434.patch',
-    # TODO(dcheng): Merge this back upstream.
-    'add-missing-ifdef-in-xml-reader.patch',
+    # TODO(jarhar): Merge this back upstream.
+    'add-fuzz-target.patch',
 ]
 
 
@@ -405,7 +399,7 @@
                 XML_WIN32_CONFIGURE_OPTIONS)
 
             # Add and commit the result.
-            shutil.move('VC10/config.h', '../../win32/config.h')
+            shutil.move('../config.h', '../../win32/config.h')
             git('add', '../../win32/config.h')
             shutil.move('../include/libxml/xmlversion.h',
                         '../../win32/include/libxml/xmlversion.h')
@@ -415,7 +409,12 @@
     print('Now push to Mac and run steps there.')
 
 
-def roll_libxml_mac(src_path):
+def roll_libxml_mac(src_path, icu4c_path):
+    icu4c_path = os.path.abspath(os.path.expanduser(icu4c_path))
+    os.environ["LDFLAGS"] = "-L" + os.path.join(icu4c_path, 'lib')
+    os.environ["CPPFLAGS"] = "-I" + os.path.join(icu4c_path, 'include')
+    os.environ["PKG_CONFIG_PATH"] = os.path.join(icu4c_path, 'lib/pkgconfig')
+
     full_path_to_third_party_libxml = os.path.join(
         src_path, THIRD_PARTY_LIBXML_SRC, '..')
 
@@ -459,6 +458,9 @@
         type=str,
         nargs='?',
         help='The path to the local clone of the libxml2 git repo.')
+    parser.add_argument(
+        '--icu4c_path',
+        help='The path to the homebrew installation of icu4c.')
     args = parser.parse_args()
 
     if args.linux:
@@ -471,7 +473,12 @@
     elif args.win32:
         roll_libxml_win32(src_dir)
     elif args.mac:
-        roll_libxml_mac(src_dir)
+        icu4c_path = args.icu4c_path
+        if not icu4c_path:
+            print('Specify the path to the homebrew installation of icu4c with --icu4c_path.')
+            print('  ex: roll.py --mac --icu4c_path=~/homebrew/opt/icu4c')
+            sys.exit(1)
+        roll_libxml_mac(src_dir, icu4c_path)
 
 
 if __name__ == '__main__':
diff --git a/linux/config.h b/linux/config.h
index e334240..b6ae433 100644
--- a/linux/config.h
+++ b/linux/config.h
@@ -1,6 +1,9 @@
 /* config.h.  Generated from config.h.in by configure.  */
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
+/* A form that will not confuse apibuild.py */
+#define ATTRIBUTE_DESTRUCTOR __attribute__((destructor))
+
 /* Type cast for the gethostbyname() argument */
 #define GETHOSTBYNAME_ARG_CAST /**/
 
@@ -10,6 +13,9 @@
 /* Define to 1 if you have the <arpa/nameser.h> header file. */
 #define HAVE_ARPA_NAMESER_H 1
 
+/* Define if __attribute__((destructor)) is accepted */
+#define HAVE_ATTRIBUTE_DESTRUCTOR 1
+
 /* Whether struct sockaddr::__ss_family exists */
 /* #undef HAVE_BROKEN_SS_FAMILY */
 
@@ -240,19 +246,19 @@
 #define PACKAGE_BUGREPORT ""
 
 /* Define to the full name of this package. */
-#define PACKAGE_NAME ""
+#define PACKAGE_NAME "libxml2"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING ""
+#define PACKAGE_STRING "libxml2 2.9.10"
 
 /* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME ""
+#define PACKAGE_TARNAME "libxml2"
 
 /* Define to the home page for this package. */
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION ""
+#define PACKAGE_VERSION "2.9.10"
 
 /* Type cast for the send() function 2nd arg */
 #define SEND_ARG2_CAST /**/
diff --git a/mac/config.h b/mac/config.h
index 16cd0ae..563202e 100644
--- a/mac/config.h
+++ b/mac/config.h
@@ -1,6 +1,9 @@
 /* config.h.  Generated from config.h.in by configure.  */
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
+/* A form that will not confuse apibuild.py */
+#define ATTRIBUTE_DESTRUCTOR __attribute__((destructor))
+
 /* Type cast for the gethostbyname() argument */
 #define GETHOSTBYNAME_ARG_CAST /**/
 
@@ -10,6 +13,9 @@
 /* Define to 1 if you have the <arpa/nameser.h> header file. */
 #define HAVE_ARPA_NAMESER_H 1
 
+/* Define if __attribute__((destructor)) is accepted */
+#define HAVE_ATTRIBUTE_DESTRUCTOR 1
+
 /* Whether struct sockaddr::__ss_family exists */
 /* #undef HAVE_BROKEN_SS_FAMILY */
 
@@ -240,19 +246,19 @@
 #define PACKAGE_BUGREPORT ""
 
 /* Define to the full name of this package. */
-#define PACKAGE_NAME ""
+#define PACKAGE_NAME "libxml2"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING ""
+#define PACKAGE_STRING "libxml2 2.9.10"
 
 /* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME ""
+#define PACKAGE_TARNAME "libxml2"
 
 /* Define to the home page for this package. */
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION ""
+#define PACKAGE_VERSION "2.9.10"
 
 /* Type cast for the send() function 2nd arg */
 #define SEND_ARG2_CAST /**/
diff --git a/src/COPYING b/src/COPYING
deleted file mode 100644
index d613185..0000000
--- a/src/COPYING
+++ /dev/null
@@ -1,23 +0,0 @@
-Except where otherwise noted in the source code (e.g. the files hash.c,
-list.c and the trio files, which are covered by a similar licence but
-with different Copyright notices) all the files are:
-
- Copyright (C) 1998-2012 Daniel Veillard.  All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is fur-
-nished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
-NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/src/HTMLparser.c b/src/HTMLparser.c
index 5dd62df..de624f8 100644
--- a/src/HTMLparser.c
+++ b/src/HTMLparser.c
@@ -296,7 +296,7 @@
 
 #define UPPER (toupper(*ctxt->input->cur))
 
-#define SKIP(val) ctxt->nbChars += (val),ctxt->input->cur += (val),ctxt->input->col+=(val)
+#define SKIP(val) ctxt->input->cur += (val),ctxt->input->col+=(val)
 
 #define NXT(val) ctxt->input->cur[(val)]
 
@@ -330,7 +330,7 @@
     if (*(ctxt->input->cur) == '\n') {					\
 	ctxt->input->line++; ctxt->input->col = 1;			\
     } else ctxt->input->col++;						\
-    ctxt->token = 0; ctxt->input->cur += l; ctxt->nbChars++;		\
+    ctxt->token = 0; ctxt->input->cur += l;				\
   } while (0)
 
 /************
@@ -414,6 +414,10 @@
 
 static int
 htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
+    const unsigned char *cur;
+    unsigned char c;
+    unsigned int val;
+
     if (ctxt->instate == XML_PARSER_EOF)
 	return(0);
 
@@ -421,99 +425,29 @@
 	*len = 0;
 	return(ctxt->token);
     }
-    if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
-	/*
-	 * We are supposed to handle UTF8, check it's valid
-	 * From rfc2044: encoding of the Unicode values on UTF-8:
-	 *
-	 * 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
-	 *
-	 * Check for the 0x110000 limit too
-	 */
-	const unsigned char *cur = ctxt->input->cur;
-	unsigned char c;
-	unsigned int val;
-
-	c = *cur;
-	if (c & 0x80) {
-	    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) {
-		    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) {
-			xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
-                        cur = ctxt->input->cur;
-                    }
-		    if (((c & 0xf8) != 0xf0) ||
-			((cur[3] & 0xc0) != 0x80))
-			goto encoding_error;
-		    /* 4-byte code */
-		    *len = 4;
-		    val = (cur[0] & 0x7) << 18;
-		    val |= (cur[1] & 0x3f) << 12;
-		    val |= (cur[2] & 0x3f) << 6;
-		    val |= cur[3] & 0x3f;
-		} else {
-		  /* 3-byte code */
-		    *len = 3;
-		    val = (cur[0] & 0xf) << 12;
-		    val |= (cur[1] & 0x3f) << 6;
-		    val |= cur[2] & 0x3f;
-		}
-	    } else {
-	      /* 2-byte code */
-		*len = 2;
-		val = (cur[0] & 0x1f) << 6;
-		val |= cur[1] & 0x3f;
-	    }
-	    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);
-	}
-    }
-    /*
-     * Assume it's a fixed length encoding (1) with
-     * a compatible encoding for the ASCII set, since
-     * XML constructs only use < 128 chars
-     */
-    *len = 1;
-    if ((int) *ctxt->input->cur < 0x80)
-	return((int) *ctxt->input->cur);
-
-    /*
-     * Humm this is bad, do an automatic flow conversion
-     */
-    {
+    if (ctxt->charset != XML_CHAR_ENCODING_UTF8) {
         xmlChar * guess;
         xmlCharEncodingHandlerPtr handler;
 
+        /*
+         * Assume it's a fixed length encoding (1) with
+         * a compatible encoding for the ASCII set, since
+         * HTML constructs only use < 128 chars
+         */
+        if ((int) *ctxt->input->cur < 0x80) {
+            *len = 1;
+            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);
+                return(' ');
+            }
+            return((int) *ctxt->input->cur);
+        }
+
+        /*
+         * Humm this is bad, do an automatic flow conversion
+         */
         guess = htmlFindEncoding(ctxt);
         if (guess == NULL) {
             xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
@@ -532,7 +466,86 @@
         ctxt->charset = XML_CHAR_ENCODING_UTF8;
     }
 
-    return(xmlCurrentChar(ctxt, len));
+    /*
+     * We are supposed to handle UTF8, check it's valid
+     * From rfc2044: encoding of the Unicode values on UTF-8:
+     *
+     * 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
+     *
+     * Check for the 0x110000 limit too
+     */
+    cur = ctxt->input->cur;
+    c = *cur;
+    if (c & 0x80) {
+        if ((c & 0x40) == 0)
+            goto encoding_error;
+        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) {
+                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) {
+                    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+                    cur = ctxt->input->cur;
+                }
+                if (((c & 0xf8) != 0xf0) ||
+                    ((cur[3] & 0xc0) != 0x80))
+                    goto encoding_error;
+                /* 4-byte code */
+                *len = 4;
+                val = (cur[0] & 0x7) << 18;
+                val |= (cur[1] & 0x3f) << 12;
+                val |= (cur[2] & 0x3f) << 6;
+                val |= cur[3] & 0x3f;
+                if (val < 0x10000)
+                    goto encoding_error;
+            } else {
+              /* 3-byte code */
+                *len = 3;
+                val = (cur[0] & 0xf) << 12;
+                val |= (cur[1] & 0x3f) << 6;
+                val |= cur[2] & 0x3f;
+                if (val < 0x800)
+                    goto encoding_error;
+            }
+        } else {
+          /* 2-byte code */
+            *len = 2;
+            val = (cur[0] & 0x1f) << 6;
+            val |= cur[1] & 0x3f;
+            if (val < 0x80)
+                goto encoding_error;
+        }
+        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);
+    }
 
 encoding_error:
     /*
@@ -584,7 +597,6 @@
 		ctxt->input->line++; ctxt->input->col = 1;
 	    } else ctxt->input->col++;
 	    ctxt->input->cur++;
-	    ctxt->nbChars++;
 	    if (*ctxt->input->cur == 0)
 		xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
 	}
@@ -2482,7 +2494,6 @@
 	    count = in - ctxt->input->cur;
 	    ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count);
 	    ctxt->input->cur = in;
-	    ctxt->nbChars += count;
 	    ctxt->input->col += count;
 	    return(ret);
 	}
@@ -2789,47 +2800,39 @@
 static xmlChar *
 htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) {
     size_t len = 0, startPosition = 0;
+    int err = 0;
+    int quote;
     xmlChar *ret = NULL;
 
-    if (CUR == '"') {
-        NEXT;
-
-        if (CUR_PTR < BASE_PTR)
-            return(ret);
-        startPosition = CUR_PTR - BASE_PTR;
-
-	while ((IS_CHAR_CH(CUR)) && (CUR != '"')) {
-	    NEXT;
-	    len++;
-	}
-	if (!IS_CHAR_CH(CUR)) {
-	    htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
-			 "Unfinished SystemLiteral\n", NULL, NULL);
-	} else {
-	    ret = xmlStrndup((BASE_PTR+startPosition), len);
-	    NEXT;
-        }
-    } else if (CUR == '\'') {
-        NEXT;
-
-        if (CUR_PTR < BASE_PTR)
-            return(ret);
-        startPosition = CUR_PTR - BASE_PTR;
-
-	while ((IS_CHAR_CH(CUR)) && (CUR != '\'')) {
-	    NEXT;
-	    len++;
-	}
-	if (!IS_CHAR_CH(CUR)) {
-	    htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
-			 "Unfinished SystemLiteral\n", NULL, NULL);
-	} else {
-	    ret = xmlStrndup((BASE_PTR+startPosition), len);
-	    NEXT;
-        }
-    } else {
+    if ((CUR != '"') && (CUR != '\'')) {
 	htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
-	             " or ' expected\n", NULL, NULL);
+	             "SystemLiteral \" or ' expected\n", NULL, NULL);
+        return(NULL);
+    }
+    quote = CUR;
+    NEXT;
+
+    if (CUR_PTR < BASE_PTR)
+        return(ret);
+    startPosition = CUR_PTR - BASE_PTR;
+
+    while ((CUR != 0) && (CUR != quote)) {
+        /* TODO: Handle UTF-8 */
+        if (!IS_CHAR_CH(CUR)) {
+            htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+                            "Invalid char in SystemLiteral 0x%X\n", CUR);
+            err = 1;
+        }
+        NEXT;
+        len++;
+    }
+    if (CUR != quote) {
+        htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
+                     "Unfinished SystemLiteral\n", NULL, NULL);
+    } else {
+        NEXT;
+        if (err == 0)
+            ret = xmlStrndup((BASE_PTR+startPosition), len);
     }
 
     return(ret);
@@ -2849,51 +2852,42 @@
 static xmlChar *
 htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) {
     size_t len = 0, startPosition = 0;
+    int err = 0;
+    int quote;
     xmlChar *ret = NULL;
+
+    if ((CUR != '"') && (CUR != '\'')) {
+	htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
+	             "PubidLiteral \" or ' expected\n", NULL, NULL);
+        return(NULL);
+    }
+    quote = CUR;
+    NEXT;
+
     /*
      * Name ::= (Letter | '_') (NameChar)*
      */
-    if (CUR == '"') {
-        NEXT;
+    if (CUR_PTR < BASE_PTR)
+        return(ret);
+    startPosition = CUR_PTR - BASE_PTR;
 
-        if (CUR_PTR < BASE_PTR)
-            return(ret);
-        startPosition = CUR_PTR - BASE_PTR;
-
-        while (IS_PUBIDCHAR_CH(CUR)) {
-            len++;
-            NEXT;
+    while ((CUR != 0) && (CUR != quote)) {
+        if (!IS_PUBIDCHAR_CH(CUR)) {
+            htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+                            "Invalid char in PubidLiteral 0x%X\n", CUR);
+            err = 1;
         }
-
-	if (CUR != '"') {
-	    htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
-	                 "Unfinished PubidLiteral\n", NULL, NULL);
-	} else {
-	    ret = xmlStrndup((BASE_PTR + startPosition), len);
-	    NEXT;
-	}
-    } else if (CUR == '\'') {
+        len++;
         NEXT;
+    }
 
-        if (CUR_PTR < BASE_PTR)
-            return(ret);
-        startPosition = CUR_PTR - BASE_PTR;
-
-        while ((IS_PUBIDCHAR_CH(CUR)) && (CUR != '\'')){
-            len++;
-            NEXT;
-        }
-
-	if (CUR != '\'') {
-	    htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
-	                 "Unfinished PubidLiteral\n", NULL, NULL);
-	} else {
-	    ret = xmlStrndup((BASE_PTR + startPosition), len);
-	    NEXT;
-	}
+    if (CUR != '"') {
+        htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
+                     "Unfinished PubidLiteral\n", NULL, NULL);
     } else {
-	htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
-	             "PubidLiteral \" or ' expected\n", NULL, NULL);
+        NEXT;
+        if (err == 0)
+            ret = xmlStrndup((BASE_PTR + startPosition), len);
     }
 
     return(ret);
@@ -2928,7 +2922,7 @@
 
     SHRINK;
     cur = CUR_CHAR(l);
-    while (IS_CHAR_CH(cur)) {
+    while (cur != 0) {
 	if ((cur == '<') && (NXT(1) == '/')) {
             /*
              * One should break here, the specification is clear:
@@ -2959,7 +2953,12 @@
                 }
             }
 	}
-	COPY_BUF(l,buf,nbchar,cur);
+        if (IS_CHAR(cur)) {
+	    COPY_BUF(l,buf,nbchar,cur);
+        } else {
+            htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+                            "Invalid char in CDATA 0x%X\n", cur);
+        }
 	if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) {
             buf[nbchar] = 0;
 	    if (ctxt->sax->cdataBlock!= NULL) {
@@ -2977,14 +2976,6 @@
 	cur = CUR_CHAR(l);
     }
 
-    if ((!(IS_CHAR_CH(cur))) && (!((cur == 0) && (ctxt->progressive)))) {
-        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)) {
         buf[nbchar] = 0;
 	if (ctxt->sax->cdataBlock!= NULL) {
@@ -3232,7 +3223,7 @@
 	    }
             SKIP_BLANKS;
 	    cur = CUR_CHAR(l);
-	    while (IS_CHAR(cur) && (cur != '>')) {
+	    while ((cur != 0) && (cur != '>')) {
 		if (len + 5 >= size) {
 		    xmlChar *tmp;
 
@@ -3251,7 +3242,13 @@
 		    GROW;
 		    count = 0;
 		}
-		COPY_BUF(l,buf,len,cur);
+                if (IS_CHAR(cur)) {
+		    COPY_BUF(l,buf,len,cur);
+                } else {
+                    htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+                                    "Invalid char in processing instruction "
+                                    "0x%X\n", cur);
+                }
 		NEXTL(l);
 		cur = CUR_CHAR(l);
 		if (cur == 0) {
@@ -3321,15 +3318,15 @@
     len = 0;
     buf[len] = 0;
     q = CUR_CHAR(ql);
-    if (!IS_CHAR(q))
+    if (q == 0)
         goto unfinished;
     NEXTL(ql);
     r = CUR_CHAR(rl);
-    if (!IS_CHAR(r))
+    if (r == 0)
         goto unfinished;
     NEXTL(rl);
     cur = CUR_CHAR(l);
-    while (IS_CHAR(cur) &&
+    while ((cur != 0) &&
            ((cur != '>') ||
 	    (r != '-') || (q != '-'))) {
 	if (len + 5 >= size) {
@@ -3345,7 +3342,12 @@
 	    }
 	    buf = tmp;
 	}
-	COPY_BUF(ql,buf,len,q);
+        if (IS_CHAR(q)) {
+	    COPY_BUF(ql,buf,len,q);
+        } else {
+            htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+                            "Invalid char in comment 0x%X\n", q);
+        }
 	q = r;
 	ql = rl;
 	r = cur;
@@ -3359,7 +3361,7 @@
 	}
     }
     buf[len] = 0;
-    if (IS_CHAR(cur)) {
+    if (cur == '>') {
         NEXT;
 	if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
 	    (!ctxt->disableSAX))
@@ -3400,13 +3402,16 @@
         ((NXT(2) == 'x') || NXT(2) == 'X')) {
 	SKIP(3);
 	while (CUR != ';') {
-	    if ((CUR >= '0') && (CUR <= '9'))
-	        val = val * 16 + (CUR - '0');
-	    else if ((CUR >= 'a') && (CUR <= 'f'))
-	        val = val * 16 + (CUR - 'a') + 10;
-	    else if ((CUR >= 'A') && (CUR <= 'F'))
-	        val = val * 16 + (CUR - 'A') + 10;
-	    else {
+	    if ((CUR >= '0') && (CUR <= '9')) {
+                if (val < 0x110000)
+	            val = val * 16 + (CUR - '0');
+            } else if ((CUR >= 'a') && (CUR <= 'f')) {
+                if (val < 0x110000)
+	            val = val * 16 + (CUR - 'a') + 10;
+            } else if ((CUR >= 'A') && (CUR <= 'F')) {
+                if (val < 0x110000)
+	            val = val * 16 + (CUR - 'A') + 10;
+            } else {
 	        htmlParseErr(ctxt, XML_ERR_INVALID_HEX_CHARREF,
 		             "htmlParseCharRef: missing semicolon\n",
 			     NULL, NULL);
@@ -3419,9 +3424,10 @@
     } else if  ((CUR == '&') && (NXT(1) == '#')) {
 	SKIP(2);
 	while (CUR != ';') {
-	    if ((CUR >= '0') && (CUR <= '9'))
-	        val = val * 10 + (CUR - '0');
-	    else {
+	    if ((CUR >= '0') && (CUR <= '9')) {
+                if (val < 0x110000)
+	            val = val * 10 + (CUR - '0');
+            } else {
 	        htmlParseErr(ctxt, XML_ERR_INVALID_DEC_CHARREF,
 		             "htmlParseCharRef: missing semicolon\n",
 			     NULL, NULL);
@@ -3440,6 +3446,9 @@
      */
     if (IS_CHAR(val)) {
         return(val);
+    } else if (val >= 0x110000) {
+	htmlParseErr(ctxt, XML_ERR_INVALID_CHAR,
+		     "htmlParseCharRef: value too large\n", NULL, NULL);
     } else {
 	htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
 			"htmlParseCharRef: invalid xmlChar value %d\n",
@@ -3499,9 +3508,12 @@
     if (CUR != '>') {
 	htmlParseErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED,
 	             "DOCTYPE improperly terminated\n", NULL, NULL);
-        /* We shouldn't try to resynchronize ... */
+        /* Ignore bogus content */
+        while ((CUR != 0) && (CUR != '>'))
+            NEXT;
     }
-    NEXT;
+    if (CUR == '>')
+        NEXT;
 
     /*
      * Create or update the document accordingly to the DOCTYPE
@@ -3779,7 +3791,7 @@
 
 
 	/* Dump the bogus tag like browsers do */
-	while ((IS_CHAR_CH(CUR)) && (CUR != '>') &&
+	while ((CUR != 0) && (CUR != '>') &&
                (ctxt->instate != XML_PARSER_EOF))
 	    NEXT;
         return -1;
@@ -3835,11 +3847,9 @@
      * (S Attribute)* S?
      */
     SKIP_BLANKS;
-    while ((IS_CHAR_CH(CUR)) &&
+    while ((CUR != 0) &&
            (CUR != '>') &&
 	   ((CUR != '/') || (NXT(1) != '>'))) {
-	long cons = ctxt->nbChars;
-
 	GROW;
 	attname = htmlParseAttribute(ctxt, &attvalue);
         if (attname != NULL) {
@@ -3898,7 +3908,7 @@
 	        xmlFree(attvalue);
 	    /* Dump the bogus attribute string up to the next blank or
 	     * the end of the tag. */
-	    while ((IS_CHAR_CH(CUR)) &&
+	    while ((CUR != 0) &&
 	           !(IS_BLANK_CH(CUR)) && (CUR != '>') &&
 		   ((CUR != '/') || (NXT(1) != '>')))
 		NEXT;
@@ -3906,12 +3916,6 @@
 
 failed:
 	SKIP_BLANKS;
-        if (cons == ctxt->nbChars) {
-	    htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
-	                 "htmlParseStartTag: problem parsing attributes\n",
-			 NULL, NULL);
-	    break;
-	}
     }
 
     /*
@@ -3979,19 +3983,14 @@
      * We should definitely be at the ending "S? '>'" part
      */
     SKIP_BLANKS;
-    if ((!IS_CHAR_CH(CUR)) || (CUR != '>')) {
+    if (CUR != '>') {
         htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
 	             "End tag : expected '>'\n", NULL, NULL);
-	if (ctxt->recovery) {
-	    /*
-	     * We're not at the ending > !!
-	     * Error, unless in recover mode where we search forwards
-	     * until we find a >
-	     */
-	    while (CUR != '\0' && CUR != '>') NEXT;
-	    NEXT;
-	}
-    } else
+        /* Skip to next '>' */
+        while ((CUR != 0) && (CUR != '>'))
+            NEXT;
+    }
+    if (CUR == '>')
         NEXT;
 
     /*
@@ -4152,8 +4151,6 @@
     currentNode = xmlStrdup(ctxt->name);
     depth = ctxt->nameNr;
     while (1) {
-	long cons = ctxt->nbChars;
-
         GROW;
 
         if (ctxt->instate == XML_PARSER_EOF)
@@ -4181,7 +4178,7 @@
 			 "htmlParseStartTag: invalid element name\n",
 			 NULL, NULL);
 	        /* Dump the bogus tag like browsers do */
-        while ((IS_CHAR_CH(CUR)) && (CUR != '>'))
+                while ((CUR != 0) && (CUR != '>'))
 	            NEXT;
 
 	        if (currentNode != NULL)
@@ -4273,15 +4270,6 @@
 	    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;
     }
@@ -4396,7 +4384,7 @@
      */
     currentNode = xmlStrdup(ctxt->name);
     depth = ctxt->nameNr;
-    while (IS_CHAR_CH(CUR)) {
+    while (CUR != 0) {
 	oldptr = ctxt->input->cur;
 	htmlParseContent(ctxt);
 	if (oldptr==ctxt->input->cur) break;
@@ -4413,7 +4401,7 @@
        node_info.node = ctxt->node;
        xmlParserAddNodeInfo(ctxt, &node_info);
     }
-    if (!IS_CHAR_CH(CUR)) {
+    if (CUR == 0) {
 	htmlAutoCloseOnEnd(ctxt);
     }
 
@@ -4434,7 +4422,7 @@
        xmlParserAddNodeInfo(ctxt, ctxt->nodeInfo);
        htmlNodeInfoPop(ctxt);
     }
-    if (!IS_CHAR_CH(CUR)) {
+    if (CUR == 0) {
        htmlAutoCloseOnEnd(ctxt);
     }
 }
@@ -4552,8 +4540,6 @@
     currentNode = xmlStrdup(ctxt->name);
     depth = ctxt->nameNr;
     while (1) {
-	long cons = ctxt->nbChars;
-
         GROW;
 
         if (ctxt->instate == XML_PARSER_EOF)
@@ -4583,7 +4569,7 @@
 			 "htmlParseStartTag: invalid element name\n",
 			 NULL, NULL);
 	        /* Dump the bogus tag like browsers do */
-	        while ((IS_CHAR_CH(CUR)) && (CUR != '>'))
+	        while ((CUR == 0) && (CUR != '>'))
 	            NEXT;
 
 	        htmlParserFinishElementParsing(ctxt);
@@ -4687,15 +4673,6 @@
 	    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;
     }
@@ -4959,7 +4936,6 @@
     ctxt->vctxt.warning = xmlParserValidityWarning;
     ctxt->record_info = 0;
     ctxt->validate = 0;
-    ctxt->nbChars = 0;
     ctxt->checkIndex = 0;
     ctxt->catalogs = NULL;
     xmlInitNodeInfoSeq(&ctxt->node_seq);
@@ -5119,7 +5095,7 @@
  * @first:  the first char to lookup
  * @next:  the next char to lookup or zero
  * @third:  the next char to lookup or zero
- * @comment: flag to force checking inside comments
+ * @ignoreattrval: skip over attribute values
  *
  * Try to find if a sequence (first, next, third) or  just (first next) or
  * (first) is available in the input stream.
@@ -5133,13 +5109,11 @@
  */
 static int
 htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
-                        xmlChar next, xmlChar third, int iscomment,
-                        int ignoreattrval)
+                        xmlChar next, xmlChar third, int ignoreattrval)
 {
     int base, len;
     htmlParserInputPtr in;
     const xmlChar *buf;
-    int incomment = 0;
     int invalue = 0;
     char valdellim = 0x0;
 
@@ -5151,8 +5125,11 @@
     if (base < 0)
         return (-1);
 
-    if (ctxt->checkIndex > base)
+    if (ctxt->checkIndex > base) {
         base = ctxt->checkIndex;
+        /* Abuse hasPErefs member to restore current state. */
+        invalue = ctxt->hasPErefs & 1 ? 1 : 0;
+    }
 
     if (in->buf == NULL) {
         buf = in->base;
@@ -5168,14 +5145,6 @@
     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) {
@@ -5192,16 +5161,6 @@
                 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))
@@ -5228,8 +5187,12 @@
             return (base - (in->cur - in->base));
         }
     }
-    if ((!incomment) && (!invalue))
-        ctxt->checkIndex = base;
+    ctxt->checkIndex = base;
+    /* Abuse hasPErefs member to track current state. */
+    if (invalue)
+        ctxt->hasPErefs |= 1;
+    else
+        ctxt->hasPErefs &= ~1;
 #ifdef DEBUG_PUSH
     if (next == 0)
         xmlGenericError(xmlGenericErrorContext,
@@ -5246,80 +5209,6 @@
 }
 
 /**
- * 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);
-}
-
-/**
  * htmlParseTryOrFinish:
  * @ctxt:  an HTML parser context
  * @terminate:  last chunk indicator
@@ -5332,7 +5221,7 @@
 htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
     int ret = 0;
     htmlParserInputPtr in;
-    int avail = 0;
+    ptrdiff_t avail = 0;
     xmlChar cur, next;
 
     htmlParserNodeInfo node_info;
@@ -5397,7 +5286,8 @@
 	if (in->buf == NULL)
 	    avail = in->length - (in->cur - in->base);
 	else
-	    avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
+	    avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
+                    (in->cur - in->base);
 	if ((avail == 0) && (terminate)) {
 	    htmlAutoCloseOnEnd(ctxt);
 	    if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
@@ -5411,6 +5301,12 @@
 	}
         if (avail < 1)
 	    goto done;
+        /*
+         * This is done to make progress and avoid an infinite loop
+         * if a parsing attempt was aborted by hitting a NUL byte. After
+         * changing htmlCurrentChar, this probably isn't necessary anymore.
+         * We should consider removing this check.
+         */
 	cur = in->cur[0];
 	if (cur == 0) {
 	    SKIP(1);
@@ -5433,7 +5329,8 @@
 		    if (in->buf == NULL)
 			avail = in->length - (in->cur - in->base);
 		    else
-			avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
+			avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
+                                (in->cur - in->base);
 		}
 		if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
 		    ctxt->sax->setDocumentLocator(ctxt->userData,
@@ -5450,7 +5347,7 @@
 		    (UPP(6) == 'Y') && (UPP(7) == 'P') &&
 		    (UPP(8) == 'E')) {
 		    if ((!terminate) &&
-		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
 			goto done;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
@@ -5475,7 +5372,8 @@
 		if (in->buf == NULL)
 		    avail = in->length - (in->cur - in->base);
 		else
-		    avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
+		    avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
+                            (in->cur - in->base);
 		/*
 		 * no chars in buffer
 		 */
@@ -5496,7 +5394,7 @@
 	        if ((cur == '<') && (next == '!') &&
 		    (in->cur[2] == '-') && (in->cur[3] == '-')) {
 		    if ((!terminate) &&
-		        (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
+		        (htmlParseLookupSequence(ctxt, '-', '-', '>', 0) < 0))
 			goto done;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
@@ -5506,7 +5404,7 @@
 		    ctxt->instate = XML_PARSER_MISC;
 	        } else if ((cur == '<') && (next == '?')) {
 		    if ((!terminate) &&
-		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 			goto done;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
@@ -5520,7 +5418,7 @@
 		    (UPP(6) == 'Y') && (UPP(7) == 'P') &&
 		    (UPP(8) == 'E')) {
 		    if ((!terminate) &&
-		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
 			goto done;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
@@ -5536,7 +5434,7 @@
 		           (avail < 9)) {
 		    goto done;
 		} else {
-		    ctxt->instate = XML_PARSER_START_TAG;
+		    ctxt->instate = XML_PARSER_CONTENT;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
 			    "HPP: entering START_TAG\n");
@@ -5548,7 +5446,8 @@
 		if (in->buf == NULL)
 		    avail = in->length - (in->cur - in->base);
 		else
-		    avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
+		    avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
+                            (in->cur - in->base);
 		if (avail < 2)
 		    goto done;
 		cur = in->cur[0];
@@ -5556,7 +5455,7 @@
 		if ((cur == '<') && (next == '!') &&
 		    (in->cur[2] == '-') && (in->cur[3] == '-')) {
 		    if ((!terminate) &&
-		        (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
+		        (htmlParseLookupSequence(ctxt, '-', '-', '>', 0) < 0))
 			goto done;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
@@ -5566,7 +5465,7 @@
 		    ctxt->instate = XML_PARSER_PROLOG;
 	        } else if ((cur == '<') && (next == '?')) {
 		    if ((!terminate) &&
-		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 			goto done;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
@@ -5578,7 +5477,7 @@
 		           (avail < 4)) {
 		    goto done;
 		} else {
-		    ctxt->instate = XML_PARSER_START_TAG;
+		    ctxt->instate = XML_PARSER_CONTENT;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
 			    "HPP: entering START_TAG\n");
@@ -5589,7 +5488,8 @@
 		if (in->buf == NULL)
 		    avail = in->length - (in->cur - in->base);
 		else
-		    avail = xmlBufUse(in->buf->buffer) - (in->cur - in->base);
+		    avail = (ptrdiff_t)xmlBufUse(in->buf->buffer) -
+                            (in->cur - in->base);
 		if (avail < 1)
 		    goto done;
 		cur = in->cur[0];
@@ -5603,7 +5503,7 @@
 	        if ((cur == '<') && (next == '!') &&
 		    (in->cur[2] == '-') && (in->cur[3] == '-')) {
 		    if ((!terminate) &&
-		        (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
+		        (htmlParseLookupSequence(ctxt, '-', '-', '>', 0) < 0))
 			goto done;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
@@ -5613,7 +5513,7 @@
 		    ctxt->instate = XML_PARSER_EPILOG;
 	        } else if ((cur == '<') && (next == '?')) {
 		    if ((!terminate) &&
-		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 			goto done;
 #ifdef DEBUG_PUSH
 		    xmlGenericError(xmlGenericErrorContext,
@@ -5677,7 +5577,7 @@
 		    break;
 		}
 		if ((!terminate) &&
-		    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+		    (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
 		    goto done;
 
                 /* Capture start position */
@@ -5769,7 +5669,6 @@
 	    }
             case XML_PARSER_CONTENT: {
 		xmlChar chr[2] = { 0, 0 };
-		long cons;
 
                 /*
 		 * Handle preparsed entities and charRef
@@ -5814,7 +5713,6 @@
 		    goto done;
 		cur = in->cur[0];
 		next = in->cur[1];
-		cons = ctxt->nbChars;
 		if ((xmlStrEqual(ctxt->name, BAD_CAST"script")) ||
 		    (xmlStrEqual(ctxt->name, BAD_CAST"style"))) {
 		    /*
@@ -5824,7 +5722,7 @@
 		        int idx;
 			xmlChar val;
 
-			idx = htmlParseLookupSequence(ctxt, '<', '/', 0, 0, 0);
+			idx = htmlParseLookupSequence(ctxt, '<', '/', 0, 0);
 			if (idx < 0)
 			    goto done;
 		        val = in->cur[idx + 2];
@@ -5851,7 +5749,7 @@
 			(UPP(6) == 'Y') && (UPP(7) == 'P') &&
 			(UPP(8) == 'E')) {
 			if ((!terminate) &&
-			    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+			    (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
 			    goto done;
 			htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
 			             "Misplaced DOCTYPE declaration\n",
@@ -5861,7 +5759,7 @@
 			(in->cur[2] == '-') && (in->cur[3] == '-')) {
 			if ((!terminate) &&
 			    (htmlParseLookupSequence(
-				ctxt, '-', '-', '>', 1, 1) < 0))
+				ctxt, '-', '-', '>', 0) < 0))
 			    goto done;
 #ifdef DEBUG_PUSH
 			xmlGenericError(xmlGenericErrorContext,
@@ -5871,7 +5769,7 @@
 			ctxt->instate = XML_PARSER_CONTENT;
 		    } else if ((cur == '<') && (next == '?')) {
 			if ((!terminate) &&
-			    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+			    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 			    goto done;
 #ifdef DEBUG_PUSH
 			xmlGenericError(xmlGenericErrorContext,
@@ -5890,24 +5788,35 @@
 #endif
 			break;
 		    } else if (cur == '<') {
-			ctxt->instate = XML_PARSER_START_TAG;
-			ctxt->checkIndex = 0;
+                        if ((!terminate) && (next == 0))
+                            goto done;
+                        /*
+                         * Only switch to START_TAG if the next character
+                         * starts a valid name. Otherwise, htmlParseStartTag
+                         * might return without consuming all characters
+                         * up to the final '>'.
+                         */
+                        if ((IS_ASCII_LETTER(next)) ||
+                            (next == '_') || (next == ':') || (next == '.')) {
+                            ctxt->instate = XML_PARSER_START_TAG;
+                            ctxt->checkIndex = 0;
 #ifdef DEBUG_PUSH
-			xmlGenericError(xmlGenericErrorContext,
-				"HPP: entering START_TAG\n");
+                            xmlGenericError(xmlGenericErrorContext,
+                                    "HPP: entering START_TAG\n");
 #endif
+                        } else {
+                            htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
+                                         "htmlParseTryOrFinish: "
+                                         "invalid element name\n",
+                                         NULL, NULL);
+                            htmlCheckParagraph(ctxt);
+                            if ((ctxt->sax != NULL) &&
+                                (ctxt->sax->characters != NULL))
+                                ctxt->sax->characters(ctxt->userData,
+                                                      in->cur, 1);
+                            NEXT;
+                        }
 			break;
-		    } else if (cur == '&') {
-			if ((!terminate) &&
-			    (htmlParseLookupChars(ctxt,
-                                                  BAD_CAST "; >/", 4) < 0))
-			    goto done;
-#ifdef DEBUG_PUSH
-			xmlGenericError(xmlGenericErrorContext,
-				"HPP: Parsing Reference\n");
-#endif
-			/* TODO: check generation of subtrees if noent !!! */
-			htmlParseReference(ctxt);
 		    } else {
 		        /*
 			 * check that the text sequence is complete
@@ -5916,25 +5825,23 @@
 			 * data detection.
 			 */
 			if ((!terminate) &&
-                            (htmlParseLookupChars(ctxt, BAD_CAST "<&", 2) < 0))
+                            (htmlParseLookupSequence(ctxt, '<', 0, 0, 0) < 0))
 			    goto done;
 			ctxt->checkIndex = 0;
 #ifdef DEBUG_PUSH
 			xmlGenericError(xmlGenericErrorContext,
 				"HPP: Parsing char data\n");
 #endif
-			htmlParseCharData(ctxt);
+                        while ((cur != '<') && (cur != 0)) {
+                            if (cur == '&') {
+			        htmlParseReference(ctxt);
+                            } else {
+			        htmlParseCharData(ctxt);
+                            }
+                            cur = in->cur[0];
+                        }
 		    }
 		}
-		if (cons == ctxt->nbChars) {
-		    if (ctxt->node != NULL) {
-			htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
-			             "detected an error in element content\n",
-				     NULL, NULL);
-		    }
-		    NEXT;
-		    break;
-		}
 
 		break;
 	    }
@@ -5942,7 +5849,7 @@
 		if (avail < 2)
 		    goto done;
 		if ((!terminate) &&
-		    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
+		    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 		    goto done;
 		htmlParseEndTag(ctxt);
 		if (ctxt->nameNr == 0) {
@@ -6124,12 +6031,12 @@
 	int res;
 
 	res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
+        xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
 	if (res < 0) {
 	    ctxt->errNo = XML_PARSER_EOF;
 	    ctxt->disableSAX = 1;
 	    return (XML_PARSER_EOF);
 	}
-        xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
 #ifdef DEBUG_PUSH
 	xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
 #endif
@@ -6148,12 +6055,12 @@
 		size_t current = ctxt->input->cur - ctxt->input->base;
 
 		nbchars = xmlCharEncInput(in, terminate);
+		xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
 		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);
 	    }
 	}
     }
@@ -6671,7 +6578,6 @@
     ctxt->vctxt.error = xmlParserValidityError;
     ctxt->vctxt.warning = xmlParserValidityWarning;
     ctxt->record_info = 0;
-    ctxt->nbChars = 0;
     ctxt->checkIndex = 0;
     ctxt->inSubset = 0;
     ctxt->errNo = XML_ERR_OK;
diff --git a/src/HTMLtree.c b/src/HTMLtree.c
index fe5d086..8d0c779 100644
--- a/src/HTMLtree.c
+++ b/src/HTMLtree.c
@@ -706,49 +706,22 @@
 		 (!xmlStrcasecmp(cur->name, BAD_CAST "src")) ||
 		 ((!xmlStrcasecmp(cur->name, BAD_CAST "name")) &&
 		  (!xmlStrcasecmp(cur->parent->name, BAD_CAST "a"))))) {
+		xmlChar *escaped;
 		xmlChar *tmp = value;
-		/* xmlURIEscapeStr() escapes '"' so it can be safely used. */
-		xmlBufCCat(buf->buffer, "\"");
 
 		while (IS_BLANK_CH(*tmp)) tmp++;
 
-		/* URI Escape everything, except server side includes. */
-		for ( ; ; ) {
-		    xmlChar *escaped;
-		    xmlChar endChar;
-		    xmlChar *end = NULL;
-		    xmlChar *start = (xmlChar *)xmlStrstr(tmp, BAD_CAST "<!--");
-		    if (start != NULL) {
-			end = (xmlChar *)xmlStrstr(tmp, BAD_CAST "-->");
-			if (end != NULL) {
-			    *start = '\0';
-			}
-		    }
-
-		    /* Escape the whole string, or until start (set to '\0'). */
-		    escaped = xmlURIEscapeStr(tmp, BAD_CAST"@/:=?;#%&,+");
-		    if (escaped != NULL) {
-		        xmlBufCat(buf->buffer, escaped);
-		        xmlFree(escaped);
-		    } else {
-		        xmlBufCat(buf->buffer, tmp);
-		    }
-
-		    if (end == NULL) { /* Everything has been written. */
-			break;
-		    }
-
-		    /* Do not escape anything within server side includes. */
-		    *start = '<'; /* Restore the first character of "<!--". */
-		    end += 3; /* strlen("-->") */
-		    endChar = *end;
-		    *end = '\0';
-		    xmlBufCat(buf->buffer, start);
-		    *end = endChar;
-		    tmp = end;
+		/*
+		 * the < and > have already been escaped at the entity level
+		 * And doing so here breaks server side includes
+		 */
+		escaped = xmlURIEscapeStr(tmp, BAD_CAST"@/:=?;#%&,+<>");
+		if (escaped != NULL) {
+		    xmlBufWriteQuotedString(buf->buffer, escaped);
+		    xmlFree(escaped);
+		} else {
+		    xmlBufWriteQuotedString(buf->buffer, value);
 		}
-
-		xmlBufCCat(buf->buffer, "\"");
 	    } else {
 		xmlBufWriteQuotedString(buf->buffer, value);
 	    }
@@ -760,50 +733,6 @@
 }
 
 /**
- * htmlAttrListDumpOutput:
- * @buf:  the HTML buffer output
- * @doc:  the document
- * @cur:  the first attribute pointer
- * @encoding:  the encoding string
- *
- * Dump a list of HTML attributes
- */
-static void
-htmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur, const char *encoding) {
-    if (cur == NULL) {
-	return;
-    }
-    while (cur != NULL) {
-        htmlAttrDumpOutput(buf, doc, cur, encoding);
-	cur = cur->next;
-    }
-}
-
-
-
-/**
- * htmlNodeListDumpOutput:
- * @buf:  the HTML buffer output
- * @doc:  the document
- * @cur:  the first node
- * @encoding:  the encoding string
- * @format:  should formatting spaces been added
- *
- * Dump an HTML node list, recursive behaviour,children are printed too.
- */
-static void
-htmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
-	               xmlNodePtr cur, const char *encoding, int format) {
-    if (cur == NULL) {
-	return;
-    }
-    while (cur != NULL) {
-        htmlNodeDumpFormatOutput(buf, doc, cur, encoding, format);
-	cur = cur->next;
-    }
-}
-
-/**
  * htmlNodeDumpFormatOutput:
  * @buf:  the HTML buffer output
  * @doc:  the document
@@ -816,6 +745,8 @@
 void
 htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
 	                 xmlNodePtr cur, const char *encoding, int format) {
+    xmlNodePtr root;
+    xmlAttrPtr attr;
     const htmlElemDesc * info;
 
     xmlInitParser();
@@ -823,172 +754,199 @@
     if ((cur == NULL) || (buf == NULL)) {
 	return;
     }
-    /*
-     * Special cases.
-     */
-    if (cur->type == XML_DTD_NODE)
-	return;
-    if ((cur->type == XML_HTML_DOCUMENT_NODE) ||
-        (cur->type == XML_DOCUMENT_NODE)){
-	htmlDocContentDumpOutput(buf, (xmlDocPtr) cur, encoding);
-	return;
-    }
-    if (cur->type == XML_ATTRIBUTE_NODE) {
-        htmlAttrDumpOutput(buf, doc, (xmlAttrPtr) cur, encoding);
-	return;
-    }
-    if (cur->type == HTML_TEXT_NODE) {
-	if (cur->content != NULL) {
-	    if (((cur->name == (const xmlChar *)xmlStringText) ||
-		 (cur->name != (const xmlChar *)xmlStringTextNoenc)) &&
-		((cur->parent == NULL) ||
-		 ((xmlStrcasecmp(cur->parent->name, BAD_CAST "script")) &&
-		  (xmlStrcasecmp(cur->parent->name, BAD_CAST "style"))))) {
-		xmlChar *buffer;
 
-		buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
-		if (buffer != NULL) {
-		    xmlOutputBufferWriteString(buf, (const char *)buffer);
-		    xmlFree(buffer);
-		}
-	    } else {
-		xmlOutputBufferWriteString(buf, (const char *)cur->content);
-	    }
-	}
-	return;
-    }
-    if (cur->type == HTML_COMMENT_NODE) {
-	if (cur->content != NULL) {
-	    xmlOutputBufferWriteString(buf, "<!--");
-	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
-	    xmlOutputBufferWriteString(buf, "-->");
-	}
-	return;
-    }
-    if (cur->type == HTML_PI_NODE) {
-	if (cur->name == NULL)
-	    return;
-	xmlOutputBufferWriteString(buf, "<?");
-	xmlOutputBufferWriteString(buf, (const char *)cur->name);
-	if (cur->content != NULL) {
-	    xmlOutputBufferWriteString(buf, " ");
-	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
-	}
-	xmlOutputBufferWriteString(buf, ">");
-	return;
-    }
-    if (cur->type == HTML_ENTITY_REF_NODE) {
-        xmlOutputBufferWriteString(buf, "&");
-	xmlOutputBufferWriteString(buf, (const char *)cur->name);
-        xmlOutputBufferWriteString(buf, ";");
-	return;
-    }
-    if (cur->type == HTML_PRESERVE_NODE) {
-	if (cur->content != NULL) {
-	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
-	}
-	return;
-    }
+    root = cur;
+    while (1) {
+        switch (cur->type) {
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_NODE:
+            if (((xmlDocPtr) cur)->intSubset != NULL) {
+                htmlDtdDumpOutput(buf, (xmlDocPtr) cur, NULL);
+            }
+            if (cur->children != NULL) {
+                cur = cur->children;
+                continue;
+            }
+            break;
 
-    /*
-     * Get specific HTML info for that node.
-     */
-    if (cur->ns == NULL)
-	info = htmlTagLookup(cur->name);
-    else
-	info = NULL;
+        case XML_ELEMENT_NODE:
+            /*
+             * Get specific HTML info for that node.
+             */
+            if (cur->ns == NULL)
+                info = htmlTagLookup(cur->name);
+            else
+                info = NULL;
 
-    xmlOutputBufferWriteString(buf, "<");
-    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
-        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
-	xmlOutputBufferWriteString(buf, ":");
-    }
-    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-    if (cur->nsDef)
-	xmlNsListDumpOutput(buf, cur->nsDef);
-    if (cur->properties != NULL)
-        htmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
-
-    if ((info != NULL) && (info->empty)) {
-        xmlOutputBufferWriteString(buf, ">");
-	if ((format) && (!info->isinline) && (cur->next != NULL)) {
-	    if ((cur->next->type != HTML_TEXT_NODE) &&
-		(cur->next->type != HTML_ENTITY_REF_NODE) &&
-		(cur->parent != NULL) &&
-		(cur->parent->name != NULL) &&
-		(cur->parent->name[0] != 'p')) /* p, pre, param */
-		xmlOutputBufferWriteString(buf, "\n");
-	}
-	return;
-    }
-    if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
-	(cur->children == NULL)) {
-        if ((info != NULL) && (info->saveEndTag != 0) &&
-	    (xmlStrcmp(BAD_CAST info->name, BAD_CAST "html")) &&
-	    (xmlStrcmp(BAD_CAST info->name, BAD_CAST "body"))) {
-	    xmlOutputBufferWriteString(buf, ">");
-	} else {
-	    xmlOutputBufferWriteString(buf, "></");
+            xmlOutputBufferWriteString(buf, "<");
             if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
                 xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
                 xmlOutputBufferWriteString(buf, ":");
             }
-	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-	    xmlOutputBufferWriteString(buf, ">");
-	}
-	if ((format) && (cur->next != NULL) &&
-            (info != NULL) && (!info->isinline)) {
-	    if ((cur->next->type != HTML_TEXT_NODE) &&
-		(cur->next->type != HTML_ENTITY_REF_NODE) &&
-		(cur->parent != NULL) &&
-		(cur->parent->name != NULL) &&
-		(cur->parent->name[0] != 'p')) /* p, pre, param */
-		xmlOutputBufferWriteString(buf, "\n");
-	}
-	return;
-    }
-    xmlOutputBufferWriteString(buf, ">");
-    if ((cur->type != XML_ELEMENT_NODE) &&
-	(cur->content != NULL)) {
-	    /*
-	     * Uses the OutputBuffer property to automatically convert
-	     * invalids to charrefs
-	     */
+            xmlOutputBufferWriteString(buf, (const char *)cur->name);
+            if (cur->nsDef)
+                xmlNsListDumpOutput(buf, cur->nsDef);
+            attr = cur->properties;
+            while (attr != NULL) {
+                htmlAttrDumpOutput(buf, doc, attr, encoding);
+                attr = attr->next;
+            }
 
-            xmlOutputBufferWriteString(buf, (const char *) cur->content);
-    }
-    if (cur->children != NULL) {
-        if ((format) && (info != NULL) && (!info->isinline) &&
-	    (cur->children->type != HTML_TEXT_NODE) &&
-	    (cur->children->type != HTML_ENTITY_REF_NODE) &&
-	    (cur->children != cur->last) &&
-	    (cur->name != NULL) &&
-	    (cur->name[0] != 'p')) /* p, pre, param */
-	    xmlOutputBufferWriteString(buf, "\n");
-	htmlNodeListDumpOutput(buf, doc, cur->children, encoding, format);
-        if ((format) && (info != NULL) && (!info->isinline) &&
-	    (cur->last->type != HTML_TEXT_NODE) &&
-	    (cur->last->type != HTML_ENTITY_REF_NODE) &&
-	    (cur->children != cur->last) &&
-	    (cur->name != NULL) &&
-	    (cur->name[0] != 'p')) /* p, pre, param */
-	    xmlOutputBufferWriteString(buf, "\n");
-    }
-    xmlOutputBufferWriteString(buf, "</");
-    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
-        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
-	xmlOutputBufferWriteString(buf, ":");
-    }
-    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-    xmlOutputBufferWriteString(buf, ">");
-    if ((format) && (info != NULL) && (!info->isinline) &&
-	(cur->next != NULL)) {
-        if ((cur->next->type != HTML_TEXT_NODE) &&
-	    (cur->next->type != HTML_ENTITY_REF_NODE) &&
-	    (cur->parent != NULL) &&
-	    (cur->parent->name != NULL) &&
-	    (cur->parent->name[0] != 'p')) /* p, pre, param */
-	    xmlOutputBufferWriteString(buf, "\n");
+            if ((info != NULL) && (info->empty)) {
+                xmlOutputBufferWriteString(buf, ">");
+            } else if (cur->children == NULL) {
+                if ((info != NULL) && (info->saveEndTag != 0) &&
+                    (xmlStrcmp(BAD_CAST info->name, BAD_CAST "html")) &&
+                    (xmlStrcmp(BAD_CAST info->name, BAD_CAST "body"))) {
+                    xmlOutputBufferWriteString(buf, ">");
+                } else {
+                    xmlOutputBufferWriteString(buf, "></");
+                    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                        xmlOutputBufferWriteString(buf,
+                                (const char *)cur->ns->prefix);
+                        xmlOutputBufferWriteString(buf, ":");
+                    }
+                    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                    xmlOutputBufferWriteString(buf, ">");
+                }
+            } else {
+                xmlOutputBufferWriteString(buf, ">");
+                if ((format) && (info != NULL) && (!info->isinline) &&
+                    (cur->children->type != HTML_TEXT_NODE) &&
+                    (cur->children->type != HTML_ENTITY_REF_NODE) &&
+                    (cur->children != cur->last) &&
+                    (cur->name != NULL) &&
+                    (cur->name[0] != 'p')) /* p, pre, param */
+                    xmlOutputBufferWriteString(buf, "\n");
+                cur = cur->children;
+                continue;
+            }
+
+            if ((format) && (cur->next != NULL) &&
+                (info != NULL) && (!info->isinline)) {
+                if ((cur->next->type != HTML_TEXT_NODE) &&
+                    (cur->next->type != HTML_ENTITY_REF_NODE) &&
+                    (cur->parent != NULL) &&
+                    (cur->parent->name != NULL) &&
+                    (cur->parent->name[0] != 'p')) /* p, pre, param */
+                    xmlOutputBufferWriteString(buf, "\n");
+            }
+
+            break;
+
+        case XML_ATTRIBUTE_NODE:
+            htmlAttrDumpOutput(buf, doc, (xmlAttrPtr) cur, encoding);
+            break;
+
+        case HTML_TEXT_NODE:
+            if (cur->content == NULL)
+                break;
+            if (((cur->name == (const xmlChar *)xmlStringText) ||
+                 (cur->name != (const xmlChar *)xmlStringTextNoenc)) &&
+                ((cur->parent == NULL) ||
+                 ((xmlStrcasecmp(cur->parent->name, BAD_CAST "script")) &&
+                  (xmlStrcasecmp(cur->parent->name, BAD_CAST "style"))))) {
+                xmlChar *buffer;
+
+                buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+                if (buffer != NULL) {
+                    xmlOutputBufferWriteString(buf, (const char *)buffer);
+                    xmlFree(buffer);
+                }
+            } else {
+                xmlOutputBufferWriteString(buf, (const char *)cur->content);
+            }
+            break;
+
+        case HTML_COMMENT_NODE:
+            if (cur->content != NULL) {
+                xmlOutputBufferWriteString(buf, "<!--");
+                xmlOutputBufferWriteString(buf, (const char *)cur->content);
+                xmlOutputBufferWriteString(buf, "-->");
+            }
+            break;
+
+        case HTML_PI_NODE:
+            if (cur->name != NULL) {
+                xmlOutputBufferWriteString(buf, "<?");
+                xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                if (cur->content != NULL) {
+                    xmlOutputBufferWriteString(buf, " ");
+                    xmlOutputBufferWriteString(buf,
+                            (const char *)cur->content);
+                }
+                xmlOutputBufferWriteString(buf, ">");
+            }
+            break;
+
+        case HTML_ENTITY_REF_NODE:
+            xmlOutputBufferWriteString(buf, "&");
+            xmlOutputBufferWriteString(buf, (const char *)cur->name);
+            xmlOutputBufferWriteString(buf, ";");
+            break;
+
+        case HTML_PRESERVE_NODE:
+            if (cur->content != NULL) {
+                xmlOutputBufferWriteString(buf, (const char *)cur->content);
+            }
+            break;
+
+        default:
+            break;
+        }
+
+        while (1) {
+            if (cur == root)
+                return;
+            if (cur->next != NULL) {
+                cur = cur->next;
+                break;
+            }
+
+            /*
+             * The parent should never be NULL here but we want to handle
+             * corrupted documents gracefully.
+             */
+            if (cur->parent == NULL)
+                return;
+            cur = cur->parent;
+
+            if ((cur->type == XML_HTML_DOCUMENT_NODE) ||
+                (cur->type == XML_DOCUMENT_NODE)) {
+                xmlOutputBufferWriteString(buf, "\n");
+            } else {
+                if ((format) && (cur->ns == NULL))
+                    info = htmlTagLookup(cur->name);
+                else
+                    info = NULL;
+
+                if ((format) && (info != NULL) && (!info->isinline) &&
+                    (cur->last->type != HTML_TEXT_NODE) &&
+                    (cur->last->type != HTML_ENTITY_REF_NODE) &&
+                    (cur->children != cur->last) &&
+                    (cur->name != NULL) &&
+                    (cur->name[0] != 'p')) /* p, pre, param */
+                    xmlOutputBufferWriteString(buf, "\n");
+
+                xmlOutputBufferWriteString(buf, "</");
+                if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                    xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+                    xmlOutputBufferWriteString(buf, ":");
+                }
+                xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                xmlOutputBufferWriteString(buf, ">");
+
+                if ((format) && (info != NULL) && (!info->isinline) &&
+                    (cur->next != NULL)) {
+                    if ((cur->next->type != HTML_TEXT_NODE) &&
+                        (cur->next->type != HTML_ENTITY_REF_NODE) &&
+                        (cur->parent != NULL) &&
+                        (cur->parent->name != NULL) &&
+                        (cur->parent->name[0] != 'p')) /* p, pre, param */
+                        xmlOutputBufferWriteString(buf, "\n");
+                }
+            }
+        }
     }
 }
 
@@ -1020,26 +978,7 @@
 void
 htmlDocContentDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
 	                       const char *encoding, int format) {
-    int type;
-
-    xmlInitParser();
-
-    if ((buf == NULL) || (cur == NULL))
-        return;
-
-    /*
-     * force to output the stuff as HTML, especially for entities
-     */
-    type = cur->type;
-    cur->type = XML_HTML_DOCUMENT_NODE;
-    if (cur->intSubset != NULL) {
-        htmlDtdDumpOutput(buf, cur, NULL);
-    }
-    if (cur->children != NULL) {
-        htmlNodeListDumpOutput(buf, cur, cur->children, encoding, format);
-    }
-    xmlOutputBufferWriteString(buf, "\n");
-    cur->type = (xmlElementType) type;
+    htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, encoding, format);
 }
 
 /**
@@ -1053,7 +992,7 @@
 void
 htmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
 	                 const char *encoding) {
-    htmlDocContentDumpFormatOutput(buf, cur, encoding, 1);
+    htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, encoding, 1);
 }
 
 /************************************************************************
diff --git a/src/Makefile.am b/src/Makefile.am
index be1a883..4ef0eb9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,9 +2,9 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = include . doc example xstc $(PYTHON_SUBDIR)
+SUBDIRS = include . doc example fuzz xstc $(PYTHON_SUBDIR)
 
-DIST_SUBDIRS = include . doc example python xstc
+DIST_SUBDIRS = include . doc example python xstc fuzz
 
 AM_CPPFLAGS = -I$(top_builddir)/include -I$(srcdir)/include
 
@@ -210,6 +210,7 @@
 	    $(CHECKER) ./runxmlconf$(EXEEXT)
 	@(if [ "$(PYTHON_SUBDIR)" != "" ] ; then cd python ; \
 	    $(MAKE) tests ; fi)
+	@cd fuzz; $(MAKE) tests
 
 check: all runtests
 
@@ -906,14 +907,16 @@
 	  if [ ! -d $$i ] ; then \
 	  if [ ! -f $(srcdir)/result/regexp/$$name ] ; then \
 	      echo New test file $$name ; \
-	      $(CHECKER) $(top_builddir)/testRegexp -i $$i > $(srcdir)/result/regexp/$$name; \
+	      $(CHECKER) $(top_builddir)/testRegexp -i $$i > $(srcdir)/result/regexp/$$name 2> $(srcdir)/result/regexp/$$name.err ; \
+	      if [ ! -s "$(srcdir)/result/regexp/$$name.err" ] ; then rm $(srcdir)/result/regexp/$$name.err; fi ; \
 	      grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
 	  else \
-	      log=`$(CHECKER) $(top_builddir)/testRegexp -i $$i 2>&1 > result.$$name ; \
+	      log=`$(CHECKER) $(top_builddir)/testRegexp -i $$i > result.$$name 2> error.$$name ; \
 	      grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
-	      diff $(srcdir)/result/regexp/$$name result.$$name` ; \
-	      if [ -n "$$log" ] ; then echo $$name result ; echo "$$log" ; fi ; \
-	      rm result.$$name ; \
+	      diff $(srcdir)/result/regexp/$$name result.$$name ; \
+	      if [ -s "$(srcdir)/result/regexp/$$name.err" -o -s "error.$$name" ] ; then diff $(srcdir)/result/regexp/$$name.err error.$$name ; fi` ; \
+	      if [ -n "$$log" ] ; then echo $$name result ; echo $$log ; fi ; \
+	      rm result.$$name error.$$name ; \
 	  fi ; fi ; done)
 
 # Disabled for now
diff --git a/src/SAX2.c b/src/SAX2.c
index 9df0184..4450a3f 100644
--- a/src/SAX2.c
+++ b/src/SAX2.c
@@ -1663,23 +1663,23 @@
 	}
     }
 
-    /*
-     * Insert all the defaulted attributes from the DTD especially namespaces
-     */
-    if ((!ctxt->html) &&
-	((ctxt->myDoc->intSubset != NULL) ||
-	 (ctxt->myDoc->extSubset != NULL))) {
-	xmlCheckDefaultedAttributes(ctxt, name, prefix, atts);
-    }
+    if (!ctxt->html) {
+        /*
+         * Insert all the defaulted attributes from the DTD especially
+         * namespaces
+         */
+        if ((ctxt->myDoc->intSubset != NULL) ||
+            (ctxt->myDoc->extSubset != NULL)) {
+            xmlCheckDefaultedAttributes(ctxt, name, prefix, atts);
+        }
 
-    /*
-     * process all the attributes whose name start with "xmlns"
-     */
-    if (atts != NULL) {
-        i = 0;
-	att = atts[i++];
-	value = atts[i++];
-	if (!ctxt->html) {
+        /*
+         * process all the attributes whose name start with "xmlns"
+         */
+        if (atts != NULL) {
+            i = 0;
+            att = atts[i++];
+            value = atts[i++];
 	    while ((att != NULL) && (value != NULL)) {
 		if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l') &&
 		    (att[3] == 'n') && (att[4] == 's'))
@@ -1688,30 +1688,30 @@
 		att = atts[i++];
 		value = atts[i++];
 	    }
-	}
-    }
+        }
 
-    /*
-     * Search the namespace, note that since the attributes have been
-     * processed, the local namespaces are available.
-     */
-    ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
-    if ((ns == NULL) && (parent != NULL))
-	ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
-    if ((prefix != NULL) && (ns == NULL)) {
-	ns = xmlNewNs(ret, NULL, prefix);
-	xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
-		     "Namespace prefix %s is not defined\n",
-		     prefix, NULL);
-    }
+        /*
+         * Search the namespace, note that since the attributes have been
+         * processed, the local namespaces are available.
+         */
+        ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
+        if ((ns == NULL) && (parent != NULL))
+            ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
+        if ((prefix != NULL) && (ns == NULL)) {
+            ns = xmlNewNs(ret, NULL, prefix);
+            xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
+                         "Namespace prefix %s is not defined\n",
+                         prefix, NULL);
+        }
 
-    /*
-     * set the namespace node, making sure that if the default namespace
-     * is unbound on a parent we simply keep it NULL
-     */
-    if ((ns != NULL) && (ns->href != NULL) &&
-	((ns->href[0] != 0) || (ns->prefix != NULL)))
-	xmlSetNs(ret, ns);
+        /*
+         * set the namespace node, making sure that if the default namespace
+         * is unbound on a parent we simply keep it NULL
+         */
+        if ((ns != NULL) && (ns->href != NULL) &&
+            ((ns->href[0] != 0) || (ns->prefix != NULL)))
+            xmlSetNs(ret, ns);
+    }
 
     /*
      * process all the other attributes
diff --git a/src/buf.c b/src/buf.c
index 8ad18a1..24368d3 100644
--- a/src/buf.c
+++ b/src/buf.c
@@ -1334,8 +1334,12 @@
 int
 xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
                       size_t base, size_t cur) {
-    if ((input == NULL) || (buf == NULL) || (buf->error))
+    if (input == NULL)
         return(-1);
+    if ((buf == NULL) || (buf->error)) {
+        input->base = input->cur = input->end = BAD_CAST "";
+        return(-1);
+    }
     CHECK_COMPAT(buf)
     input->base = &buf->content[base];
     input->cur = input->base + cur;
diff --git a/src/config.h.in b/src/config.h.in
index a751769..5f87036 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -1,5 +1,8 @@
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
+/* A form that will not confuse apibuild.py */
+#undef ATTRIBUTE_DESTRUCTOR
+
 /* Type cast for the gethostbyname() argument */
 #undef GETHOSTBYNAME_ARG_CAST
 
@@ -9,6 +12,9 @@
 /* Define to 1 if you have the <arpa/nameser.h> header file. */
 #undef HAVE_ARPA_NAMESER_H
 
+/* Define if __attribute__((destructor)) is accepted */
+#undef HAVE_ATTRIBUTE_DESTRUCTOR
+
 /* Whether struct sockaddr::__ss_family exists */
 #undef HAVE_BROKEN_SS_FAMILY
 
diff --git a/src/configure.ac b/src/configure.ac
index 09418af..a4c675b 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1,15 +1,20 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ([2.63])
-AC_INIT
+
+m4_define([MAJOR_VERSION], 2)
+m4_define([MINOR_VERSION], 9)
+m4_define([MICRO_VERSION], 10)
+
+AC_INIT([libxml2],[MAJOR_VERSION.MINOR_VERSION.MICRO_VERSION])
 AC_CONFIG_SRCDIR([entities.c])
 AC_CONFIG_HEADERS([config.h])
 AM_MAINTAINER_MODE([enable])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CANONICAL_HOST
 
-LIBXML_MAJOR_VERSION=2
-LIBXML_MINOR_VERSION=9
-LIBXML_MICRO_VERSION=10
+LIBXML_MAJOR_VERSION=MAJOR_VERSION
+LIBXML_MINOR_VERSION=MINOR_VERSION
+LIBXML_MICRO_VERSION=MICRO_VERSION
 LIBXML_MICRO_VERSION_SUFFIX=
 LIBXML_VERSION=$LIBXML_MAJOR_VERSION.$LIBXML_MINOR_VERSION.$LIBXML_MICRO_VERSION$LIBXML_MICRO_VERSION_SUFFIX
 LIBXML_VERSION_INFO=`expr $LIBXML_MAJOR_VERSION + $LIBXML_MINOR_VERSION`:$LIBXML_MICRO_VERSION:$LIBXML_MINOR_VERSION
@@ -50,7 +55,7 @@
 
 VERSION=${LIBXML_VERSION}
 
-AM_INIT_AUTOMAKE(libxml2, $VERSION)
+AM_INIT_AUTOMAKE([foreign])
 
 # Support silent build rules, requires at least automake-1.11. Disable
 # by either passing --disable-silent-rules to configure or passing V=1
@@ -641,6 +646,17 @@
       [Type cast for the send() function 2nd arg])
 fi
 
+dnl Checking whether __attribute__((destructor)) is accepted by the compiler
+AC_MSG_CHECKING([whether __attribute__((destructor)) is accepted])
+AC_TRY_COMPILE2([
+void __attribute__((destructor))
+f(void) {}], [], [
+  AC_MSG_RESULT(yes)
+  AC_DEFINE([HAVE_ATTRIBUTE_DESTRUCTOR], [1],[Define if __attribute__((destructor)) is accepted])
+  AC_DEFINE([ATTRIBUTE_DESTRUCTOR], [__attribute__((destructor))],[A form that will not confuse apibuild.py])],[
+  AC_MSG_RESULT(no)])
+
+
 dnl ***********************Checking for availability of IPv6*******************
 
 AC_MSG_CHECKING([whether to enable IPv6])
@@ -1503,8 +1519,8 @@
 
             AC_CHECK_HEADER(unicode/ucnv.h,
             AC_MSG_CHECKING(for icu)
-            AC_TRY_LINK([#include <unicode/ucnv.h>],[
-        UConverter *utf = ucnv_open("UTF-8", NULL);],[
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <unicode/ucnv.h>]], [[
+        UConverter *utf = ucnv_open("UTF-8", NULL);]])],[
                 AC_MSG_RESULT(yes)
                 have_libicu=yes],[
                 AC_MSG_RESULT(no)
@@ -1515,8 +1531,8 @@
                 LDFLAGS="${LDFLAGS} ${ICU_LIBS}"
                 LIBS="${LIBS} -licucore"
 
-                AC_TRY_LINK([#include <unicode/ucnv.h>],[
-        UConverter *utf = ucnv_open("UTF-8", NULL);],[
+                AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <unicode/ucnv.h>]], [[
+        UConverter *utf = ucnv_open("UTF-8", NULL);]])],[
                     AC_MSG_RESULT(yes)
                     have_libicu=yes
                     ICU_LIBS="${ICU_LIBS} -licucore"
@@ -1704,7 +1720,7 @@
 ln -s $srcdir/Copyright COPYING
 
 # keep on one line for cygwin c.f. #130896
-AC_CONFIG_FILES([libxml2.spec:libxml.spec.in Makefile include/Makefile include/libxml/Makefile doc/Makefile doc/examples/Makefile doc/devhelp/Makefile example/Makefile python/Makefile python/tests/Makefile xstc/Makefile include/libxml/xmlversion.h libxml-2.0.pc libxml-2.0-uninstalled.pc libxml2-config.cmake])
+AC_CONFIG_FILES([libxml2.spec:libxml.spec.in Makefile include/Makefile include/libxml/Makefile doc/Makefile doc/examples/Makefile doc/devhelp/Makefile example/Makefile fuzz/Makefile python/Makefile python/tests/Makefile xstc/Makefile include/libxml/xmlversion.h libxml-2.0.pc libxml-2.0-uninstalled.pc libxml2-config.cmake])
 AC_CONFIG_FILES([python/setup.py], [chmod +x python/setup.py])
 AC_CONFIG_FILES([xml2-config], [chmod +x xml2-config])
 AC_OUTPUT
diff --git a/src/encoding.c b/src/encoding.c
index 65c5889..c34aca4 100644
--- a/src/encoding.c
+++ b/src/encoding.c
@@ -170,7 +170,7 @@
  * Returns 0 if success, or -1 otherwise
  * The value of @inlen after return is the number of octets consumed
  *     if the return value is positive, else unpredictable.
- * The value of @outlen after return is the number of octets consumed.
+ * The value of @outlen after return is the number of octets produced.
  */
 static int
 asciiToUTF8(unsigned char* out, int *outlen,
@@ -217,7 +217,7 @@
  * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
  * The value of @inlen after return is the number of octets consumed
  *     if the return value is positive, else unpredictable.
- * The value of @outlen after return is the number of octets consumed.
+ * The value of @outlen after return is the number of octets produced.
  */
 static int
 UTF8Toascii(unsigned char* out, int *outlen,
@@ -301,7 +301,7 @@
  * Returns the number of bytes written if success, or -1 otherwise
  * The value of @inlen after return is the number of octets consumed
  *     if the return value is positive, else unpredictable.
- * The value of @outlen after return is the number of octets consumed.
+ * The value of @outlen after return is the number of octets produced.
  */
 int
 isolat1ToUTF8(unsigned char* out, int *outlen,
@@ -396,7 +396,7 @@
            or -1 otherwise
  * The value of @inlen after return is the number of octets consumed
  *     if the return value is positive, else unpredictable.
- * The value of @outlen after return is the number of octets consumed.
+ * The value of @outlen after return is the number of octets produced.
  */
 int
 UTF8Toisolat1(unsigned char* out, int *outlen,
@@ -496,13 +496,18 @@
 {
     unsigned char* outstart = out;
     const unsigned char* processed = inb;
-    unsigned char* outend = out + *outlen;
+    unsigned char* outend;
     unsigned short* in = (unsigned short*) inb;
     unsigned short* inend;
     unsigned int c, d, inlen;
     unsigned char *tmp;
     int bits;
 
+    if (*outlen == 0) {
+        *inlenb = 0;
+        return(0);
+    }
+    outend = out + *outlen;
     if ((*inlenb % 2) == 1)
         (*inlenb)--;
     inlen = *inlenb / 2;
@@ -1784,7 +1789,7 @@
  * @cd:		iconv converter data structure
  * @out:  a pointer to an array of bytes to store the result
  * @outlen:  the length of @out
- * @in:  a pointer to an array of ISO Latin 1 chars
+ * @in:  a pointer to an array of input bytes
  * @inlen:  the length of @in
  *
  * Returns 0 if success, or
@@ -1795,7 +1800,7 @@
  *
  * The value of @inlen after return is the number of octets consumed
  *     as the return value is positive, else unpredictable.
- * The value of @outlen after return is the number of octets consumed.
+ * The value of @outlen after return is the number of octets produced.
  */
 static int
 xmlIconvWrapper(iconv_t cd, unsigned char *out, int *outlen,
@@ -1851,7 +1856,7 @@
  * @toUnicode : non-zero if toUnicode. 0 otherwise.
  * @out:  a pointer to an array of bytes to store the result
  * @outlen:  the length of @out
- * @in:  a pointer to an array of ISO Latin 1 chars
+ * @in:  a pointer to an array of input bytes
  * @inlen:  the length of @in
  * @flush: if true, indicates end of input
  *
@@ -1863,7 +1868,7 @@
  *
  * The value of @inlen after return is the number of octets consumed
  *     as the return value is positive, else unpredictable.
- * The value of @outlen after return is the number of octets consumed.
+ * The value of @outlen after return is the number of octets produced.
  */
 static int
 xmlUconvWrapper(uconv_t *cd, int toUnicode, unsigned char *out, int *outlen,
@@ -1912,6 +1917,25 @@
  *									*
  ************************************************************************/
 
+/**
+ * xmlEncInputChunk:
+ * @handler:  encoding handler
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of input bytes
+ * @inlen:  the length of @in
+ * @flush:  flush (ICU-related)
+ *
+ * Returns 0 if success, or
+ *     -1 by lack of space, or
+ *     -2 if the transcoding fails (for *in is not valid utf8 string or
+ *        the result of transformation can't fit into the encoding we want), or
+ *     -3 if there the last byte can't form a single output char.
+ *
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is 0, else unpredictable.
+ * The value of @outlen after return is the number of octets produced.
+ */
 static int
 xmlEncInputChunk(xmlCharEncodingHandler *handler, unsigned char *out,
                  int *outlen, const unsigned char *in, int *inlen, int flush) {
@@ -1920,6 +1944,8 @@
 
     if (handler->input != NULL) {
         ret = handler->input(out, outlen, in, inlen);
+        if (ret > 0)
+           ret = 0;
     }
 #ifdef LIBXML_ICONV_ENABLED
     else if (handler->iconv_in != NULL) {
@@ -1941,7 +1967,25 @@
     return(ret);
 }
 
-/* Returns -4 if no output function was found. */
+/**
+ * xmlEncOutputChunk:
+ * @handler:  encoding handler
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of input bytes
+ * @inlen:  the length of @in
+ *
+ * Returns 0 if success, or
+ *     -1 by lack of space, or
+ *     -2 if the transcoding fails (for *in is not valid utf8 string or
+ *        the result of transformation can't fit into the encoding we want), or
+ *     -3 if there the last byte can't form a single output char.
+ *     -4 if no output function was found.
+ *
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is 0, else unpredictable.
+ * The value of @outlen after return is the number of octets produced.
+ */
 static int
 xmlEncOutputChunk(xmlCharEncodingHandler *handler, unsigned char *out,
                   int *outlen, const unsigned char *in, int *inlen) {
@@ -1949,6 +1993,8 @@
 
     if (handler->output != NULL) {
         ret = handler->output(out, outlen, in, inlen);
+        if (ret > 0)
+           ret = 0;
     }
 #ifdef LIBXML_ICONV_ENABLED
     else if (handler->iconv_out != NULL) {
@@ -2054,7 +2100,7 @@
      */
     if (ret == -3) ret = 0;
     if (ret == -1) ret = 0;
-    return(ret);
+    return(written ? written : ret);
 }
 
 /**
@@ -2184,7 +2230,7 @@
      */
     if (ret == -3) ret = 0;
     if (ret == -1) ret = 0;
-    return(ret);
+    return(c_out ? c_out : ret);
 }
 
 /**
@@ -2394,7 +2440,7 @@
 {
     int ret;
     size_t written;
-    size_t writtentot = 0;
+    int writtentot = 0;
     size_t toconv;
     int c_in;
     int c_out;
@@ -2427,7 +2473,7 @@
 	xmlGenericError(xmlGenericErrorContext,
 		"initialized encoder\n");
 #endif
-        return(0);
+        return(c_out);
     }
 
     /*
@@ -2540,7 +2586,7 @@
             goto retry;
 	}
     }
-    return(ret);
+    return(writtentot ? writtentot : ret);
 }
 #endif
 
@@ -2705,7 +2751,7 @@
             goto retry;
 	}
     }
-    return(ret);
+    return(writtentot ? writtentot : ret);
 }
 
 /**
diff --git a/src/error.c b/src/error.c
index 3e41e17..9ff1c2b 100644
--- a/src/error.c
+++ b/src/error.c
@@ -557,6 +557,7 @@
 	 * of the usual "base" (doc->URL) for the node (bug 152623).
 	 */
         xmlNodePtr prev = baseptr;
+        char *href = NULL;
 	int inclcount = 0;
 	while (prev != NULL) {
 	    if (prev->prev == NULL)
@@ -564,21 +565,20 @@
 	    else {
 	        prev = prev->prev;
 		if (prev->type == XML_XINCLUDE_START) {
-		    if (--inclcount < 0)
-		        break;
+		    if (inclcount > 0) {
+                        --inclcount;
+                    } else {
+                        href = (char *) xmlGetProp(prev, BAD_CAST "href");
+                        if (href != NULL)
+		            break;
+                    }
 		} else if (prev->type == XML_XINCLUDE_END)
 		    inclcount++;
 	    }
 	}
-	if (prev != NULL) {
-	    if (prev->type == XML_XINCLUDE_START) {
-		prev->type = XML_ELEMENT_NODE;
-		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
-		prev->type = XML_XINCLUDE_START;
-	    } else {
-		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
-	    }
-	} else
+        if (href != NULL)
+            to->file = href;
+	else
 #endif
 	    to->file = (char *) xmlStrdup(baseptr->doc->URL);
 	if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) {
diff --git a/src/fuzz/Makefile.am b/src/fuzz/Makefile.am
new file mode 100644
index 0000000..49b9554
--- /dev/null
+++ b/src/fuzz/Makefile.am
@@ -0,0 +1,138 @@
+AUTOMAKE_OPTIONS = -Wno-syntax
+EXTRA_PROGRAMS = genSeed html regexp schema uri xml xpath
+check_PROGRAMS = testFuzzer
+CLEANFILES = $(EXTRA_PROGRAMS)
+AM_CPPFLAGS = -I$(top_srcdir)/include
+DEPENDENCIES = $(top_builddir)/libxml2.la
+LDADD = $(STATIC_BINARIES) $(top_builddir)/libxml2.la $(THREAD_LIBS) $(Z_LIBS) $(LZMA_LIBS) $(ICONV_LIBS) $(M_LIBS) $(WIN32_EXTRA_LIBADD)
+
+XML_MAX_LEN = 80000
+# Single quotes to avoid wildcard expansion by the shell
+XML_SEED_CORPUS_SRC = \
+    '$(top_srcdir)/test/*' \
+    '$(top_srcdir)/test/errors/*.xml' \
+    '$(top_srcdir)/test/errors10/*.xml' \
+    '$(top_srcdir)/test/namespaces/*' \
+    '$(top_srcdir)/test/valid/*.xml' \
+    '$(top_srcdir)/test/VC/*' \
+    '$(top_srcdir)/test/VCM/*' \
+    '$(top_srcdir)/test/XInclude/docs/*' \
+    '$(top_srcdir)/test/xmlid/*'
+
+testFuzzer_SOURCES = testFuzzer.c fuzz.c
+
+.PHONY: tests corpus clean-corpus
+
+corpus: seed/html.stamp seed/schema.stamp seed/xml.stamp seed/xpath.stamp
+
+tests: testFuzzer$(EXEEXT) corpus
+	@echo "## Running fuzzer tests"
+	@./testFuzzer$(EXEEXT)
+
+clean-corpus:
+	rm -rf seed/html.stamp seed/html
+	rm -rf seed/schema.stamp seed/schema
+	rm -rf seed/xml.stamp seed/xml
+	rm -rf seed/xpath.stamp seed/xpath
+
+# Seed corpus
+
+genSeed_SOURCES = genSeed.c fuzz.c
+
+# XML fuzzer
+
+seed/xml.stamp: genSeed$(EXEEXT)
+	@mkdir -p seed/xml
+	@./genSeed$(EXEEXT) xml $(XML_SEED_CORPUS_SRC)
+	@touch seed/xml.stamp
+
+xml_SOURCES = xml.c fuzz.c
+xml_LDFLAGS = -fsanitize=fuzzer
+
+fuzz-xml: xml$(EXEEXT) seed/xml.stamp
+	@mkdir -p corpus/xml
+	./xml$(EXEEXT) \
+	    -dict=xml.dict \
+	    -max_len=$(XML_MAX_LEN) \
+	    -timeout=20 \
+	    corpus/xml seed/xml
+
+# HTML fuzzer
+
+seed/html.stamp: genSeed$(EXEEXT)
+	@mkdir -p seed/html
+	@./genSeed$(EXEEXT) html '$(top_srcdir)/test/HTML/*'
+	@touch seed/html.stamp
+
+html_SOURCES = html.c fuzz.c
+html_LDFLAGS = -fsanitize=fuzzer
+
+fuzz-html: html$(EXEEXT) seed/html.stamp
+	@mkdir -p corpus/html
+	./html$(EXEEXT) \
+	    -dict=html.dict \
+	    -max_len=1000000 \
+	    -timeout=20 \
+	    corpus/html seed/html
+
+# Regexp fuzzer
+
+regexp_SOURCES = regexp.c fuzz.c
+regexp_LDFLAGS = -fsanitize=fuzzer
+
+fuzz-regexp: regexp$(EXEEXT)
+	@mkdir -p corpus/regexp
+	./regexp$(EXEEXT) \
+	    -dict=regexp.dict \
+	    -max_len=200 \
+	    -timeout=5 \
+	    corpus/regexp $(srcdir)/seed/regexp
+
+# URI fuzzer
+
+uri_SOURCES = uri.c fuzz.c
+uri_LDFLAGS = -fsanitize=fuzzer
+
+fuzz-uri: uri$(EXEEXT)
+	@mkdir -p corpus/uri
+	./uri$(EXEEXT) \
+	    -max_len=10000 \
+	    -timeout=5 \
+	    corpus/uri $(srcdir)/seed/uri
+
+# XML Schema fuzzer
+
+seed/schema.stamp: genSeed$(EXEEXT)
+	@mkdir -p seed/schema
+	@./genSeed$(EXEEXT) schema '$(top_srcdir)/test/schemas/*.xsd'
+	@touch seed/schema.stamp
+
+schema_SOURCES = schema.c fuzz.c
+schema_LDFLAGS = -fsanitize=fuzzer
+
+fuzz-schema: schema$(EXEEXT) seed/schema.stamp
+	@mkdir -p corpus/schema
+	./schema$(EXEEXT) \
+	    -dict=schema.dict \
+	    -max_len=$(XML_MAX_LEN) \
+	    -timeout=20 \
+	    corpus/schema seed/schema
+
+# XPath fuzzer
+
+seed/xpath.stamp: genSeed$(EXEEXT)
+	@mkdir -p seed/xpath
+	@./genSeed$(EXEEXT) xpath "$(top_builddir)/test/XPath"
+	@touch seed/xpath.stamp
+
+xpath_SOURCES = xpath.c fuzz.c
+xpath_LDFLAGS = -fsanitize=fuzzer
+
+fuzz-xpath: xpath$(EXEEXT) seed/xpath.stamp
+	@mkdir -p corpus/xpath
+	./xpath$(EXEEXT) \
+	    -dict=xpath.dict \
+	    -max_len=10000 \
+	    -timeout=20 \
+	    corpus/xpath seed/xpath
+
diff --git a/src/fuzz/Makefile.in b/src/fuzz/Makefile.in
new file mode 100644
index 0000000..4dd6eba
--- /dev/null
+++ b/src/fuzz/Makefile.in
@@ -0,0 +1,969 @@
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = genSeed$(EXEEXT) html$(EXEEXT) regexp$(EXEEXT) \
+	schema$(EXEEXT) uri$(EXEEXT) xml$(EXEEXT) xpath$(EXEEXT)
+check_PROGRAMS = testFuzzer$(EXEEXT)
+subdir = fuzz
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_genSeed_OBJECTS = genSeed.$(OBJEXT) fuzz.$(OBJEXT)
+genSeed_OBJECTS = $(am_genSeed_OBJECTS)
+genSeed_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+genSeed_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	$(top_builddir)/libxml2.la $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+am_html_OBJECTS = html.$(OBJEXT) fuzz.$(OBJEXT)
+html_OBJECTS = $(am_html_OBJECTS)
+html_LDADD = $(LDADD)
+html_DEPENDENCIES = $(am__DEPENDENCIES_1) $(top_builddir)/libxml2.la \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+html_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(html_LDFLAGS) $(LDFLAGS) -o $@
+am_regexp_OBJECTS = regexp.$(OBJEXT) fuzz.$(OBJEXT)
+regexp_OBJECTS = $(am_regexp_OBJECTS)
+regexp_LDADD = $(LDADD)
+regexp_DEPENDENCIES = $(am__DEPENDENCIES_1) $(top_builddir)/libxml2.la \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+regexp_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(regexp_LDFLAGS) $(LDFLAGS) -o $@
+am_schema_OBJECTS = schema.$(OBJEXT) fuzz.$(OBJEXT)
+schema_OBJECTS = $(am_schema_OBJECTS)
+schema_LDADD = $(LDADD)
+schema_DEPENDENCIES = $(am__DEPENDENCIES_1) $(top_builddir)/libxml2.la \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+schema_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(schema_LDFLAGS) $(LDFLAGS) -o $@
+am_testFuzzer_OBJECTS = testFuzzer.$(OBJEXT) fuzz.$(OBJEXT)
+testFuzzer_OBJECTS = $(am_testFuzzer_OBJECTS)
+testFuzzer_LDADD = $(LDADD)
+testFuzzer_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+	$(top_builddir)/libxml2.la $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1)
+am_uri_OBJECTS = uri.$(OBJEXT) fuzz.$(OBJEXT)
+uri_OBJECTS = $(am_uri_OBJECTS)
+uri_LDADD = $(LDADD)
+uri_DEPENDENCIES = $(am__DEPENDENCIES_1) $(top_builddir)/libxml2.la \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+uri_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(uri_LDFLAGS) $(LDFLAGS) -o $@
+am_xml_OBJECTS = xml.$(OBJEXT) fuzz.$(OBJEXT)
+xml_OBJECTS = $(am_xml_OBJECTS)
+xml_LDADD = $(LDADD)
+xml_DEPENDENCIES = $(am__DEPENDENCIES_1) $(top_builddir)/libxml2.la \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+xml_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(xml_LDFLAGS) $(LDFLAGS) -o $@
+am_xpath_OBJECTS = xpath.$(OBJEXT) fuzz.$(OBJEXT)
+xpath_OBJECTS = $(am_xpath_OBJECTS)
+xpath_LDADD = $(LDADD)
+xpath_DEPENDENCIES = $(am__DEPENDENCIES_1) $(top_builddir)/libxml2.la \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+xpath_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(xpath_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/fuzz.Po ./$(DEPDIR)/genSeed.Po \
+	./$(DEPDIR)/html.Po ./$(DEPDIR)/regexp.Po \
+	./$(DEPDIR)/schema.Po ./$(DEPDIR)/testFuzzer.Po \
+	./$(DEPDIR)/uri.Po ./$(DEPDIR)/xml.Po ./$(DEPDIR)/xpath.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(genSeed_SOURCES) $(html_SOURCES) $(regexp_SOURCES) \
+	$(schema_SOURCES) $(testFuzzer_SOURCES) $(uri_SOURCES) \
+	$(xml_SOURCES) $(xpath_SOURCES)
+DIST_SOURCES = $(genSeed_SOURCES) $(html_SOURCES) $(regexp_SOURCES) \
+	$(schema_SOURCES) $(testFuzzer_SOURCES) $(uri_SOURCES) \
+	$(xml_SOURCES) $(xpath_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASE_THREAD_LIBS = @BASE_THREAD_LIBS@
+C14N_OBJ = @C14N_OBJ@
+CATALOG_OBJ = @CATALOG_OBJ@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+CYGWIN_EXTRA_LDFLAGS = @CYGWIN_EXTRA_LDFLAGS@
+CYGWIN_EXTRA_PYTHON_LIBADD = @CYGWIN_EXTRA_PYTHON_LIBADD@
+DEBUG_OBJ = @DEBUG_OBJ@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOCB_OBJ = @DOCB_OBJ@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXTRA_CFLAGS = @EXTRA_CFLAGS@
+FGREP = @FGREP@
+FTP_OBJ = @FTP_OBJ@
+GREP = @GREP@
+HAVE_ISINF = @HAVE_ISINF@
+HAVE_ISNAN = @HAVE_ISNAN@
+HTML_DIR = @HTML_DIR@
+HTML_OBJ = @HTML_OBJ@
+HTTP_OBJ = @HTTP_OBJ@
+ICONV_LIBS = @ICONV_LIBS@
+ICU_CFLAGS = @ICU_CFLAGS@
+ICU_LIBS = @ICU_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBXML_MAJOR_VERSION = @LIBXML_MAJOR_VERSION@
+LIBXML_MICRO_VERSION = @LIBXML_MICRO_VERSION@
+LIBXML_MINOR_VERSION = @LIBXML_MINOR_VERSION@
+LIBXML_VERSION = @LIBXML_VERSION@
+LIBXML_VERSION_EXTRA = @LIBXML_VERSION_EXTRA@
+LIBXML_VERSION_INFO = @LIBXML_VERSION_INFO@
+LIBXML_VERSION_NUMBER = @LIBXML_VERSION_NUMBER@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MODULE_EXTENSION = @MODULE_EXTENSION@
+MODULE_PLATFORM_LIBS = @MODULE_PLATFORM_LIBS@
+MV = @MV@
+M_LIBS = @M_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PYTHON = @PYTHON@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_SITE_PACKAGES = @PYTHON_SITE_PACKAGES@
+PYTHON_SUBDIR = @PYTHON_SUBDIR@
+PYTHON_TESTS = @PYTHON_TESTS@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RDL_LIBS = @RDL_LIBS@
+READER_TEST = @READER_TEST@
+RELDATE = @RELDATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STATIC_BINARIES = @STATIC_BINARIES@
+STRIP = @STRIP@
+TAR = @TAR@
+TEST_C14N = @TEST_C14N@
+TEST_CATALOG = @TEST_CATALOG@
+TEST_DEBUG = @TEST_DEBUG@
+TEST_HTML = @TEST_HTML@
+TEST_MODULES = @TEST_MODULES@
+TEST_PATTERN = @TEST_PATTERN@
+TEST_PHTML = @TEST_PHTML@
+TEST_PUSH = @TEST_PUSH@
+TEST_REGEXPS = @TEST_REGEXPS@
+TEST_SAX = @TEST_SAX@
+TEST_SCHEMAS = @TEST_SCHEMAS@
+TEST_SCHEMATRON = @TEST_SCHEMATRON@
+TEST_THREADS = @TEST_THREADS@
+TEST_VALID = @TEST_VALID@
+TEST_VTIME = @TEST_VTIME@
+TEST_XINCLUDE = @TEST_XINCLUDE@
+TEST_XPATH = @TEST_XPATH@
+TEST_XPTR = @TEST_XPTR@
+THREAD_CFLAGS = @THREAD_CFLAGS@
+THREAD_LIBS = @THREAD_LIBS@
+VERSION = @VERSION@
+VERSION_SCRIPT_FLAGS = @VERSION_SCRIPT_FLAGS@
+WGET = @WGET@
+WIN32_EXTRA_LDFLAGS = @WIN32_EXTRA_LDFLAGS@
+WIN32_EXTRA_LIBADD = @WIN32_EXTRA_LIBADD@
+WIN32_EXTRA_PYTHON_LIBADD = @WIN32_EXTRA_PYTHON_LIBADD@
+WITH_C14N = @WITH_C14N@
+WITH_CATALOG = @WITH_CATALOG@
+WITH_DEBUG = @WITH_DEBUG@
+WITH_DOCB = @WITH_DOCB@
+WITH_FTP = @WITH_FTP@
+WITH_HTML = @WITH_HTML@
+WITH_HTTP = @WITH_HTTP@
+WITH_ICONV = @WITH_ICONV@
+WITH_ICU = @WITH_ICU@
+WITH_ISO8859X = @WITH_ISO8859X@
+WITH_LEGACY = @WITH_LEGACY@
+WITH_LZMA = @WITH_LZMA@
+WITH_MEM_DEBUG = @WITH_MEM_DEBUG@
+WITH_MODULES = @WITH_MODULES@
+WITH_OUTPUT = @WITH_OUTPUT@
+WITH_PATTERN = @WITH_PATTERN@
+WITH_PUSH = @WITH_PUSH@
+WITH_READER = @WITH_READER@
+WITH_REGEXPS = @WITH_REGEXPS@
+WITH_RUN_DEBUG = @WITH_RUN_DEBUG@
+WITH_SAX1 = @WITH_SAX1@
+WITH_SCHEMAS = @WITH_SCHEMAS@
+WITH_SCHEMATRON = @WITH_SCHEMATRON@
+WITH_THREADS = @WITH_THREADS@
+WITH_THREAD_ALLOC = @WITH_THREAD_ALLOC@
+WITH_TREE = @WITH_TREE@
+WITH_TRIO = @WITH_TRIO@
+WITH_VALID = @WITH_VALID@
+WITH_WRITER = @WITH_WRITER@
+WITH_XINCLUDE = @WITH_XINCLUDE@
+WITH_XPATH = @WITH_XPATH@
+WITH_XPTR = @WITH_XPTR@
+WITH_ZLIB = @WITH_ZLIB@
+XINCLUDE_OBJ = @XINCLUDE_OBJ@
+XMLLINT = @XMLLINT@
+XML_CFLAGS = @XML_CFLAGS@
+XML_INCLUDEDIR = @XML_INCLUDEDIR@
+XML_LIBDIR = @XML_LIBDIR@
+XML_LIBS = @XML_LIBS@
+XML_LIBTOOLLIBS = @XML_LIBTOOLLIBS@
+XML_PRIVATE_LIBS = @XML_PRIVATE_LIBS@
+XPATH_OBJ = @XPATH_OBJ@
+XPTR_OBJ = @XPTR_OBJ@
+XSLTPROC = @XSLTPROC@
+Z_CFLAGS = @Z_CFLAGS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = -Wno-syntax
+CLEANFILES = $(EXTRA_PROGRAMS)
+AM_CPPFLAGS = -I$(top_srcdir)/include
+DEPENDENCIES = $(top_builddir)/libxml2.la
+LDADD = $(STATIC_BINARIES) $(top_builddir)/libxml2.la $(THREAD_LIBS) $(Z_LIBS) $(LZMA_LIBS) $(ICONV_LIBS) $(M_LIBS) $(WIN32_EXTRA_LIBADD)
+XML_MAX_LEN = 80000
+# Single quotes to avoid wildcard expansion by the shell
+XML_SEED_CORPUS_SRC = \
+    '$(top_srcdir)/test/*' \
+    '$(top_srcdir)/test/errors/*.xml' \
+    '$(top_srcdir)/test/errors10/*.xml' \
+    '$(top_srcdir)/test/namespaces/*' \
+    '$(top_srcdir)/test/valid/*.xml' \
+    '$(top_srcdir)/test/VC/*' \
+    '$(top_srcdir)/test/VCM/*' \
+    '$(top_srcdir)/test/XInclude/docs/*' \
+    '$(top_srcdir)/test/xmlid/*'
+
+testFuzzer_SOURCES = testFuzzer.c fuzz.c
+
+# Seed corpus
+genSeed_SOURCES = genSeed.c fuzz.c
+xml_SOURCES = xml.c fuzz.c
+xml_LDFLAGS = -fsanitize=fuzzer
+html_SOURCES = html.c fuzz.c
+html_LDFLAGS = -fsanitize=fuzzer
+
+# Regexp fuzzer
+regexp_SOURCES = regexp.c fuzz.c
+regexp_LDFLAGS = -fsanitize=fuzzer
+
+# URI fuzzer
+uri_SOURCES = uri.c fuzz.c
+uri_LDFLAGS = -fsanitize=fuzzer
+schema_SOURCES = schema.c fuzz.c
+schema_LDFLAGS = -fsanitize=fuzzer
+xpath_SOURCES = xpath.c fuzz.c
+xpath_LDFLAGS = -fsanitize=fuzzer
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign fuzz/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign fuzz/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+genSeed$(EXEEXT): $(genSeed_OBJECTS) $(genSeed_DEPENDENCIES) $(EXTRA_genSeed_DEPENDENCIES) 
+	@rm -f genSeed$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(genSeed_OBJECTS) $(genSeed_LDADD) $(LIBS)
+
+html$(EXEEXT): $(html_OBJECTS) $(html_DEPENDENCIES) $(EXTRA_html_DEPENDENCIES) 
+	@rm -f html$(EXEEXT)
+	$(AM_V_CCLD)$(html_LINK) $(html_OBJECTS) $(html_LDADD) $(LIBS)
+
+regexp$(EXEEXT): $(regexp_OBJECTS) $(regexp_DEPENDENCIES) $(EXTRA_regexp_DEPENDENCIES) 
+	@rm -f regexp$(EXEEXT)
+	$(AM_V_CCLD)$(regexp_LINK) $(regexp_OBJECTS) $(regexp_LDADD) $(LIBS)
+
+schema$(EXEEXT): $(schema_OBJECTS) $(schema_DEPENDENCIES) $(EXTRA_schema_DEPENDENCIES) 
+	@rm -f schema$(EXEEXT)
+	$(AM_V_CCLD)$(schema_LINK) $(schema_OBJECTS) $(schema_LDADD) $(LIBS)
+
+testFuzzer$(EXEEXT): $(testFuzzer_OBJECTS) $(testFuzzer_DEPENDENCIES) $(EXTRA_testFuzzer_DEPENDENCIES) 
+	@rm -f testFuzzer$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(testFuzzer_OBJECTS) $(testFuzzer_LDADD) $(LIBS)
+
+uri$(EXEEXT): $(uri_OBJECTS) $(uri_DEPENDENCIES) $(EXTRA_uri_DEPENDENCIES) 
+	@rm -f uri$(EXEEXT)
+	$(AM_V_CCLD)$(uri_LINK) $(uri_OBJECTS) $(uri_LDADD) $(LIBS)
+
+xml$(EXEEXT): $(xml_OBJECTS) $(xml_DEPENDENCIES) $(EXTRA_xml_DEPENDENCIES) 
+	@rm -f xml$(EXEEXT)
+	$(AM_V_CCLD)$(xml_LINK) $(xml_OBJECTS) $(xml_LDADD) $(LIBS)
+
+xpath$(EXEEXT): $(xpath_OBJECTS) $(xpath_DEPENDENCIES) $(EXTRA_xpath_DEPENDENCIES) 
+	@rm -f xpath$(EXEEXT)
+	$(AM_V_CCLD)$(xpath_LINK) $(xpath_OBJECTS) $(xpath_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fuzz.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genSeed.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/html.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regexp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/schema.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testFuzzer.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uri.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xpath.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+	@$(MKDIR_P) $(@D)
+	@echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+		-rm -f ./$(DEPDIR)/fuzz.Po
+	-rm -f ./$(DEPDIR)/genSeed.Po
+	-rm -f ./$(DEPDIR)/html.Po
+	-rm -f ./$(DEPDIR)/regexp.Po
+	-rm -f ./$(DEPDIR)/schema.Po
+	-rm -f ./$(DEPDIR)/testFuzzer.Po
+	-rm -f ./$(DEPDIR)/uri.Po
+	-rm -f ./$(DEPDIR)/xml.Po
+	-rm -f ./$(DEPDIR)/xpath.Po
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+		-rm -f ./$(DEPDIR)/fuzz.Po
+	-rm -f ./$(DEPDIR)/genSeed.Po
+	-rm -f ./$(DEPDIR)/html.Po
+	-rm -f ./$(DEPDIR)/regexp.Po
+	-rm -f ./$(DEPDIR)/schema.Po
+	-rm -f ./$(DEPDIR)/testFuzzer.Po
+	-rm -f ./$(DEPDIR)/uri.Po
+	-rm -f ./$(DEPDIR)/xml.Po
+	-rm -f ./$(DEPDIR)/xpath.Po
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+.PHONY: tests corpus clean-corpus
+
+corpus: seed/html.stamp seed/schema.stamp seed/xml.stamp seed/xpath.stamp
+
+tests: testFuzzer$(EXEEXT) corpus
+	@echo "## Running fuzzer tests"
+	@./testFuzzer$(EXEEXT)
+
+clean-corpus:
+	rm -rf seed/html.stamp seed/html
+	rm -rf seed/schema.stamp seed/schema
+	rm -rf seed/xml.stamp seed/xml
+	rm -rf seed/xpath.stamp seed/xpath
+
+# XML fuzzer
+
+seed/xml.stamp: genSeed$(EXEEXT)
+	@mkdir -p seed/xml
+	@./genSeed$(EXEEXT) xml $(XML_SEED_CORPUS_SRC)
+	@touch seed/xml.stamp
+
+fuzz-xml: xml$(EXEEXT) seed/xml.stamp
+	@mkdir -p corpus/xml
+	./xml$(EXEEXT) \
+	    -dict=xml.dict \
+	    -max_len=$(XML_MAX_LEN) \
+	    -timeout=20 \
+	    corpus/xml seed/xml
+
+# HTML fuzzer
+
+seed/html.stamp: genSeed$(EXEEXT)
+	@mkdir -p seed/html
+	@./genSeed$(EXEEXT) html '$(top_srcdir)/test/HTML/*'
+	@touch seed/html.stamp
+
+fuzz-html: html$(EXEEXT) seed/html.stamp
+	@mkdir -p corpus/html
+	./html$(EXEEXT) \
+	    -dict=html.dict \
+	    -max_len=1000000 \
+	    -timeout=20 \
+	    corpus/html seed/html
+
+fuzz-regexp: regexp$(EXEEXT)
+	@mkdir -p corpus/regexp
+	./regexp$(EXEEXT) \
+	    -dict=regexp.dict \
+	    -max_len=200 \
+	    -timeout=5 \
+	    corpus/regexp $(srcdir)/seed/regexp
+
+fuzz-uri: uri$(EXEEXT)
+	@mkdir -p corpus/uri
+	./uri$(EXEEXT) \
+	    -max_len=10000 \
+	    -timeout=5 \
+	    corpus/uri $(srcdir)/seed/uri
+
+# XML Schema fuzzer
+
+seed/schema.stamp: genSeed$(EXEEXT)
+	@mkdir -p seed/schema
+	@./genSeed$(EXEEXT) schema '$(top_srcdir)/test/schemas/*.xsd'
+	@touch seed/schema.stamp
+
+fuzz-schema: schema$(EXEEXT) seed/schema.stamp
+	@mkdir -p corpus/schema
+	./schema$(EXEEXT) \
+	    -dict=schema.dict \
+	    -max_len=$(XML_MAX_LEN) \
+	    -timeout=20 \
+	    corpus/schema seed/schema
+
+# XPath fuzzer
+
+seed/xpath.stamp: genSeed$(EXEEXT)
+	@mkdir -p seed/xpath
+	@./genSeed$(EXEEXT) xpath "$(top_builddir)/test/XPath"
+	@touch seed/xpath.stamp
+
+fuzz-xpath: xpath$(EXEEXT) seed/xpath.stamp
+	@mkdir -p corpus/xpath
+	./xpath$(EXEEXT) \
+	    -dict=xpath.dict \
+	    -max_len=10000 \
+	    -timeout=20 \
+	    corpus/xpath seed/xpath
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/fuzz/README b/src/fuzz/README
new file mode 100644
index 0000000..f675ad8
--- /dev/null
+++ b/src/fuzz/README
@@ -0,0 +1,19 @@
+libFuzzer instructions for libxml2
+==================================
+
+Set compiler and options:
+
+    export CC=clang
+    export CFLAGS="-g -fsanitize=fuzzer-no-link,address,undefined \
+        -fno-sanitize-recover=all \
+        -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
+
+Build libxml2 with instrumentation:
+
+    ./configure --without-python
+    make
+
+Run fuzzers:
+
+    make -C fuzz fuzz-xml
+
diff --git a/src/fuzz/fuzz.c b/src/fuzz/fuzz.c
new file mode 100644
index 0000000..b5dfa18
--- /dev/null
+++ b/src/fuzz/fuzz.c
@@ -0,0 +1,349 @@
+/*
+ * fuzz.c: Common functions for fuzzing.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <libxml/hash.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/tree.h>
+#include <libxml/xmlIO.h>
+#include "fuzz.h"
+
+typedef struct {
+    const char *data;
+    size_t size;
+} xmlFuzzEntityInfo;
+
+/* Single static instance for now */
+static struct {
+    /* Original data */
+    const char *data;
+    size_t size;
+
+    /* Remaining data */
+    const char *ptr;
+    size_t remaining;
+
+    /* Buffer for unescaped strings */
+    char *outBuf;
+    char *outPtr; /* Free space at end of buffer */
+
+    xmlHashTablePtr entities; /* Maps URLs to xmlFuzzEntityInfos */
+
+    /* The first entity is the main entity. */
+    const char *mainUrl;
+    xmlFuzzEntityInfo *mainEntity;
+} fuzzData;
+
+/**
+ * xmlFuzzErrorFunc:
+ *
+ * An error function that simply discards all errors.
+ */
+void
+xmlFuzzErrorFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
+                 ...) {
+}
+
+/**
+ * xmlFuzzDataInit:
+ *
+ * Initialize fuzz data provider.
+ */
+void
+xmlFuzzDataInit(const char *data, size_t size) {
+    fuzzData.data = data;
+    fuzzData.size = size;
+    fuzzData.ptr = data;
+    fuzzData.remaining = size;
+
+    fuzzData.outBuf = xmlMalloc(size + 1);
+    fuzzData.outPtr = fuzzData.outBuf;
+
+    fuzzData.entities = xmlHashCreate(8);
+    fuzzData.mainUrl = NULL;
+    fuzzData.mainEntity = NULL;
+}
+
+/**
+ * xmlFuzzDataFree:
+ *
+ * Cleanup fuzz data provider.
+ */
+void
+xmlFuzzDataCleanup(void) {
+    xmlFree(fuzzData.outBuf);
+    xmlHashFree(fuzzData.entities, xmlHashDefaultDeallocator);
+}
+
+/**
+ * xmlFuzzReadInt:
+ * @size:  size of string in bytes
+ *
+ * Read an integer from the fuzz data.
+ */
+int
+xmlFuzzReadInt() {
+    int ret;
+
+    if (fuzzData.remaining < sizeof(int))
+        return(0);
+    memcpy(&ret, fuzzData.ptr, sizeof(int));
+    fuzzData.ptr += sizeof(int);
+    fuzzData.remaining -= sizeof(int);
+
+    return ret;
+}
+
+/**
+ * xmlFuzzReadRemaining:
+ * @size:  size of string in bytes
+ *
+ * Read remaining bytes from fuzz data.
+ */
+const char *
+xmlFuzzReadRemaining(size_t *size) {
+    const char *ret = fuzzData.ptr;
+
+    *size = fuzzData.remaining;
+    fuzzData.ptr += fuzzData.remaining;
+    fuzzData.remaining = 0;
+
+    return(ret);
+}
+
+/*
+ * xmlFuzzWriteString:
+ * @out:  output file
+ * @str:  string to write
+ *
+ * Write a random-length string to file in a format similar to
+ * FuzzedDataProvider. Backslash followed by newline marks the end of the
+ * string. Two backslashes are used to escape a backslash.
+ */
+void
+xmlFuzzWriteString(FILE *out, const char *str) {
+    for (; *str; str++) {
+        int c = (unsigned char) *str;
+        putc(c, out);
+        if (c == '\\')
+            putc(c, out);
+    }
+    putc('\\', out);
+    putc('\n', out);
+}
+
+/**
+ * xmlFuzzReadString:
+ * @size:  size of string in bytes
+ *
+ * Read a random-length string from the fuzz data.
+ *
+ * The format is similar to libFuzzer's FuzzedDataProvider but treats
+ * backslash followed by newline as end of string. This makes the fuzz data
+ * more readable. A backslash character is escaped with another backslash.
+ *
+ * Returns a zero-terminated string or NULL if the fuzz data is exhausted.
+ */
+const char *
+xmlFuzzReadString(size_t *size) {
+    const char *out = fuzzData.outPtr;
+
+    while (fuzzData.remaining > 0) {
+        int c = *fuzzData.ptr++;
+        fuzzData.remaining--;
+
+        if ((c == '\\') && (fuzzData.remaining > 0)) {
+            int c2 = *fuzzData.ptr;
+
+            if (c2 == '\n') {
+                fuzzData.ptr++;
+                fuzzData.remaining--;
+                *size = fuzzData.outPtr - out;
+                *fuzzData.outPtr++ = '\0';
+                return(out);
+            }
+            if (c2 == '\\') {
+                fuzzData.ptr++;
+                fuzzData.remaining--;
+            }
+        }
+
+        *fuzzData.outPtr++ = c;
+    }
+
+    if (fuzzData.outPtr > out) {
+        *size = fuzzData.outPtr - out;
+        *fuzzData.outPtr++ = '\0';
+        return(out);
+    }
+
+    return(NULL);
+}
+
+/**
+ * xmlFuzzReadEntities:
+ *
+ * Read entities like the main XML file, external DTDs, external parsed
+ * entities from fuzz data.
+ */
+void
+xmlFuzzReadEntities(void) {
+    size_t num = 0;
+
+    while (1) {
+        const char *url, *entity;
+        size_t urlSize, entitySize;
+        xmlFuzzEntityInfo *entityInfo;
+        
+        url = xmlFuzzReadString(&urlSize);
+        if (url == NULL) break;
+
+        entity = xmlFuzzReadString(&entitySize);
+        if (entity == NULL) break;
+
+        if (xmlHashLookup(fuzzData.entities, (xmlChar *)url) == NULL) {
+            entityInfo = xmlMalloc(sizeof(xmlFuzzEntityInfo));
+            entityInfo->data = entity;
+            entityInfo->size = entitySize;
+
+            xmlHashAddEntry(fuzzData.entities, (xmlChar *)url, entityInfo);
+
+            if (num == 0) {
+                fuzzData.mainUrl = url;
+                fuzzData.mainEntity = entityInfo;
+            }
+
+            num++;
+        }
+    }
+}
+
+/**
+ * xmlFuzzMainUrl:
+ *
+ * Returns the main URL.
+ */
+const char *
+xmlFuzzMainUrl(void) {
+    return(fuzzData.mainUrl);
+}
+
+/**
+ * xmlFuzzMainEntity:
+ * @size:  size of the main entity in bytes
+ *
+ * Returns the main entity.
+ */
+const char *
+xmlFuzzMainEntity(size_t *size) {
+    if (fuzzData.mainEntity == NULL)
+        return(NULL);
+    *size = fuzzData.mainEntity->size;
+    return(fuzzData.mainEntity->data);
+}
+
+/**
+ * xmlFuzzEntityLoader:
+ *
+ * The entity loader for fuzz data.
+ */
+xmlParserInputPtr
+xmlFuzzEntityLoader(const char *URL, const char *ID ATTRIBUTE_UNUSED,
+                    xmlParserCtxtPtr ctxt) {
+    xmlParserInputPtr input;
+    xmlFuzzEntityInfo *entity;
+
+    if (URL == NULL)
+        return(NULL);
+    entity = xmlHashLookup(fuzzData.entities, (xmlChar *) URL);
+    if (entity == NULL)
+        return(NULL);
+
+    input = xmlNewInputStream(ctxt);
+    input->filename = NULL;
+    input->buf = xmlParserInputBufferCreateMem(entity->data, entity->size,
+                                               XML_CHAR_ENCODING_NONE);
+    input->base = input->cur = xmlBufContent(input->buf->buffer);
+    input->end = input->base + entity->size;
+
+    return input;
+}
+
+/**
+ * xmlFuzzExtractStrings:
+ *
+ * Extract C strings from input data. Use exact-size allocations to detect
+ * potential memory errors.
+ */
+size_t
+xmlFuzzExtractStrings(const char *data, size_t size, char **strings,
+                      size_t numStrings) {
+    const char *start = data;
+    const char *end = data + size;
+    size_t i = 0, ret;
+
+    while (i < numStrings) {
+        size_t strSize = end - start;
+        const char *zero = memchr(start, 0, strSize);
+
+        if (zero != NULL)
+            strSize = zero - start;
+
+        strings[i] = xmlMalloc(strSize + 1);
+        memcpy(strings[i], start, strSize);
+        strings[i][strSize] = '\0';
+
+        i++;
+        if (zero != NULL)
+            start = zero + 1;
+        else
+            break;
+    }
+
+    ret = i;
+
+    while (i < numStrings) {
+        strings[i] = NULL;
+        i++;
+    }
+
+    return(ret);
+}
+
+char *
+xmlSlurpFile(const char *path, size_t *sizeRet) {
+    FILE *file;
+    struct stat statbuf;
+    char *data;
+    size_t size;
+
+    if ((stat(path, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
+        return(NULL);
+    size = statbuf.st_size;
+    file = fopen(path, "rb");
+    if (file == NULL)
+        return(NULL);
+    data = xmlMalloc(size + 1);
+    if (data != NULL) {
+        if (fread(data, 1, size, file) != size) {
+            xmlFree(data);
+            data = NULL;
+        } else {
+            data[size] = 0;
+            if (sizeRet != NULL)
+                *sizeRet = size;
+        }
+    }
+    fclose(file);
+
+    return(data);
+}
+
diff --git a/src/fuzz/genSeed.c b/src/fuzz/genSeed.c
new file mode 100644
index 0000000..68fb87a
--- /dev/null
+++ b/src/fuzz/genSeed.c
@@ -0,0 +1,407 @@
+/*
+ * xmlSeed.c: Generate the XML seed corpus for fuzzing.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <glob.h>
+#include <libgen.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/HTMLparser.h>
+#include <libxml/xinclude.h>
+#include <libxml/xmlschemas.h>
+#include "fuzz.h"
+
+#define PATH_SIZE 500
+#define SEED_BUF_SIZE 16384
+#define EXPR_SIZE 4500
+
+typedef int
+(*fileFunc)(const char *base, FILE *out);
+
+typedef int
+(*mainFunc)(const char *arg);
+
+static struct {
+    FILE *out;
+    xmlHashTablePtr entities; /* Maps URLs to xmlFuzzEntityInfos */
+    xmlExternalEntityLoader oldLoader;
+    fileFunc processFile;
+    const char *fuzzer;
+    int counter;
+    char cwd[PATH_SIZE];
+} globalData;
+
+/*
+ * A custom entity loader that writes all external DTDs or entities to a
+ * single file in the format expected by xmlFuzzEntityLoader.
+ */
+static xmlParserInputPtr
+fuzzEntityRecorder(const char *URL, const char *ID,
+                      xmlParserCtxtPtr ctxt) {
+    xmlParserInputPtr in;
+    static const int chunkSize = 16384;
+    int len;
+
+    in = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
+    if (in == NULL)
+        return(NULL);
+
+    if (globalData.entities == NULL) {
+        globalData.entities = xmlHashCreate(4);
+    } else if (xmlHashLookup(globalData.entities,
+                             (const xmlChar *) URL) != NULL) {
+        return(in);
+    }
+
+    do {
+        len = xmlParserInputBufferGrow(in->buf, chunkSize);
+        if (len < 0) {
+            fprintf(stderr, "Error reading %s\n", URL);
+            xmlFreeInputStream(in);
+            return(NULL);
+        }
+    } while (len > 0);
+
+    xmlFuzzWriteString(globalData.out, URL);
+    xmlFuzzWriteString(globalData.out,
+                       (char *) xmlBufContent(in->buf->buffer));
+
+    xmlFreeInputStream(in);
+
+    xmlHashAddEntry(globalData.entities, (const xmlChar *) URL, NULL);
+
+    return(xmlNoNetExternalEntityLoader(URL, ID, ctxt));
+}
+
+static void
+fuzzRecorderInit(FILE *out) {
+    globalData.out = out;
+    globalData.entities = xmlHashCreate(8);
+    globalData.oldLoader = xmlGetExternalEntityLoader();
+    xmlSetExternalEntityLoader(fuzzEntityRecorder);
+}
+
+static void
+fuzzRecorderCleanup() {
+    xmlSetExternalEntityLoader(globalData.oldLoader);
+    xmlHashFree(globalData.entities, xmlHashDefaultDeallocator);
+    globalData.out = NULL;
+    globalData.entities = NULL;
+    globalData.oldLoader = NULL;
+}
+
+static int
+processXml(const char *docFile, FILE *out) {
+    int opts = XML_PARSE_NOENT | XML_PARSE_DTDLOAD;
+    xmlDocPtr doc;
+
+    fwrite(&opts, sizeof(opts), 1, out);
+
+    fuzzRecorderInit(out);
+
+    doc = xmlReadFile(docFile, NULL, opts);
+    xmlXIncludeProcessFlags(doc, opts);
+    xmlFreeDoc(doc);
+
+    fuzzRecorderCleanup();
+
+    return(0);
+}
+
+static int
+processHtml(const char *docFile, FILE *out) {
+    char buf[SEED_BUF_SIZE];
+    FILE *file;
+    size_t size;
+    int opts = 0;
+
+    fwrite(&opts, sizeof(opts), 1, out);
+
+    /* Copy file */
+    file = fopen(docFile, "rb");
+    if (file == NULL) {
+        fprintf(stderr, "couldn't open %s\n", docFile);
+        return(0);
+    }
+    do {
+        size = fread(buf, 1, SEED_BUF_SIZE, file);
+        if (size > 0)
+            fwrite(buf, 1, size, out);
+    } while (size == SEED_BUF_SIZE);
+    fclose(file);
+
+    return(0);
+}
+
+static int
+processSchema(const char *docFile, FILE *out) {
+    xmlSchemaPtr schema;
+    xmlSchemaParserCtxtPtr pctxt;
+
+    fuzzRecorderInit(out);
+
+    pctxt = xmlSchemaNewParserCtxt(docFile);
+    xmlSchemaSetParserErrors(pctxt, xmlFuzzErrorFunc, xmlFuzzErrorFunc, NULL);
+    schema = xmlSchemaParse(pctxt);
+    xmlSchemaFreeParserCtxt(pctxt);
+    xmlSchemaFree(schema);
+
+    fuzzRecorderCleanup();
+
+    return(0);
+}
+
+static int
+processPattern(const char *pattern) {
+    glob_t globbuf;
+    int ret = 0;
+    int res, i;
+
+    res = glob(pattern, 0, NULL, &globbuf);
+    if (res == GLOB_NOMATCH)
+        return(0);
+    if (res != 0) {
+        fprintf(stderr, "couldn't match pattern %s\n", pattern);
+        return(-1);
+    }
+
+    for (i = 0; i < globbuf.gl_pathc; i++) {
+        struct stat statbuf;
+        char outPath[PATH_SIZE];
+        char *dirBuf = NULL;
+        char *baseBuf = NULL;
+        const char *path, *dir, *base;
+        FILE *out = NULL;
+        int dirChanged = 0;
+        size_t size;
+
+        path = globbuf.gl_pathv[i];
+
+        if ((stat(path, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
+            continue;
+
+        dirBuf = (char *) xmlCharStrdup(path);
+        baseBuf = (char *) xmlCharStrdup(path);
+        if ((dirBuf == NULL) || (baseBuf == NULL)) {
+            fprintf(stderr, "memory allocation failed\n");
+            ret = -1;
+            goto error;
+        }
+        dir = dirname(dirBuf);
+        base = basename(baseBuf);
+
+        size = snprintf(outPath, sizeof(outPath), "seed/%s/%s",
+                        globalData.fuzzer, base);
+        if (size >= PATH_SIZE) {
+            fprintf(stderr, "creating path failed\n");
+            ret = -1;
+            goto error;
+        }
+        out = fopen(outPath, "wb");
+        if (out == NULL) {
+            fprintf(stderr, "couldn't open %s for writing\n", outPath);
+            ret = -1;
+            goto error;
+        }
+        if (chdir(dir) != 0) {
+            fprintf(stderr, "couldn't chdir to %s\n", dir);
+            ret = -1;
+            goto error;
+        }
+        dirChanged = 1;
+        if (globalData.processFile(base, out) != 0)
+            ret = -1;
+
+error:
+        if (out != NULL)
+            fclose(out);
+        xmlFree(dirBuf);
+        xmlFree(baseBuf);
+        if ((dirChanged) && (chdir(globalData.cwd) != 0)) {
+            fprintf(stderr, "couldn't chdir to %s\n", globalData.cwd);
+            ret = -1;
+            break;
+        }
+    }
+
+    globfree(&globbuf);
+    return(ret);
+}
+
+static int
+processXPath(const char *testDir, const char *prefix, const char *name,
+             const char *data, const char *subdir, int xptr) {
+    char pattern[PATH_SIZE];
+    glob_t globbuf;
+    size_t i, size;
+    int ret = 0, res;
+
+    size = snprintf(pattern, sizeof(pattern), "%s/%s/%s*",
+                    testDir, subdir, prefix);
+    if (size >= PATH_SIZE)
+        return(-1);
+    res = glob(pattern, 0, NULL, &globbuf);
+    if (res == GLOB_NOMATCH)
+        return(0);
+    if (res != 0) {
+        fprintf(stderr, "couldn't match pattern %s\n", pattern);
+        return(-1);
+    }
+
+    for (i = 0; i < globbuf.gl_pathc; i++) {
+        char *path = globbuf.gl_pathv[i];
+        struct stat statbuf;
+        FILE *in;
+        char expr[EXPR_SIZE];
+
+        if ((stat(path, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode)))
+            continue;
+
+        in = fopen(path, "rb");
+        if (in == NULL) {
+            ret = -1;
+            continue;
+        }
+
+        while (fgets(expr, EXPR_SIZE, in) > 0) {
+            char outPath[PATH_SIZE];
+            FILE *out;
+            int j;
+
+            for (j = 0; expr[j] != 0; j++)
+                if (expr[j] == '\r' || expr[j] == '\n')
+                    break;
+            expr[j] = 0;
+
+            size = snprintf(outPath, sizeof(outPath), "seed/xpath/%s-%d",
+                            name, globalData.counter);
+            if (size >= PATH_SIZE) {
+                ret = -1;
+                continue;
+            }
+            out = fopen(outPath, "wb");
+            if (out == NULL) {
+                ret = -1;
+                continue;
+            }
+
+            if (xptr) {
+                xmlFuzzWriteString(out, expr);
+            } else {
+                char xptrExpr[EXPR_SIZE+100];
+
+                /* Wrap XPath expressions as XPointer */
+                snprintf(xptrExpr, sizeof(xptrExpr), "xpointer(%s)", expr);
+                xmlFuzzWriteString(out, xptrExpr);
+            }
+
+            xmlFuzzWriteString(out, data);
+
+            fclose(out);
+            globalData.counter++;
+        }
+
+        fclose(in);
+    }
+
+    globfree(&globbuf);
+
+    return(ret);
+}
+
+int
+processXPathDir(const char *testDir) {
+    char pattern[PATH_SIZE];
+    glob_t globbuf;
+    size_t i, size;
+    int ret = 0;
+
+    globalData.counter = 1;
+    if (processXPath(testDir, "", "expr", "<d></d>", "expr", 0) != 0)
+        ret = -1;
+
+    size = snprintf(pattern, sizeof(pattern), "%s/docs/*", testDir);
+    if (size >= PATH_SIZE)
+        return(1);
+    if (glob(pattern, 0, NULL, &globbuf) != 0)
+        return(1);
+
+    for (i = 0; i < globbuf.gl_pathc; i++) {
+        char *path = globbuf.gl_pathv[i];
+        char *data;
+        const char *docFile;
+
+        data = xmlSlurpFile(path, NULL);
+        if (data == NULL) {
+            ret = -1;
+            continue;
+        }
+        docFile = basename(path);
+
+        globalData.counter = 1;
+        if (processXPath(testDir, docFile, docFile, data, "tests", 0) != 0)
+            ret = -1;
+        if (processXPath(testDir, docFile, docFile, data, "xptr", 1) != 0)
+            ret = -1;
+
+        xmlFree(data);
+    }
+
+    globfree(&globbuf);
+
+    return(ret);
+}
+
+int
+main(int argc, const char **argv) {
+    mainFunc processArg = processPattern;
+    const char *fuzzer;
+    int ret = 0;
+    int xpath = 0;
+    int i;
+
+    if (argc < 3) {
+        fprintf(stderr, "usage: seed [FUZZER] [PATTERN...]\n");
+        return(1);
+    }
+
+    xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
+
+    fuzzer = argv[1];
+    if (strcmp(fuzzer, "html") == 0) {
+        globalData.processFile = processHtml;
+    } else if (strcmp(fuzzer, "schema") == 0) {
+        globalData.processFile = processSchema;
+    } else if (strcmp(fuzzer, "xml") == 0) {
+        globalData.processFile = processXml;
+    } else if (strcmp(fuzzer, "xpath") == 0) {
+        processArg = processXPathDir;
+    } else {
+        fprintf(stderr, "unknown fuzzer %s\n", fuzzer);
+        return(1);
+    }
+    globalData.fuzzer = fuzzer;
+
+    if (getcwd(globalData.cwd, PATH_SIZE) == NULL) {
+        fprintf(stderr, "couldn't get current directory\n");
+        return(1);
+    }
+
+    for (i = 2; i < argc; i++)
+        processArg(argv[i]);
+
+    return(ret);
+}
+
diff --git a/src/fuzz/html.c b/src/fuzz/html.c
new file mode 100644
index 0000000..d212c1f
--- /dev/null
+++ b/src/fuzz/html.c
@@ -0,0 +1,70 @@
+/*
+ * html.c: a libFuzzer target to test several HTML parser interfaces.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <libxml/HTMLparser.h>
+#include <libxml/HTMLtree.h>
+#include "fuzz.h"
+
+int
+LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
+                     char ***argv ATTRIBUTE_UNUSED) {
+    xmlInitParser();
+    xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
+
+    return 0;
+}
+
+int
+LLVMFuzzerTestOneInput(const char *data, size_t size) {
+    static const size_t maxChunkSize = 128;
+    htmlDocPtr doc;
+    htmlParserCtxtPtr ctxt;
+    xmlChar *out;
+    const char *docBuffer;
+    size_t docSize, consumed, chunkSize;
+    int opts, outSize;
+
+    xmlFuzzDataInit(data, size);
+    opts = xmlFuzzReadInt();
+
+    docBuffer = xmlFuzzReadRemaining(&docSize);
+    if (docBuffer == NULL) {
+        xmlFuzzDataCleanup();
+        return(0);
+    }
+
+    /* Pull parser */
+
+    doc = htmlReadMemory(docBuffer, docSize, NULL, NULL, opts);
+    /* Also test the serializer. */
+    htmlDocDumpMemory(doc, &out, &outSize);
+    xmlFree(out);
+    xmlFreeDoc(doc);
+
+    /* Push parser */
+
+    ctxt = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL,
+                                    XML_CHAR_ENCODING_NONE);
+    htmlCtxtUseOptions(ctxt, opts);
+
+    for (consumed = 0; consumed < docSize; consumed += chunkSize) {
+        chunkSize = docSize - consumed;
+        if (chunkSize > maxChunkSize)
+            chunkSize = maxChunkSize;
+        htmlParseChunk(ctxt, docBuffer + consumed, chunkSize, 0);
+    }
+
+    htmlParseChunk(ctxt, NULL, 0, 1);
+    xmlFreeDoc(ctxt->myDoc);
+    htmlFreeParserCtxt(ctxt);
+
+    /* Cleanup */
+
+    xmlFuzzDataCleanup();
+
+    return(0);
+}
+
diff --git a/src/fuzz/regexp.c b/src/fuzz/regexp.c
new file mode 100644
index 0000000..3b35671
--- /dev/null
+++ b/src/fuzz/regexp.c
@@ -0,0 +1,43 @@
+/*
+ * regexp.c: a libFuzzer target to test the regexp module.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <libxml/xmlregexp.h>
+#include "fuzz.h"
+
+int
+LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
+                     char ***argv ATTRIBUTE_UNUSED) {
+    xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
+
+    return 0;
+}
+
+int
+LLVMFuzzerTestOneInput(const char *data, size_t size) {
+    xmlRegexpPtr regexp;
+    char *str[2] = { NULL, NULL };
+    size_t numStrings;
+
+    numStrings = xmlFuzzExtractStrings(data, size, str, 2);
+
+    /* CUR_SCHAR doesn't handle invalid UTF-8 and may cause infinite loops. */
+    if (xmlCheckUTF8(BAD_CAST str[0]) != 0) {
+        regexp = xmlRegexpCompile(BAD_CAST str[0]);
+        /* xmlRegexpExec has pathological performance in too many cases. */
+#if 0
+        if ((regexp != NULL) && (numStrings >= 2)) {
+            xmlRegexpExec(regexp, BAD_CAST str[1]);
+        }
+#endif
+        xmlRegFreeRegexp(regexp);
+    }
+
+    xmlFree(str[0]);
+    xmlFree(str[1]);
+
+    return 0;
+}
+
diff --git a/src/fuzz/schema.c b/src/fuzz/schema.c
new file mode 100644
index 0000000..f1ee938
--- /dev/null
+++ b/src/fuzz/schema.c
@@ -0,0 +1,36 @@
+/*
+ * schema.c: a libFuzzer target to test the XML Schema processor.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <libxml/xmlschemas.h>
+#include "fuzz.h"
+
+int
+LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
+                     char ***argv ATTRIBUTE_UNUSED) {
+    xmlInitParser();
+    xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
+    xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
+
+    return 0;
+}
+
+int
+LLVMFuzzerTestOneInput(const char *data, size_t size) {
+    xmlSchemaParserCtxtPtr pctxt;
+
+    xmlFuzzDataInit(data, size);
+    xmlFuzzReadEntities();
+
+    pctxt = xmlSchemaNewParserCtxt(xmlFuzzMainUrl());
+    xmlSchemaSetParserErrors(pctxt, xmlFuzzErrorFunc, xmlFuzzErrorFunc, NULL);
+    xmlSchemaFree(xmlSchemaParse(pctxt));
+    xmlSchemaFreeParserCtxt(pctxt);
+
+    xmlFuzzDataCleanup();
+
+    return(0);
+}
+
diff --git a/src/fuzz/testFuzzer.c b/src/fuzz/testFuzzer.c
new file mode 100644
index 0000000..678f324
--- /dev/null
+++ b/src/fuzz/testFuzzer.c
@@ -0,0 +1,160 @@
+/*
+ * testFuzzer.c: Test program for the custom entity loader used to fuzz
+ * with multiple inputs.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <string.h>
+#include <glob.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlstring.h>
+#include "fuzz.h"
+
+#define LLVMFuzzerInitialize fuzzHtmlInit
+#define LLVMFuzzerTestOneInput fuzzHtml
+#include "html.c"
+#undef LLVMFuzzerInitialize
+#undef LLVMFuzzerTestOneInput
+
+#define LLVMFuzzerInitialize fuzzRegexpInit
+#define LLVMFuzzerTestOneInput fuzzRegexp
+#include "regexp.c"
+#undef LLVMFuzzerInitialize
+#undef LLVMFuzzerTestOneInput
+
+#define LLVMFuzzerInitialize fuzzSchemaInit
+#define LLVMFuzzerTestOneInput fuzzSchema
+#include "schema.c"
+#undef LLVMFuzzerInitialize
+#undef LLVMFuzzerTestOneInput
+
+#define LLVMFuzzerInitialize fuzzUriInit
+#define LLVMFuzzerTestOneInput fuzzUri
+#include "uri.c"
+#undef LLVMFuzzerInitialize
+#undef LLVMFuzzerTestOneInput
+
+#define LLVMFuzzerInitialize fuzzXmlInit
+#define LLVMFuzzerTestOneInput fuzzXml
+#include "xml.c"
+#undef LLVMFuzzerInitialize
+#undef LLVMFuzzerTestOneInput
+
+#define LLVMFuzzerInitialize fuzzXPathInit
+#define LLVMFuzzerTestOneInput fuzzXPath
+#include "xpath.c"
+#undef LLVMFuzzerInitialize
+#undef LLVMFuzzerTestOneInput
+
+typedef int
+(*initFunc)(int *argc, char ***argv);
+typedef int
+(*fuzzFunc)(const char *data, size_t size);
+
+int numInputs;
+
+static int
+testFuzzer(initFunc init, fuzzFunc fuzz, const char *pattern) {
+    glob_t globbuf;
+    int ret = -1;
+    int i;
+
+    if (glob(pattern, 0, NULL, &globbuf) != 0) {
+        fprintf(stderr, "pattern %s matches no files\n", pattern);
+        return(-1);
+    }
+
+    if (init != NULL)
+        init(NULL, NULL);
+
+    for (i = 0; i < globbuf.gl_pathc; i++) {
+        const char *path = globbuf.gl_pathv[i];
+        char *data;
+        size_t size;
+
+        data = xmlSlurpFile(path, &size);
+        if (data == NULL) {
+            fprintf(stderr, "couldn't read %s\n", path);
+            goto error;
+        }
+        fuzz(data, size);
+        xmlFree(data);
+
+        numInputs++;
+    }
+
+    ret = 0;
+error:
+    globfree(&globbuf);
+    return(ret);
+}
+
+static int
+testEntityLoader() {
+    static const char data[] =
+        "doc.xml\\\n"
+        "<!DOCTYPE doc SYSTEM \"doc.dtd\">\n"
+        "<doc>&ent;</doc>\\\n"
+        "doc.dtd\\\n"
+        "<!ELEMENT doc (#PCDATA)>\n"
+        "<!ENTITY ent SYSTEM \"ent.txt\">\\\n"
+        "ent.txt\\\n"
+        "Hello, world!\\\n";
+    static xmlChar expected[] =
+        "<?xml version=\"1.0\"?>\n"
+        "<!DOCTYPE doc SYSTEM \"doc.dtd\">\n"
+        "<doc>Hello, world!</doc>\n";
+    const char *docBuffer;
+    size_t docSize;
+    xmlDocPtr doc;
+    xmlChar *out;
+    int ret = 0;
+
+    xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
+
+    xmlFuzzDataInit(data, sizeof(data) - 1);
+    xmlFuzzReadEntities();
+    docBuffer = xmlFuzzMainEntity(&docSize);
+    doc = xmlReadMemory(docBuffer, docSize, NULL, NULL,
+                        XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
+
+    xmlDocDumpMemory(doc, &out, NULL);
+    if (xmlStrcmp(out, expected) != 0) {
+        fprintf(stderr, "Expected:\n%sGot:\n%s", expected, out);
+        ret = 1;
+    }
+
+    xmlFree(out);
+    xmlFreeDoc(doc);
+    xmlFuzzDataCleanup();
+
+    return(ret);
+}
+
+int
+main() {
+    int ret = 0;
+
+    if (testEntityLoader() != 0)
+        ret = 1;
+    if (testFuzzer(fuzzHtmlInit, fuzzHtml, "seed/html/*") != 0)
+        ret = 1;
+    if (testFuzzer(fuzzRegexpInit, fuzzRegexp, "seed/regexp/*") != 0)
+        ret = 1;
+    if (testFuzzer(fuzzSchemaInit, fuzzSchema, "seed/schema/*") != 0)
+        ret = 1;
+    if (testFuzzer(NULL, fuzzUri, "seed/uri/*") != 0)
+        ret = 1;
+    if (testFuzzer(fuzzXmlInit, fuzzXml, "seed/xml/*") != 0)
+        ret = 1;
+    if (testFuzzer(fuzzXPathInit, fuzzXPath, "seed/xpath/*") != 0)
+        ret = 1;
+
+    if (ret == 0)
+        printf("Successfully tested %d inputs\n", numInputs);
+
+    return(ret);
+}
+
diff --git a/src/fuzz/uri.c b/src/fuzz/uri.c
new file mode 100644
index 0000000..69d0439
--- /dev/null
+++ b/src/fuzz/uri.c
@@ -0,0 +1,45 @@
+/*
+ * uri.c: a libFuzzer target to test the URI module.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <libxml/uri.h>
+#include "fuzz.h"
+
+int
+LLVMFuzzerTestOneInput(const char *data, size_t size) {
+    xmlURIPtr uri;
+    char *str[2] = { NULL, NULL };
+    size_t numStrings;
+
+    numStrings = xmlFuzzExtractStrings(data, size, str, 2);
+
+    uri = xmlParseURI(str[0]);
+    xmlFree(xmlSaveUri(uri));
+    xmlFreeURI(uri);
+
+    uri = xmlParseURIRaw(str[0], 1);
+    xmlFree(xmlSaveUri(uri));
+    xmlFreeURI(uri);
+
+    xmlFree(xmlURIUnescapeString(str[0], -1, NULL));
+    xmlFree(xmlURIEscape(BAD_CAST str[0]));
+    xmlFree(xmlCanonicPath(BAD_CAST str[0]));
+    xmlFree(xmlPathToURI(BAD_CAST str[0]));
+
+    if (numStrings >= 2) {
+        xmlFree(xmlBuildURI(BAD_CAST str[1], BAD_CAST str[0]));
+        xmlFree(xmlBuildRelativeURI(BAD_CAST str[1], BAD_CAST str[0]));
+        xmlFree(xmlURIEscapeStr(BAD_CAST str[0], BAD_CAST str[1]));
+    }
+
+    /* Modifies string, so must come last. */
+    xmlNormalizeURIPath(str[0]);
+
+    xmlFree(str[0]);
+    xmlFree(str[1]);
+
+    return 0;
+}
+
diff --git a/src/fuzz/xml.c b/src/fuzz/xml.c
new file mode 100644
index 0000000..09867cf
--- /dev/null
+++ b/src/fuzz/xml.c
@@ -0,0 +1,96 @@
+/*
+ * xml.c: a libFuzzer target to test several XML parser interfaces.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlerror.h>
+#include <libxml/xinclude.h>
+#include <libxml/xmlreader.h>
+#include "fuzz.h"
+
+int
+LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
+                     char ***argv ATTRIBUTE_UNUSED) {
+    xmlInitParser();
+    xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
+    xmlSetExternalEntityLoader(xmlFuzzEntityLoader);
+
+    return 0;
+}
+
+int
+LLVMFuzzerTestOneInput(const char *data, size_t size) {
+    static const size_t maxChunkSize = 128;
+    xmlDocPtr doc;
+    xmlParserCtxtPtr ctxt;
+    xmlTextReaderPtr reader;
+    xmlChar *out;
+    const char *docBuffer, *docUrl;
+    size_t docSize, consumed, chunkSize;
+    int opts, outSize;
+
+    xmlFuzzDataInit(data, size);
+    opts = xmlFuzzReadInt();
+    /* XML_PARSE_HUGE still causes timeouts. */
+    opts &= ~XML_PARSE_HUGE;
+
+    xmlFuzzReadEntities();
+    docBuffer = xmlFuzzMainEntity(&docSize);
+    docUrl = xmlFuzzMainUrl();
+    if (docBuffer == NULL) {
+        xmlFuzzDataCleanup();
+        return(0);
+    }
+
+    /* Pull parser */
+
+    doc = xmlReadMemory(docBuffer, docSize, docUrl, NULL, opts);
+    if (opts & XML_PARSE_XINCLUDE)
+        xmlXIncludeProcessFlags(doc, opts);
+    /* Also test the serializer. */
+    xmlDocDumpMemory(doc, &out, &outSize);
+    xmlFree(out);
+    xmlFreeDoc(doc);
+
+    /* Push parser */
+
+    ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, docUrl);
+    xmlCtxtUseOptions(ctxt, opts);
+
+    for (consumed = 0; consumed < docSize; consumed += chunkSize) {
+        chunkSize = docSize - consumed;
+        if (chunkSize > maxChunkSize)
+            chunkSize = maxChunkSize;
+        xmlParseChunk(ctxt, docBuffer + consumed, chunkSize, 0);
+    }
+
+    xmlParseChunk(ctxt, NULL, 0, 1);
+    if (opts & XML_PARSE_XINCLUDE)
+        xmlXIncludeProcessFlags(ctxt->myDoc, opts);
+    xmlFreeDoc(ctxt->myDoc);
+    xmlFreeParserCtxt(ctxt);
+
+    /* Reader */
+
+    reader = xmlReaderForMemory(docBuffer, docSize, NULL, NULL, opts);
+    while (xmlTextReaderRead(reader) == 1) {
+        if (xmlTextReaderNodeType(reader) == XML_ELEMENT_NODE) {
+            int i, n = xmlTextReaderAttributeCount(reader);
+            for (i=0; i<n; i++) {
+                xmlTextReaderMoveToAttributeNo(reader, i);
+                while (xmlTextReaderReadAttributeValue(reader) == 1);
+            }
+        }
+    }
+    xmlFreeTextReader(reader);
+
+    /* Cleanup */
+
+    xmlFuzzDataCleanup();
+
+    return(0);
+}
+
diff --git a/src/fuzz/xpath.c b/src/fuzz/xpath.c
new file mode 100644
index 0000000..767acb9
--- /dev/null
+++ b/src/fuzz/xpath.c
@@ -0,0 +1,48 @@
+/*
+ * xpath.c: a libFuzzer target to test XPath and XPointer expressions.
+ *
+ * See Copyright for the status of this software.
+ */
+
+#include <libxml/parser.h>
+#include <libxml/xpointer.h>
+#include "fuzz.h"
+
+int
+LLVMFuzzerInitialize(int *argc ATTRIBUTE_UNUSED,
+                     char ***argv ATTRIBUTE_UNUSED) {
+    xmlInitParser();
+    xmlSetGenericErrorFunc(NULL, xmlFuzzErrorFunc);
+
+    return 0;
+}
+
+int
+LLVMFuzzerTestOneInput(const char *data, size_t size) {
+    xmlDocPtr doc;
+    const char *expr, *xml;
+    size_t exprSize, xmlSize;
+
+    xmlFuzzDataInit(data, size);
+
+    expr = xmlFuzzReadString(&exprSize);
+    xml = xmlFuzzReadString(&xmlSize);
+
+    /* Recovery mode allows more input to be fuzzed. */
+    doc = xmlReadMemory(xml, xmlSize, NULL, NULL, XML_PARSE_RECOVER);
+    if (doc != NULL) {
+        xmlXPathContextPtr xpctxt = xmlXPathNewContext(doc);
+
+        /* Operation limit to avoid timeout */
+        xpctxt->opLimit = 500000;
+
+        xmlXPathFreeObject(xmlXPtrEval(BAD_CAST expr, xpctxt));
+        xmlXPathFreeContext(xpctxt);
+    }
+    xmlFreeDoc(doc);
+
+    xmlFuzzDataCleanup();
+
+    return(0);
+}
+
diff --git a/src/include/libxml/parser.h b/src/include/libxml/parser.h
index 3020b20..1c86a97 100644
--- a/src/include/libxml/parser.h
+++ b/src/include/libxml/parser.h
@@ -231,7 +231,7 @@
     int                nameMax;       /* Max depth of the parsing stack */
     const xmlChar *   *nameTab;       /* array of nodes */
 
-    long               nbChars;       /* number of xmlChar processed */
+    long               nbChars;       /* unused */
     long            checkIndex;       /* used by progressive parsing lookup */
     int             keepBlanks;       /* ugly but ... */
     int             disableSAX;       /* SAX callbacks are disabled */
diff --git a/src/libxml2.spec b/src/libxml2.spec
index d2a5ffb..6f6c1d0 100644
--- a/src/libxml2.spec
+++ b/src/libxml2.spec
@@ -204,6 +204,6 @@
 %endif # with_python3
 
 %changelog
-* Fri Apr 10 2020 Daniel Veillard <veillard@redhat.com>
+* Wed Oct  7 2020 Daniel Veillard <veillard@redhat.com>
 - upstream release 2.9.10 see http://xmlsoft.org/news.html
 
diff --git a/src/parser.c b/src/parser.c
index 87d9e61..5633e3e 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1074,11 +1074,15 @@
  */
 static void
 xmlDetectSAX2(xmlParserCtxtPtr ctxt) {
+    xmlSAXHandlerPtr sax;
     if (ctxt == NULL) return;
+    sax = ctxt->sax;
 #ifdef LIBXML_SAX1_ENABLED
-    if ((ctxt->sax) &&  (ctxt->sax->initialized == XML_SAX2_MAGIC) &&
-        ((ctxt->sax->startElementNs != NULL) ||
-         (ctxt->sax->endElementNs != NULL))) ctxt->sax2 = 1;
+    if ((sax) &&  (sax->initialized == XML_SAX2_MAGIC) &&
+        ((sax->startElementNs != NULL) ||
+         (sax->endElementNs != NULL) ||
+         ((sax->startElement == NULL) && (sax->endElement == NULL))))
+        ctxt->sax2 = 1;
 #else
     ctxt->sax2 = 1;
 #endif /* LIBXML_SAX1_ENABLED */
@@ -2051,7 +2055,7 @@
     ((unsigned char *) s)[ 9 ] == c10 )
 
 #define SKIP(val) do {							\
-    ctxt->nbChars += (val),ctxt->input->cur += (val),ctxt->input->col+=(val);			\
+    ctxt->input->cur += (val),ctxt->input->col+=(val);			\
     if (*ctxt->input->cur == 0)						\
         xmlParserInputGrow(ctxt->input, INPUT_CHUNK);			\
   } while (0)
@@ -2062,7 +2066,6 @@
 	if (*(ctxt->input->cur) == '\n') {				\
 	ctxt->input->line++; ctxt->input->col = 1;			\
 	} else ctxt->input->col++;					\
-	ctxt->nbChars++;						\
 	ctxt->input->cur++;						\
     }									\
     if (*ctxt->input->cur == 0)						\
@@ -2115,7 +2118,6 @@
 #define NEXT1 {								\
 	ctxt->input->col++;						\
 	ctxt->input->cur++;						\
-	ctxt->nbChars++;						\
 	if (*ctxt->input->cur == 0)					\
 	    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);		\
     }
@@ -2152,7 +2154,7 @@
      * It's Okay to use CUR/NEXT here since all the blanks are on
      * the ASCII range.
      */
-    if ((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) {
+    if (ctxt->instate != XML_PARSER_DTD) {
 	const xmlChar *cur;
 	/*
 	 * if we are in the document content, go really fast
@@ -2328,7 +2330,6 @@
 	if (RAW == ';') {
 	    /* on purpose to avoid reentrancy problems with NEXT and SKIP */
 	    ctxt->input->col++;
-	    ctxt->nbChars ++;
 	    ctxt->input->cur++;
 	}
     } else if  ((RAW == '&') && (NXT(1) == '#')) {
@@ -2357,7 +2358,6 @@
 	if (RAW == ';') {
 	    /* on purpose to avoid reentrancy problems with NEXT and SKIP */
 	    ctxt->input->col++;
-	    ctxt->nbChars ++;
 	    ctxt->input->cur++;
 	}
     } else {
@@ -3329,7 +3329,6 @@
             }
 	    ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count);
 	    ctxt->input->cur = in;
-	    ctxt->nbChars += count;
 	    ctxt->input->col += count;
 	    if (ret == NULL)
 	        xmlErrMemory(ctxt, NULL);
@@ -3452,7 +3451,6 @@
             }
 	    ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count);
 	    ctxt->input->cur = in;
-	    ctxt->nbChars += count;
 	    ctxt->input->col += count;
 	    if (ret == NULL) {
 	        xmlErrMemory(ctxt, NULL);
@@ -3489,10 +3487,10 @@
     while (*in != 0 && *in == *cmp) {
 	++in;
 	++cmp;
-	ctxt->input->col++;
     }
     if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) {
 	/* success */
+	ctxt->input->col += in - ctxt->input->cur;
 	ctxt->input->cur = in;
 	return (const xmlChar*) 1;
     }
@@ -6848,6 +6846,7 @@
 xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
     xmlChar *version;
     const xmlChar *encoding;
+    int oldstate;
 
     /*
      * We know that '<?xml' is here.
@@ -6859,6 +6858,10 @@
 	return;
     }
 
+    /* Avoid expansion of parameter entities when skipping blanks. */
+    oldstate = ctxt->instate;
+    ctxt->instate = XML_PARSER_START;
+
     if (SKIP_BLANKS == 0) {
 	xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 		       "Space needed after '<?xml'\n");
@@ -6886,6 +6889,7 @@
 	/*
 	 * The XML REC instructs us to stop parsing right here
 	 */
+        ctxt->instate = oldstate;
         return;
     }
     if ((encoding == NULL) && (ctxt->errNo == XML_ERR_OK)) {
@@ -6905,6 +6909,8 @@
 	MOVETO_ENDTAG(CUR_PTR);
 	NEXT;
     }
+
+    ctxt->instate = oldstate;
 }
 
 /**
@@ -8825,6 +8831,7 @@
 	}
 	if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) {
 	    /* success */
+            ctxt->input->col += in - ctxt->input->cur;
 	    ctxt->input->cur = in;
 	    return((const xmlChar*) 1);
 	}
@@ -12206,12 +12213,12 @@
             }
         }
 	res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
+        xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
 	if (res < 0) {
 	    ctxt->errNo = XML_PARSER_EOF;
 	    xmlHaltParser(ctxt);
 	    return (XML_PARSER_EOF);
 	}
-        xmlBufSetInputBaseCur(ctxt->input->buf->buffer, ctxt->input, base, cur);
 #ifdef DEBUG_PUSH
 	xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size);
 #endif
@@ -12226,6 +12233,7 @@
 		size_t current = ctxt->input->cur - ctxt->input->base;
 
 		nbchars = xmlCharEncInput(in, terminate);
+		xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
 		if (nbchars < 0) {
 		    /* TODO 2.6.0 */
 		    xmlGenericError(xmlGenericErrorContext,
@@ -12233,7 +12241,6 @@
                     xmlHaltParser(ctxt);
 		    return(XML_ERR_INVALID_ENCODING);
 		}
-		xmlBufSetInputBaseCur(in->buffer, ctxt->input, base, current);
 	    }
 	}
     }
@@ -13163,7 +13170,7 @@
 
 /**
  * xmlParseBalancedChunkMemory:
- * @doc:  the document the chunk pertains to
+ * @doc:  the document the chunk pertains to (must not be NULL)
  * @sax:  the SAX handler block (possibly NULL)
  * @user_data:  The user data returned on SAX callbacks (possibly NULL)
  * @depth:  Used for loop detection, use 0
@@ -13615,7 +13622,7 @@
 #ifdef LIBXML_SAX1_ENABLED
 /**
  * xmlParseBalancedChunkMemoryRecover:
- * @doc:  the document the chunk pertains to
+ * @doc:  the document the chunk pertains to (must not be NULL)
  * @sax:  the SAX handler block (possibly NULL)
  * @user_data:  The user data returned on SAX callbacks (possibly NULL)
  * @depth:  Used for loop detection, use 0
@@ -13687,6 +13694,7 @@
     } else {
 	xmlCtxtUseOptionsInternal(ctxt, XML_PARSE_NODICT, NULL);
     }
+    /* doc == NULL is only supported for historic reasons */
     if (doc != NULL) {
 	newDoc->intSubset = doc->intSubset;
 	newDoc->extSubset = doc->extSubset;
@@ -13703,6 +13711,7 @@
     }
     xmlAddChild((xmlNodePtr) newDoc, newRoot);
     nodePush(ctxt, newRoot);
+    /* doc == NULL is only supported for historic reasons */
     if (doc == NULL) {
 	ctxt->myDoc = newDoc;
     } else {
@@ -13772,8 +13781,8 @@
     xmlFreeParserCtxt(ctxt);
     newDoc->intSubset = NULL;
     newDoc->extSubset = NULL;
-    if(doc != NULL)
-	newDoc->oldNs = NULL;
+    /* This leaks the namespace list if doc == NULL */
+    newDoc->oldNs = NULL;
     xmlFreeDoc(newDoc);
 
     return(ret);
@@ -14055,7 +14064,7 @@
 
     if ((ctxt->wellFormed) || recovery) {
         ret = ctxt->myDoc;
-	if (ret != NULL) {
+	if ((ret != NULL) && (ctxt->input->buf != NULL)) {
 	    if (ctxt->input->buf->compressed > 0)
 		ret->compression = 9;
 	    else
@@ -14586,7 +14595,7 @@
     if (xmlParserInitialized != 0)
 	return;
 
-#if defined(WIN32) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
+#if defined(_WIN32) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
 	atexit(xmlCleanupParser);
 #endif
 
@@ -14668,6 +14677,20 @@
     xmlParserInitialized = 0;
 }
 
+#if defined(HAVE_ATTRIBUTE_DESTRUCTOR) && !defined(LIBXML_STATIC) && \
+    !defined(_WIN32)
+static void
+ATTRIBUTE_DESTRUCTOR
+xmlDestructor(void) {
+    /*
+     * Calling custom deallocation functions in a destructor can cause
+     * problems, for example with Nokogiri.
+     */
+    if (xmlFree == free)
+        xmlCleanupParser();
+}
+#endif
+
 /************************************************************************
  *									*
  *	New set (2.6.0) of simpler and more flexible APIs		*
@@ -14756,7 +14779,6 @@
     ctxt->vctxt.warning = xmlParserValidityWarning;
 #endif
     ctxt->record_info = 0;
-    ctxt->nbChars = 0;
     ctxt->checkIndex = 0;
     ctxt->inSubset = 0;
     ctxt->errNo = XML_ERR_OK;
diff --git a/src/parserInternals.c b/src/parserInternals.c
index 71b899c..e3828af 100644
--- a/src/parserInternals.c
+++ b/src/parserInternals.c
@@ -519,8 +519,6 @@
         } else
             /* 1-byte code */
             ctxt->input->cur++;
-
-        ctxt->nbChars++;
     } else {
         /*
          * Assume it's a fixed length encoding (1) with
@@ -533,7 +531,6 @@
         } else
             ctxt->input->col++;
         ctxt->input->cur++;
-        ctxt->nbChars++;
     }
     if (*ctxt->input->cur == 0)
         xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
@@ -677,7 +674,6 @@
 	    }
 	    if (*ctxt->input->cur == 0xD) {
 		if (ctxt->input->cur[1] == 0xA) {
-		    ctxt->nbChars++;
 		    ctxt->input->cur++;
 		}
 		return(0xA);
@@ -693,7 +689,6 @@
     *len = 1;
     if (*ctxt->input->cur == 0xD) {
 	if (ctxt->input->cur[1] == 0xA) {
-	    ctxt->nbChars++;
 	    ctxt->input->cur++;
 	}
 	return(0xA);
@@ -1753,7 +1748,6 @@
         ctxt->options |= XML_PARSE_NOENT;
     }
     ctxt->record_info = 0;
-    ctxt->nbChars = 0;
     ctxt->checkIndex = 0;
     ctxt->inSubset = 0;
     ctxt->errNo = XML_ERR_OK;
diff --git a/src/runtest.c b/src/runtest.c
index dc5e09a..0f178cb 100644
--- a/src/runtest.c
+++ b/src/runtest.c
@@ -105,6 +105,7 @@
 };
 
 static int update_results = 0;
+static char* temp_directory = NULL;
 static int checkTestFile(const char *filename);
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -1699,7 +1700,7 @@
     char *temp;
 
     nb_tests++;
-    temp = resultFilename(filename, "", ".res");
+    temp = resultFilename(filename, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "out of memory\n");
         fatalError();
@@ -1818,7 +1819,7 @@
 #endif
     if (doc == NULL)
         return(1);
-    temp = resultFilename(filename, "", ".res");
+    temp = resultFilename(filename, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "out of memory\n");
         fatalError();
@@ -2030,7 +2031,7 @@
     doc = xmlReadFile(filename, NULL, options);
     if (doc == NULL)
         return(1);
-    temp = resultFilename(filename, "", ".res");
+    temp = resultFilename(filename, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "Out of memory\n");
         fatalError();
@@ -2107,16 +2108,16 @@
 	    xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
 	}
 	res = compareFileMem(result, base, size);
-	if (res != 0) {
-	    fprintf(stderr, "Result for %s failed in %s\n", filename, result);
-	    return(-1);
-	}
     }
     if (doc != NULL) {
 	if (base != NULL)
 	    xmlFree((char *)base);
 	xmlFreeDoc(doc);
     }
+    if (res != 0) {
+        fprintf(stderr, "Result for %s failed in %s\n", filename, result);
+        return(-1);
+    }
     if (err != NULL) {
 	res = compareFileMem(err, testErrors, testErrorsSize);
 	if (res != 0) {
@@ -2177,7 +2178,7 @@
 
     nb_tests++;
     if (result != NULL) {
-	temp = resultFilename(filename, "", ".res");
+	temp = resultFilename(filename, temp_directory, ".res");
 	if (temp == NULL) {
 	    fprintf(stderr, "Out of memory\n");
 	    fatalError();
@@ -2406,7 +2407,7 @@
     int len, ret = 0;
     char *temp;
 
-    temp = resultFilename(filename, "", ".res");
+    temp = resultFilename(filename, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "Out of memory\n");
         fatalError();
@@ -2605,7 +2606,7 @@
 	return(-1);
     }
 
-    temp = resultFilename(filename, "", ".res");
+    temp = resultFilename(filename, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "Out of memory\n");
         fatalError();
@@ -2703,7 +2704,7 @@
     char str[1024];
     int res = 0, i, ret;
 
-    temp = resultFilename(filename, "", ".res");
+    temp = resultFilename(filename, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "Out of memory\n");
         fatalError();
@@ -3007,7 +3008,7 @@
 	return(-1);
     }
 
-    temp = resultFilename(result, "", ".res");
+    temp = resultFilename(result, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "Out of memory\n");
         fatalError();
@@ -3178,7 +3179,7 @@
 	return(-1);
     }
 
-    temp = resultFilename(result, "", ".res");
+    temp = resultFilename(result, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "Out of memory\n");
         fatalError();
@@ -3528,7 +3529,7 @@
         fprintf(stderr, "Failed to open %s\n", filename);
 	return(-1);
     }
-    temp = resultFilename(filename, "", ".res");
+    temp = resultFilename(filename, temp_directory, ".res");
     if (temp == NULL) {
         fprintf(stderr, "Out of memory\n");
         fatalError();
@@ -4565,6 +4566,8 @@
 	    update_results = 1;
         else if (!strcmp(argv[a], "-quiet"))
 	    tests_quiet = 1;
+        else if (!strcmp(argv[a], "--out"))
+	    temp_directory = argv[++a];
 	else {
 	    for (i = 0; testDescriptions[i].func != NULL; i++) {
 	        if (strstr(testDescriptions[i].desc, argv[a])) {
diff --git a/src/win32/Makefile.msvc b/src/win32/Makefile.msvc
index f6a0182..725b0ca 100644
--- a/src/win32/Makefile.msvc
+++ b/src/win32/Makefile.msvc
@@ -106,6 +106,11 @@
 LDFLAGS = $(LDFLAGS)
 !endif
 
+# append CFLAGS etc. passed on command line
+CPPFLAGS = $(CPPFLAGS) $(EXTRA_CPPFLAGS)
+CFLAGS = $(CFLAGS) $(EXTRA_CFLAGS)
+LDFLAGS = $(LDFLAGS) $(EXTRA_LDFLAGS)
+
 # Libxml object files.
 XML_OBJS = $(XML_INTDIR)\buf.obj\
 	$(XML_INTDIR)\c14n.obj\
diff --git a/src/win32/configure.js b/src/win32/configure.js
index e2ab31d..cec64c5 100644
--- a/src/win32/configure.js
+++ b/src/win32/configure.js
@@ -208,15 +208,15 @@
 	while (cf.AtEndOfStream != true) {
 		ln = cf.ReadLine();
 		s = new String(ln);
-		if (s.search(/^LIBXML_MAJOR_VERSION=/) != -1) {
-			vf.WriteLine(s);
-			verMajor = s.substring(s.indexOf("=") + 1, s.length);
-		} else if(s.search(/^LIBXML_MINOR_VERSION=/) != -1) {
-			vf.WriteLine(s);
-			verMinor = s.substring(s.indexOf("=") + 1, s.length);
-		} else if(s.search(/^LIBXML_MICRO_VERSION=/) != -1) {
-			vf.WriteLine(s);
-			verMicro = s.substring(s.indexOf("=") + 1, s.length);
+		if (m = s.match(/^m4_define\(\[MAJOR_VERSION\], (\w+)\)/)) {
+			vf.WriteLine("LIBXML_MAJOR_VERSION=" + m[1]);
+			verMajor = m[1];
+		} else if(m = s.match(/^m4_define\(\[MINOR_VERSION\], (\w+)\)/)) {
+			vf.WriteLine("LIBXML_MINOR_VERSION=" + m[1]);
+			verMinor = m[1];
+		} else if(m = s.match(/^m4_define\(\[MICRO_VERSION\], (\w+)\)/)) {
+			vf.WriteLine("LIBXML_MICRO_VERSION=" + m[1]);
+			verMicro = m[1];
 		} else if(s.search(/^LIBXML_MICRO_VERSION_SUFFIX=/) != -1) {
 			vf.WriteLine(s);
 			verMicroSuffix = s.substring(s.indexOf("=") + 1, s.length);
diff --git a/src/xmlIO.c b/src/xmlIO.c
index 7827dcf..57312b9 100644
--- a/src/xmlIO.c
+++ b/src/xmlIO.c
@@ -3401,18 +3401,12 @@
 		out->error = XML_IO_ENCODER;
 		return(-1);
 	    }
-            if (out->writecallback)
-	        nbchars = xmlBufUse(out->conv);
-            else
-                nbchars = ret;
+            nbchars = ret >= 0 ? ret : 0;
 	} else {
 	    ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
 	    if (ret != 0)
 	        return(-1);
-            if (out->writecallback)
-	        nbchars = xmlBufUse(out->buffer);
-            else
-                nbchars = chunk;
+            nbchars = chunk;
 	}
 	buf += chunk;
 	len -= chunk;
@@ -3599,19 +3593,13 @@
 		out->error = XML_IO_ENCODER;
 		return(-1);
 	    }
-            if (out->writecallback)
-	        nbchars = xmlBufUse(out->conv);
-            else
-                nbchars = ret;
+            nbchars = ret >= 0 ? ret : 0;
 	} else {
 	    ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
 	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
 	        return(-1);
             xmlBufAddLen(out->buffer, chunk);
-            if (out->writecallback)
-	        nbchars = xmlBufUse(out->buffer);
-            else
-                nbchars = chunk;
+            nbchars = chunk;
 	}
 	str += cons;
 	len -= cons;
diff --git a/src/xmlreader.c b/src/xmlreader.c
index b603c72..01adf74 100644
--- a/src/xmlreader.c
+++ b/src/xmlreader.c
@@ -48,6 +48,13 @@
 
 #define MAX_ERR_MSG_SIZE 64000
 
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+/* Keeping free objects can hide memory errors. */
+#define MAX_FREE_NODES 1
+#else
+#define MAX_FREE_NODES 100
+#endif
+
 /*
  * The following VA_COPY was coded following an example in
  * the Samba project.  It may not be sufficient for some
@@ -279,6 +286,59 @@
 }
 
 /**
+ * xmlTextReaderWalkRemoveRef:
+ * @data:  Contents of current link
+ * @user:  Value supplied by the user
+ *
+ * Returns 0 to abort the walk or 1 to continue
+ */
+static int
+xmlTextReaderWalkRemoveRef(const void *data, void *user)
+{
+    xmlRefPtr ref = (xmlRefPtr)data;
+    xmlAttrPtr attr = (xmlAttrPtr)user;
+
+    if (ref->attr == attr) { /* Matched: remove and terminate walk */
+        ref->name = xmlStrdup(attr->name);
+        ref->attr = NULL;
+        return 0;
+    }
+    return 1;
+}
+
+/**
+ * xmlTextReaderRemoveRef:
+ * @doc:  the document
+ * @attr:  the attribute
+ *
+ * Remove the given attribute from the Ref table maintained internally.
+ *
+ * Returns -1 if the lookup failed and 0 otherwise
+ */
+static int
+xmlTextReaderRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
+    xmlListPtr ref_list;
+    xmlRefTablePtr table;
+    xmlChar *ID;
+
+    if (doc == NULL) return(-1);
+    if (attr == NULL) return(-1);
+    table = (xmlRefTablePtr) doc->refs;
+    if (table == NULL)
+        return(-1);
+
+    ID = xmlNodeListGetString(doc, attr->children, 1);
+    if (ID == NULL)
+        return(-1);
+    ref_list = xmlHashLookup(table, ID);
+    xmlFree(ID);
+    if(ref_list == NULL)
+        return (-1);
+    xmlListWalk(ref_list, xmlTextReaderWalkRemoveRef, attr);
+    return(0);
+}
+
+/**
  * xmlTextReaderFreeProp:
  * @reader:  the xmlTextReaderPtr used
  * @cur:  the node
@@ -299,18 +359,20 @@
 	xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
 
     /* Check for ID removal -> leading to invalid references ! */
-    if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
-	((cur->parent->doc->intSubset != NULL) ||
-	 (cur->parent->doc->extSubset != NULL))) {
+    if ((cur->parent != NULL) && (cur->parent->doc != NULL)) {
         if (xmlIsID(cur->parent->doc, cur->parent, cur))
 	    xmlTextReaderRemoveID(cur->parent->doc, cur);
+	if (((cur->parent->doc->intSubset != NULL) ||
+	     (cur->parent->doc->extSubset != NULL)) &&
+            (xmlIsRef(cur->parent->doc, cur->parent, cur)))
+            xmlTextReaderRemoveRef(cur->parent->doc, cur);
     }
     if (cur->children != NULL)
         xmlTextReaderFreeNodeList(reader, cur->children);
 
     DICT_FREE(cur->name);
     if ((reader != NULL) && (reader->ctxt != NULL) &&
-        (reader->ctxt->freeAttrsNr < 100)) {
+        (reader->ctxt->freeAttrsNr < MAX_FREE_NODES)) {
         cur->next = reader->ctxt->freeAttrs;
 	reader->ctxt->freeAttrs = cur;
 	reader->ctxt->freeAttrsNr++;
@@ -411,7 +473,7 @@
 	    if (((cur->type == XML_ELEMENT_NODE) ||
 		 (cur->type == XML_TEXT_NODE)) &&
 	        (reader != NULL) && (reader->ctxt != NULL) &&
-		(reader->ctxt->freeElemsNr < 100)) {
+		(reader->ctxt->freeElemsNr < MAX_FREE_NODES)) {
 	        cur->next = reader->ctxt->freeElems;
 		reader->ctxt->freeElems = cur;
 		reader->ctxt->freeElemsNr++;
@@ -499,7 +561,7 @@
     if (((cur->type == XML_ELEMENT_NODE) ||
 	 (cur->type == XML_TEXT_NODE)) &&
 	(reader != NULL) && (reader->ctxt != NULL) &&
-	(reader->ctxt->freeElemsNr < 100)) {
+	(reader->ctxt->freeElemsNr < MAX_FREE_NODES)) {
 	cur->next = reader->ctxt->freeElems;
 	reader->ctxt->freeElems = cur;
 	reader->ctxt->freeElemsNr++;
@@ -1436,6 +1498,8 @@
             (reader->node->prev->type != XML_DTD_NODE)) {
 	    xmlNodePtr tmp = reader->node->prev;
 	    if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
+                if (oldnode == tmp)
+                    oldnode = NULL;
 		xmlUnlinkNode(tmp);
 		xmlTextReaderFreeNode(reader, tmp);
 	    }
@@ -2260,6 +2324,7 @@
     if (reader->ctxt != NULL) {
         if (reader->dict == reader->ctxt->dict)
 	    reader->dict = NULL;
+#ifdef LIBXML_VALID_ENABLED
 	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
 	    (reader->ctxt->vctxt.vstateMax > 0)){
 #ifdef LIBXML_REGEXP_ENABLED
@@ -2270,6 +2335,7 @@
 	    reader->ctxt->vctxt.vstateTab = NULL;
 	    reader->ctxt->vctxt.vstateMax = 0;
 	}
+#endif /* LIBXML_VALID_ENABLED */
 	if (reader->ctxt->myDoc != NULL) {
 	    if (reader->preserve == 0)
 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
diff --git a/src/xmlsave.c b/src/xmlsave.c
index 0e698bb..61a4045 100644
--- a/src/xmlsave.c
+++ b/src/xmlsave.c
@@ -590,7 +590,6 @@
 static void
 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
 #endif
-static void xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
 static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur);
 void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
 static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur);
@@ -705,6 +704,7 @@
 static void
 xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) {
     xmlOutputBufferPtr buf;
+    xmlNodePtr cur;
     int format, level;
 
     if (dtd == NULL) return;
@@ -742,7 +742,9 @@
     level = ctxt->level;
     ctxt->format = 0;
     ctxt->level = -1;
-    xmlNodeListDumpOutput(ctxt, dtd->children);
+    for (cur = dtd->children; cur != NULL; cur = cur->next) {
+        xmlNodeDumpOutputInternal(ctxt, cur);
+    }
     ctxt->format = format;
     ctxt->level = level;
     xmlOutputBufferWrite(buf, 2, "]>");
@@ -776,58 +778,9 @@
     xmlOutputBufferWrite(buf, 1, "\"");
 }
 
-/**
- * xmlAttrListDumpOutput:
- * @buf:  the XML buffer output
- * @doc:  the document
- * @cur:  the first attribute pointer
- * @encoding:  an optional encoding string
- *
- * Dump a list of XML attributes
- */
-static void
-xmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) {
-    if (cur == NULL) return;
-    while (cur != NULL) {
-        xmlAttrDumpOutput(ctxt, cur);
-	cur = cur->next;
-    }
-}
-
-
-
-/**
- * xmlNodeListDumpOutput:
- * @cur:  the first node
- *
- * Dump an XML node list, recursive behaviour, children are printed too.
- */
-static void
-xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
-    xmlOutputBufferPtr buf;
-
-    if (cur == NULL) return;
-    buf = ctxt->buf;
-    while (cur != NULL) {
-	if ((ctxt->format == 1) && (xmlIndentTreeOutput) &&
-	    ((cur->type == XML_ELEMENT_NODE) ||
-	     (cur->type == XML_COMMENT_NODE) ||
-	     (cur->type == XML_PI_NODE)))
-	    xmlOutputBufferWrite(buf, ctxt->indent_size *
-	                         (ctxt->level > ctxt->indent_nr ?
-				  ctxt->indent_nr : ctxt->level),
-				 ctxt->indent);
-        xmlNodeDumpOutputInternal(ctxt, cur);
-	if (ctxt->format == 1) {
-	    xmlOutputBufferWrite(buf, 1, "\n");
-	}
-	cur = cur->next;
-    }
-}
-
 #ifdef LIBXML_HTML_ENABLED
 /**
- * xmlNodeDumpOutputInternal:
+ * htmlNodeDumpOutputInternal:
  * @cur:  the current node
  *
  * Dump an HTML node, recursive behaviour, children are printed too.
@@ -893,57 +846,111 @@
  */
 static void
 xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
-    int format;
-    xmlNodePtr tmp;
+    int format = ctxt->format;
+    xmlNodePtr tmp, root, unformattedNode = NULL;
+    xmlAttrPtr attr;
     xmlChar *start, *end;
     xmlOutputBufferPtr buf;
 
     if (cur == NULL) return;
     buf = ctxt->buf;
-    if (cur->type == XML_XINCLUDE_START)
-	return;
-    if (cur->type == XML_XINCLUDE_END)
-	return;
-    if ((cur->type == XML_DOCUMENT_NODE) ||
-        (cur->type == XML_HTML_DOCUMENT_NODE)) {
-	xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
-	return;
-    }
-#ifdef LIBXML_HTML_ENABLED
-    if (ctxt->options & XML_SAVE_XHTML) {
-        xhtmlNodeDumpOutput(ctxt, cur);
-        return;
-    }
-    if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
-         (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
-         ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
-        (ctxt->options & XML_SAVE_AS_HTML)) {
-	htmlNodeDumpOutputInternal(ctxt, cur);
-	return;
-    }
-#endif
-    if (cur->type == XML_DTD_NODE) {
-        xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
-	return;
-    }
-    if (cur->type == XML_DOCUMENT_FRAG_NODE) {
-        xmlNodeListDumpOutput(ctxt, cur->children);
-	return;
-    }
-    if (cur->type == XML_ELEMENT_DECL) {
-        xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
-	return;
-    }
-    if (cur->type == XML_ATTRIBUTE_DECL) {
-        xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
-	return;
-    }
-    if (cur->type == XML_ENTITY_DECL) {
-        xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
-	return;
-    }
-    if (cur->type == XML_TEXT_NODE) {
-	if (cur->content != NULL) {
+
+    root = cur;
+    while (1) {
+        switch (cur->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+	    xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
+	    break;
+
+        case XML_DTD_NODE:
+            xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
+            break;
+
+        case XML_DOCUMENT_FRAG_NODE:
+            if (cur->children != NULL) {
+                cur = cur->children;
+                continue;
+            }
+	    break;
+
+        case XML_ELEMENT_DECL:
+            xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
+            break;
+
+        case XML_ATTRIBUTE_DECL:
+            xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
+            break;
+
+        case XML_ENTITY_DECL:
+            xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
+            break;
+
+        case XML_ELEMENT_NODE:
+	    if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+		xmlOutputBufferWrite(buf, ctxt->indent_size *
+				     (ctxt->level > ctxt->indent_nr ?
+				      ctxt->indent_nr : ctxt->level),
+				     ctxt->indent);
+
+            xmlOutputBufferWrite(buf, 1, "<");
+            if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+                xmlOutputBufferWrite(buf, 1, ":");
+            }
+            xmlOutputBufferWriteString(buf, (const char *)cur->name);
+            if (cur->nsDef)
+                xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
+            for (attr = cur->properties; attr != NULL; attr = attr->next)
+                xmlAttrDumpOutput(ctxt, attr);
+
+            if (cur->children == NULL) {
+                if ((ctxt->options & XML_SAVE_NO_EMPTY) == 0) {
+                    if (ctxt->format == 2)
+                        xmlOutputBufferWriteWSNonSig(ctxt, 0);
+                    xmlOutputBufferWrite(buf, 2, "/>");
+                } else {
+                    if (ctxt->format == 2)
+                        xmlOutputBufferWriteWSNonSig(ctxt, 1);
+                    xmlOutputBufferWrite(buf, 3, "></");
+                    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                        xmlOutputBufferWriteString(buf,
+                                (const char *)cur->ns->prefix);
+                        xmlOutputBufferWrite(buf, 1, ":");
+                    }
+                    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                    if (ctxt->format == 2)
+                        xmlOutputBufferWriteWSNonSig(ctxt, 0);
+                    xmlOutputBufferWrite(buf, 1, ">");
+                }
+            } else {
+                if (ctxt->format == 1) {
+                    tmp = cur->children;
+                    while (tmp != NULL) {
+                        if ((tmp->type == XML_TEXT_NODE) ||
+                            (tmp->type == XML_CDATA_SECTION_NODE) ||
+                            (tmp->type == XML_ENTITY_REF_NODE)) {
+                            ctxt->format = 0;
+                            unformattedNode = cur;
+                            break;
+                        }
+                        tmp = tmp->next;
+                    }
+                }
+                if (ctxt->format == 2)
+                    xmlOutputBufferWriteWSNonSig(ctxt, 1);
+                xmlOutputBufferWrite(buf, 1, ">");
+                if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
+                if (ctxt->level >= 0) ctxt->level++;
+                cur = cur->children;
+                continue;
+            }
+
+            break;
+
+        case XML_TEXT_NODE:
+	    if (cur->content == NULL)
+                break;
 	    if (cur->name != xmlStringTextNoenc) {
                 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
 	    } else {
@@ -952,139 +959,140 @@
 		 */
 		xmlOutputBufferWriteString(buf, (const char *) cur->content);
 	    }
-	}
+	    break;
 
-	return;
-    }
-    if (cur->type == XML_PI_NODE) {
-	if (cur->content != NULL) {
-	    xmlOutputBufferWrite(buf, 2, "<?");
-	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-	    if (cur->content != NULL) {
-	        if (ctxt->format == 2)
-	            xmlOutputBufferWriteWSNonSig(ctxt, 0);
-	        else
-	            xmlOutputBufferWrite(buf, 1, " ");
-		xmlOutputBufferWriteString(buf, (const char *)cur->content);
-	    }
-	    xmlOutputBufferWrite(buf, 2, "?>");
-	} else {
-	    xmlOutputBufferWrite(buf, 2, "<?");
-	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-	    if (ctxt->format == 2)
-	        xmlOutputBufferWriteWSNonSig(ctxt, 0);
-	    xmlOutputBufferWrite(buf, 2, "?>");
-	}
-	return;
-    }
-    if (cur->type == XML_COMMENT_NODE) {
-	if (cur->content != NULL) {
-	    xmlOutputBufferWrite(buf, 4, "<!--");
-	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
-	    xmlOutputBufferWrite(buf, 3, "-->");
-	}
-	return;
-    }
-    if (cur->type == XML_ENTITY_REF_NODE) {
-        xmlOutputBufferWrite(buf, 1, "&");
-	xmlOutputBufferWriteString(buf, (const char *)cur->name);
-        xmlOutputBufferWrite(buf, 1, ";");
-	return;
-    }
-    if (cur->type == XML_CDATA_SECTION_NODE) {
-	if (cur->content == NULL || *cur->content == '\0') {
-	    xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
-	} else {
-	    start = end = cur->content;
-	    while (*end != '\0') {
-		if ((*end == ']') && (*(end + 1) == ']') &&
-		    (*(end + 2) == '>')) {
-		    end = end + 2;
-		    xmlOutputBufferWrite(buf, 9, "<![CDATA[");
-		    xmlOutputBufferWrite(buf, end - start, (const char *)start);
-		    xmlOutputBufferWrite(buf, 3, "]]>");
-		    start = end;
-		}
-		end++;
-	    }
-	    if (start != end) {
-		xmlOutputBufferWrite(buf, 9, "<![CDATA[");
-		xmlOutputBufferWriteString(buf, (const char *)start);
-		xmlOutputBufferWrite(buf, 3, "]]>");
-	    }
-	}
-	return;
-    }
-    if (cur->type == XML_ATTRIBUTE_NODE) {
-	xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
-	return;
-    }
-    if (cur->type == XML_NAMESPACE_DECL) {
-	xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
-	return;
-    }
+        case XML_PI_NODE:
+	    if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+		xmlOutputBufferWrite(buf, ctxt->indent_size *
+				     (ctxt->level > ctxt->indent_nr ?
+				      ctxt->indent_nr : ctxt->level),
+				     ctxt->indent);
 
-    format = ctxt->format;
-    if (format == 1) {
-	tmp = cur->children;
-	while (tmp != NULL) {
-	    if ((tmp->type == XML_TEXT_NODE) ||
-		(tmp->type == XML_CDATA_SECTION_NODE) ||
-		(tmp->type == XML_ENTITY_REF_NODE)) {
-		ctxt->format = 0;
-		break;
-	    }
-	    tmp = tmp->next;
-	}
-    }
-    xmlOutputBufferWrite(buf, 1, "<");
-    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
-        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
-	xmlOutputBufferWrite(buf, 1, ":");
-    }
+            if (cur->content != NULL) {
+                xmlOutputBufferWrite(buf, 2, "<?");
+                xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                if (cur->content != NULL) {
+                    if (ctxt->format == 2)
+                        xmlOutputBufferWriteWSNonSig(ctxt, 0);
+                    else
+                        xmlOutputBufferWrite(buf, 1, " ");
+                    xmlOutputBufferWriteString(buf,
+                            (const char *)cur->content);
+                }
+                xmlOutputBufferWrite(buf, 2, "?>");
+            } else {
+                xmlOutputBufferWrite(buf, 2, "<?");
+                xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                if (ctxt->format == 2)
+                    xmlOutputBufferWriteWSNonSig(ctxt, 0);
+                xmlOutputBufferWrite(buf, 2, "?>");
+            }
+            break;
 
-    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-    if (cur->nsDef)
-        xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
-    if (cur->properties != NULL)
-        xmlAttrListDumpOutput(ctxt, cur->properties);
+        case XML_COMMENT_NODE:
+	    if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+		xmlOutputBufferWrite(buf, ctxt->indent_size *
+				     (ctxt->level > ctxt->indent_nr ?
+				      ctxt->indent_nr : ctxt->level),
+				     ctxt->indent);
 
-    if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) &&
-	(cur->children == NULL) && ((ctxt->options & XML_SAVE_NO_EMPTY) == 0)) {
-        if (ctxt->format == 2)
-            xmlOutputBufferWriteWSNonSig(ctxt, 0);
-        xmlOutputBufferWrite(buf, 2, "/>");
-	ctxt->format = format;
-	return;
-    }
-    if (ctxt->format == 2)
-        xmlOutputBufferWriteWSNonSig(ctxt, 1);
-    xmlOutputBufferWrite(buf, 1, ">");
-    if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
-	xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
-    }
-    if (cur->children != NULL) {
-	if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
-	if (ctxt->level >= 0) ctxt->level++;
-	xmlNodeListDumpOutput(ctxt, cur->children);
-	if (ctxt->level > 0) ctxt->level--;
-	if ((xmlIndentTreeOutput) && (ctxt->format == 1))
-	    xmlOutputBufferWrite(buf, ctxt->indent_size *
-	                         (ctxt->level > ctxt->indent_nr ?
-				  ctxt->indent_nr : ctxt->level),
-				 ctxt->indent);
-    }
-    xmlOutputBufferWrite(buf, 2, "</");
-    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
-        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
-	xmlOutputBufferWrite(buf, 1, ":");
-    }
+            if (cur->content != NULL) {
+                xmlOutputBufferWrite(buf, 4, "<!--");
+                xmlOutputBufferWriteString(buf, (const char *)cur->content);
+                xmlOutputBufferWrite(buf, 3, "-->");
+            }
+            break;
 
-    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-    if (ctxt->format == 2)
-        xmlOutputBufferWriteWSNonSig(ctxt, 0);
-    xmlOutputBufferWrite(buf, 1, ">");
-    ctxt->format = format;
+        case XML_ENTITY_REF_NODE:
+            xmlOutputBufferWrite(buf, 1, "&");
+            xmlOutputBufferWriteString(buf, (const char *)cur->name);
+            xmlOutputBufferWrite(buf, 1, ";");
+            break;
+
+        case XML_CDATA_SECTION_NODE:
+            if (cur->content == NULL || *cur->content == '\0') {
+                xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
+            } else {
+                start = end = cur->content;
+                while (*end != '\0') {
+                    if ((*end == ']') && (*(end + 1) == ']') &&
+                        (*(end + 2) == '>')) {
+                        end = end + 2;
+                        xmlOutputBufferWrite(buf, 9, "<![CDATA[");
+                        xmlOutputBufferWrite(buf, end - start,
+                                (const char *)start);
+                        xmlOutputBufferWrite(buf, 3, "]]>");
+                        start = end;
+                    }
+                    end++;
+                }
+                if (start != end) {
+                    xmlOutputBufferWrite(buf, 9, "<![CDATA[");
+                    xmlOutputBufferWriteString(buf, (const char *)start);
+                    xmlOutputBufferWrite(buf, 3, "]]>");
+                }
+            }
+            break;
+
+        case XML_ATTRIBUTE_NODE:
+            xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
+            break;
+
+        case XML_NAMESPACE_DECL:
+            xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
+            break;
+
+        default:
+            break;
+        }
+
+        while (1) {
+            if (cur == root)
+                return;
+            if ((ctxt->format == 1) &&
+                (cur->type != XML_XINCLUDE_START) &&
+                (cur->type != XML_XINCLUDE_END))
+                xmlOutputBufferWrite(buf, 1, "\n");
+            if (cur->next != NULL) {
+                cur = cur->next;
+                break;
+            }
+
+            /*
+             * The parent should never be NULL here but we want to handle
+             * corrupted documents gracefully.
+             */
+            if (cur->parent == NULL)
+                return;
+            cur = cur->parent;
+
+            if (cur->type == XML_ELEMENT_NODE) {
+                if (ctxt->level > 0) ctxt->level--;
+                if ((xmlIndentTreeOutput) && (ctxt->format == 1))
+                    xmlOutputBufferWrite(buf, ctxt->indent_size *
+                                         (ctxt->level > ctxt->indent_nr ?
+                                          ctxt->indent_nr : ctxt->level),
+                                         ctxt->indent);
+
+                xmlOutputBufferWrite(buf, 2, "</");
+                if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                    xmlOutputBufferWriteString(buf,
+                            (const char *)cur->ns->prefix);
+                    xmlOutputBufferWrite(buf, 1, ":");
+                }
+
+                xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                if (ctxt->format == 2)
+                    xmlOutputBufferWriteWSNonSig(ctxt, 0);
+                xmlOutputBufferWrite(buf, 1, ">");
+
+                if (cur == unformattedNode) {
+                    ctxt->format = format;
+                    unformattedNode = NULL;
+                }
+            }
+        }
+    }
 }
 
 /**
@@ -1224,7 +1232,9 @@
 		else
 #endif
 		    xmlNodeDumpOutputInternal(ctxt, child);
-		xmlOutputBufferWrite(buf, 1, "\n");
+                if ((child->type != XML_XINCLUDE_START) &&
+                    (child->type != XML_XINCLUDE_END))
+                    xmlOutputBufferWrite(buf, 1, "\n");
 		child = child->next;
 	    }
 	}
@@ -1396,40 +1406,6 @@
 }
 
 /**
- * xhtmlNodeListDumpOutput:
- * @buf:  the XML buffer output
- * @doc:  the XHTML document
- * @cur:  the first node
- * @level: the imbrication level for indenting
- * @format: is formatting allowed
- * @encoding:  an optional encoding string
- *
- * Dump an XML node list, recursive behaviour, children are printed too.
- * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1
- * or xmlKeepBlanksDefault(0) was called
- */
-static void
-xhtmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
-    xmlOutputBufferPtr buf;
-
-    if (cur == NULL) return;
-    buf = ctxt->buf;
-    while (cur != NULL) {
-	if ((ctxt->format == 1) && (xmlIndentTreeOutput) &&
-	    (cur->type == XML_ELEMENT_NODE))
-	    xmlOutputBufferWrite(buf, ctxt->indent_size *
-	                         (ctxt->level > ctxt->indent_nr ?
-				  ctxt->indent_nr : ctxt->level),
-				 ctxt->indent);
-        xhtmlNodeDumpOutput(ctxt, cur);
-	if (ctxt->format == 1) {
-	    xmlOutputBufferWrite(buf, 1, "\n");
-	}
-	cur = cur->next;
-    }
-}
-
-/**
  * xhtmlNodeDumpOutput:
  * @buf:  the XML buffer output
  * @doc:  the XHTML document
@@ -1442,48 +1418,195 @@
  */
 static void
 xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
-    int format, addmeta = 0;
-    xmlNodePtr tmp;
+    int format = ctxt->format, addmeta;
+    xmlNodePtr tmp, root, unformattedNode = NULL;
     xmlChar *start, *end;
-    xmlOutputBufferPtr buf;
+    xmlOutputBufferPtr buf = ctxt->buf;
 
     if (cur == NULL) return;
-    if ((cur->type == XML_DOCUMENT_NODE) ||
-        (cur->type == XML_HTML_DOCUMENT_NODE)) {
-        xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
-	return;
-    }
-    if (cur->type == XML_XINCLUDE_START)
-	return;
-    if (cur->type == XML_XINCLUDE_END)
-	return;
-    if (cur->type == XML_NAMESPACE_DECL) {
-	xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
-	return;
-    }
-    if (cur->type == XML_DTD_NODE) {
-        xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
-	return;
-    }
-    if (cur->type == XML_DOCUMENT_FRAG_NODE) {
-        xhtmlNodeListDumpOutput(ctxt, cur->children);
-	return;
-    }
-    buf = ctxt->buf;
-    if (cur->type == XML_ELEMENT_DECL) {
-        xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
-	return;
-    }
-    if (cur->type == XML_ATTRIBUTE_DECL) {
-        xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
-	return;
-    }
-    if (cur->type == XML_ENTITY_DECL) {
-        xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
-	return;
-    }
-    if (cur->type == XML_TEXT_NODE) {
-	if (cur->content != NULL) {
+
+    root = cur;
+    while (1) {
+        switch (cur->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+            xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur);
+	    break;
+
+        case XML_NAMESPACE_DECL:
+	    xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur);
+	    break;
+
+        case XML_DTD_NODE:
+            xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur);
+	    break;
+
+        case XML_DOCUMENT_FRAG_NODE:
+            if (cur->children) {
+                cur = cur->children;
+                continue;
+            }
+            break;
+
+        case XML_ELEMENT_DECL:
+            xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
+	    break;
+
+        case XML_ATTRIBUTE_DECL:
+            xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
+	    break;
+
+        case XML_ENTITY_DECL:
+            xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
+	    break;
+
+        case XML_ELEMENT_NODE:
+            addmeta = 0;
+
+	    if ((cur != root) && (ctxt->format == 1) && (xmlIndentTreeOutput))
+		xmlOutputBufferWrite(buf, ctxt->indent_size *
+				     (ctxt->level > ctxt->indent_nr ?
+				      ctxt->indent_nr : ctxt->level),
+				     ctxt->indent);
+
+            xmlOutputBufferWrite(buf, 1, "<");
+            if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+                xmlOutputBufferWrite(buf, 1, ":");
+            }
+
+            xmlOutputBufferWriteString(buf, (const char *)cur->name);
+            if (cur->nsDef)
+                xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
+            if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
+                (cur->ns == NULL) && (cur->nsDef == NULL))) {
+                /*
+                 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
+                 */
+                xmlOutputBufferWriteString(buf,
+                        " xmlns=\"http://www.w3.org/1999/xhtml\"");
+            }
+            if (cur->properties != NULL)
+                xhtmlAttrListDumpOutput(ctxt, cur->properties);
+
+            if ((cur->parent != NULL) &&
+                (cur->parent->parent == (xmlNodePtr) cur->doc) &&
+                xmlStrEqual(cur->name, BAD_CAST"head") &&
+                xmlStrEqual(cur->parent->name, BAD_CAST"html")) {
+
+                tmp = cur->children;
+                while (tmp != NULL) {
+                    if (xmlStrEqual(tmp->name, BAD_CAST"meta")) {
+                        xmlChar *httpequiv;
+
+                        httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv");
+                        if (httpequiv != NULL) {
+                            if (xmlStrcasecmp(httpequiv,
+                                        BAD_CAST"Content-Type") == 0) {
+                                xmlFree(httpequiv);
+                                break;
+                            }
+                            xmlFree(httpequiv);
+                        }
+                    }
+                    tmp = tmp->next;
+                }
+                if (tmp == NULL)
+                    addmeta = 1;
+            }
+
+            if (cur->children == NULL) {
+                if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
+                    ((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) {
+                    /*
+                     * C.2. Empty Elements
+                     */
+                    xmlOutputBufferWrite(buf, 3, " />");
+                } else {
+                    if (addmeta == 1) {
+                        xmlOutputBufferWrite(buf, 1, ">");
+                        if (ctxt->format == 1) {
+                            xmlOutputBufferWrite(buf, 1, "\n");
+                            if (xmlIndentTreeOutput)
+                                xmlOutputBufferWrite(buf, ctxt->indent_size *
+                                    (ctxt->level + 1 > ctxt->indent_nr ?
+                                    ctxt->indent_nr : ctxt->level + 1),
+                                    ctxt->indent);
+                        }
+                        xmlOutputBufferWriteString(buf,
+                                "<meta http-equiv=\"Content-Type\" "
+                                "content=\"text/html; charset=");
+                        if (ctxt->encoding) {
+                            xmlOutputBufferWriteString(buf,
+                                    (const char *)ctxt->encoding);
+                        } else {
+                            xmlOutputBufferWrite(buf, 5, "UTF-8");
+                        }
+                        xmlOutputBufferWrite(buf, 4, "\" />");
+                        if (ctxt->format == 1)
+                            xmlOutputBufferWrite(buf, 1, "\n");
+                    } else {
+                        xmlOutputBufferWrite(buf, 1, ">");
+                    }
+                    /*
+                     * C.3. Element Minimization and Empty Element Content
+                     */
+                    xmlOutputBufferWrite(buf, 2, "</");
+                    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                        xmlOutputBufferWriteString(buf,
+                                (const char *)cur->ns->prefix);
+                        xmlOutputBufferWrite(buf, 1, ":");
+                    }
+                    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                    xmlOutputBufferWrite(buf, 1, ">");
+                }
+            } else {
+                xmlOutputBufferWrite(buf, 1, ">");
+                if (addmeta == 1) {
+                    if (ctxt->format == 1) {
+                        xmlOutputBufferWrite(buf, 1, "\n");
+                        if (xmlIndentTreeOutput)
+                            xmlOutputBufferWrite(buf, ctxt->indent_size *
+                                (ctxt->level + 1 > ctxt->indent_nr ?
+                                ctxt->indent_nr : ctxt->level + 1),
+                                ctxt->indent);
+                    }
+                    xmlOutputBufferWriteString(buf,
+                            "<meta http-equiv=\"Content-Type\" "
+                            "content=\"text/html; charset=");
+                    if (ctxt->encoding) {
+                        xmlOutputBufferWriteString(buf,
+                                (const char *)ctxt->encoding);
+                    } else {
+                        xmlOutputBufferWrite(buf, 5, "UTF-8");
+                    }
+                    xmlOutputBufferWrite(buf, 4, "\" />");
+                }
+
+                if (ctxt->format == 1) {
+                    tmp = cur->children;
+                    while (tmp != NULL) {
+                        if ((tmp->type == XML_TEXT_NODE) ||
+                            (tmp->type == XML_ENTITY_REF_NODE)) {
+                            unformattedNode = cur;
+                            ctxt->format = 0;
+                            break;
+                        }
+                        tmp = tmp->next;
+                    }
+                }
+
+                if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n");
+                if (ctxt->level >= 0) ctxt->level++;
+                cur = cur->children;
+                continue;
+            }
+
+            break;
+
+        case XML_TEXT_NODE:
+	    if (cur->content == NULL)
+                break;
 	    if ((cur->name == xmlStringText) ||
 		(cur->name != xmlStringTextNoenc)) {
                 xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
@@ -1493,286 +1616,115 @@
 		 */
 		xmlOutputBufferWriteString(buf, (const char *) cur->content);
 	    }
-	}
+	    break;
 
-	return;
-    }
-    if (cur->type == XML_PI_NODE) {
-	if (cur->content != NULL) {
-	    xmlOutputBufferWrite(buf, 2, "<?");
-	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-	    if (cur->content != NULL) {
-		xmlOutputBufferWrite(buf, 1, " ");
-		xmlOutputBufferWriteString(buf, (const char *)cur->content);
-	    }
-	    xmlOutputBufferWrite(buf, 2, "?>");
-	} else {
-	    xmlOutputBufferWrite(buf, 2, "<?");
-	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-	    xmlOutputBufferWrite(buf, 2, "?>");
-	}
-	return;
-    }
-    if (cur->type == XML_COMMENT_NODE) {
-	if (cur->content != NULL) {
-	    xmlOutputBufferWrite(buf, 4, "<!--");
-	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
-	    xmlOutputBufferWrite(buf, 3, "-->");
-	}
-	return;
-    }
-    if (cur->type == XML_ENTITY_REF_NODE) {
-        xmlOutputBufferWrite(buf, 1, "&");
-	xmlOutputBufferWriteString(buf, (const char *)cur->name);
-        xmlOutputBufferWrite(buf, 1, ";");
-	return;
-    }
-    if (cur->type == XML_CDATA_SECTION_NODE) {
-	if (cur->content == NULL || *cur->content == '\0') {
-	    xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
-	} else {
-	    start = end = cur->content;
-	    while (*end != '\0') {
-		if (*end == ']' && *(end + 1) == ']' && *(end + 2) == '>') {
-		    end = end + 2;
-		    xmlOutputBufferWrite(buf, 9, "<![CDATA[");
-		    xmlOutputBufferWrite(buf, end - start, (const char *)start);
-		    xmlOutputBufferWrite(buf, 3, "]]>");
-		    start = end;
-		}
-		end++;
-	    }
-	    if (start != end) {
-		xmlOutputBufferWrite(buf, 9, "<![CDATA[");
-		xmlOutputBufferWriteString(buf, (const char *)start);
-		xmlOutputBufferWrite(buf, 3, "]]>");
-	    }
-	}
-	return;
-    }
-    if (cur->type == XML_ATTRIBUTE_NODE) {
-        xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
-	return;
-    }
+        case XML_PI_NODE:
+            if (cur->content != NULL) {
+                xmlOutputBufferWrite(buf, 2, "<?");
+                xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                if (cur->content != NULL) {
+                    xmlOutputBufferWrite(buf, 1, " ");
+                    xmlOutputBufferWriteString(buf,
+                            (const char *)cur->content);
+                }
+                xmlOutputBufferWrite(buf, 2, "?>");
+            } else {
+                xmlOutputBufferWrite(buf, 2, "<?");
+                xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                xmlOutputBufferWrite(buf, 2, "?>");
+            }
+            break;
 
-    format = ctxt->format;
-    if (format == 1) {
-	tmp = cur->children;
-	while (tmp != NULL) {
-	    if ((tmp->type == XML_TEXT_NODE) ||
-		(tmp->type == XML_ENTITY_REF_NODE)) {
-		format = 0;
-		break;
-	    }
-	    tmp = tmp->next;
-	}
-    }
-    xmlOutputBufferWrite(buf, 1, "<");
-    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
-        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
-	xmlOutputBufferWrite(buf, 1, ":");
-    }
+        case XML_COMMENT_NODE:
+            if (cur->content != NULL) {
+                xmlOutputBufferWrite(buf, 4, "<!--");
+                xmlOutputBufferWriteString(buf, (const char *)cur->content);
+                xmlOutputBufferWrite(buf, 3, "-->");
+            }
+            break;
 
-    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-    if (cur->nsDef)
-        xmlNsListDumpOutputCtxt(ctxt, cur->nsDef);
-    if ((xmlStrEqual(cur->name, BAD_CAST "html") &&
-	(cur->ns == NULL) && (cur->nsDef == NULL))) {
-	/*
-	 * 3.1.1. Strictly Conforming Documents A.3.1.1 3/
-	 */
-	xmlOutputBufferWriteString(buf,
-		" xmlns=\"http://www.w3.org/1999/xhtml\"");
-    }
-    if (cur->properties != NULL)
-        xhtmlAttrListDumpOutput(ctxt, cur->properties);
+        case XML_ENTITY_REF_NODE:
+            xmlOutputBufferWrite(buf, 1, "&");
+            xmlOutputBufferWriteString(buf, (const char *)cur->name);
+            xmlOutputBufferWrite(buf, 1, ";");
+            break;
 
-    if ((cur->type == XML_ELEMENT_NODE) &&
-        (cur->parent != NULL) &&
-        (cur->parent->parent == (xmlNodePtr) cur->doc) &&
-        xmlStrEqual(cur->name, BAD_CAST"head") &&
-        xmlStrEqual(cur->parent->name, BAD_CAST"html")) {
-
-        tmp = cur->children;
-        while (tmp != NULL) {
-            if (xmlStrEqual(tmp->name, BAD_CAST"meta")) {
-                xmlChar *httpequiv;
-
-                httpequiv = xmlGetProp(tmp, BAD_CAST"http-equiv");
-                if (httpequiv != NULL) {
-                    if (xmlStrcasecmp(httpequiv, BAD_CAST"Content-Type") == 0) {
-                        xmlFree(httpequiv);
-                        break;
+        case XML_CDATA_SECTION_NODE:
+            if (cur->content == NULL || *cur->content == '\0') {
+                xmlOutputBufferWrite(buf, 12, "<![CDATA[]]>");
+            } else {
+                start = end = cur->content;
+                while (*end != '\0') {
+                    if (*end == ']' && *(end + 1) == ']' &&
+                        *(end + 2) == '>') {
+                        end = end + 2;
+                        xmlOutputBufferWrite(buf, 9, "<![CDATA[");
+                        xmlOutputBufferWrite(buf, end - start,
+                                (const char *)start);
+                        xmlOutputBufferWrite(buf, 3, "]]>");
+                        start = end;
                     }
-                    xmlFree(httpequiv);
+                    end++;
+                }
+                if (start != end) {
+                    xmlOutputBufferWrite(buf, 9, "<![CDATA[");
+                    xmlOutputBufferWriteString(buf, (const char *)start);
+                    xmlOutputBufferWrite(buf, 3, "]]>");
                 }
             }
-            tmp = tmp->next;
+            break;
+
+        case XML_ATTRIBUTE_NODE:
+            xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur);
+	    break;
+
+        default:
+            break;
         }
-        if (tmp == NULL)
-            addmeta = 1;
+
+        while (1) {
+            if (cur == root)
+                return;
+            if (ctxt->format == 1)
+                xmlOutputBufferWrite(buf, 1, "\n");
+            if (cur->next != NULL) {
+                cur = cur->next;
+                break;
+            }
+
+            /*
+             * The parent should never be NULL here but we want to handle
+             * corrupted documents gracefully.
+             */
+            if (cur->parent == NULL)
+                return;
+            cur = cur->parent;
+
+            if (cur->type == XML_ELEMENT_NODE) {
+                if (ctxt->level > 0) ctxt->level--;
+                if ((xmlIndentTreeOutput) && (ctxt->format == 1))
+                    xmlOutputBufferWrite(buf, ctxt->indent_size *
+                                         (ctxt->level > ctxt->indent_nr ?
+                                          ctxt->indent_nr : ctxt->level),
+                                         ctxt->indent);
+
+                xmlOutputBufferWrite(buf, 2, "</");
+                if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                    xmlOutputBufferWriteString(buf,
+                            (const char *)cur->ns->prefix);
+                    xmlOutputBufferWrite(buf, 1, ":");
+                }
+
+                xmlOutputBufferWriteString(buf, (const char *)cur->name);
+                xmlOutputBufferWrite(buf, 1, ">");
+
+                if (cur == unformattedNode) {
+                    ctxt->format = format;
+                    unformattedNode = NULL;
+                }
+            }
+        }
     }
-
-    if ((cur->type == XML_ELEMENT_NODE) && (cur->children == NULL)) {
-	if (((cur->ns == NULL) || (cur->ns->prefix == NULL)) &&
-	    ((xhtmlIsEmpty(cur) == 1) && (addmeta == 0))) {
-	    /*
-	     * C.2. Empty Elements
-	     */
-	    xmlOutputBufferWrite(buf, 3, " />");
-	} else {
-		if (addmeta == 1) {
-			xmlOutputBufferWrite(buf, 1, ">");
-			if (ctxt->format == 1) {
-				xmlOutputBufferWrite(buf, 1, "\n");
-				if (xmlIndentTreeOutput)
-					xmlOutputBufferWrite(buf, ctxt->indent_size *
-					(ctxt->level + 1 > ctxt->indent_nr ?
-					ctxt->indent_nr : ctxt->level + 1), ctxt->indent);
-			}
-			xmlOutputBufferWriteString(buf,
-				"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=");
-			if (ctxt->encoding) {
-				xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding);
-			} else {
-				xmlOutputBufferWrite(buf, 5, "UTF-8");
-			}
-			xmlOutputBufferWrite(buf, 4, "\" />");
-			if (ctxt->format == 1)
-				xmlOutputBufferWrite(buf, 1, "\n");
-		} else {
-			xmlOutputBufferWrite(buf, 1, ">");
-		}
-	    /*
-	     * C.3. Element Minimization and Empty Element Content
-	     */
-	    xmlOutputBufferWrite(buf, 2, "</");
-	    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
-		xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
-		xmlOutputBufferWrite(buf, 1, ":");
-	    }
-	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-	    xmlOutputBufferWrite(buf, 1, ">");
-	}
-	return;
-    }
-    xmlOutputBufferWrite(buf, 1, ">");
-	if (addmeta == 1) {
-		if (ctxt->format == 1) {
-			xmlOutputBufferWrite(buf, 1, "\n");
-			if (xmlIndentTreeOutput)
-				xmlOutputBufferWrite(buf, ctxt->indent_size *
-				(ctxt->level + 1 > ctxt->indent_nr ?
-				ctxt->indent_nr : ctxt->level + 1), ctxt->indent);
-		}
-		xmlOutputBufferWriteString(buf,
-			"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=");
-		if (ctxt->encoding) {
-			xmlOutputBufferWriteString(buf, (const char *)ctxt->encoding);
-		} else {
-			xmlOutputBufferWrite(buf, 5, "UTF-8");
-		}
-		xmlOutputBufferWrite(buf, 4, "\" />");
-	}
-    if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
-	xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape);
-    }
-
-#if 0
-    /*
-    * This was removed due to problems with HTML processors.
-    * See bug #345147.
-    */
-    /*
-     * 4.8. Script and Style elements
-     */
-    if ((cur->type == XML_ELEMENT_NODE) &&
-	((xmlStrEqual(cur->name, BAD_CAST "script")) ||
-	 (xmlStrEqual(cur->name, BAD_CAST "style"))) &&
-	((cur->ns == NULL) ||
-	 (xmlStrEqual(cur->ns->href, XHTML_NS_NAME)))) {
-	xmlNodePtr child = cur->children;
-
-	while (child != NULL) {
-	    if (child->type == XML_TEXT_NODE) {
-		if ((xmlStrchr(child->content, '<') == NULL) &&
-		    (xmlStrchr(child->content, '&') == NULL) &&
-		    (xmlStrstr(child->content, BAD_CAST "]]>") == NULL)) {
-		    /* Nothing to escape, so just output as is... */
-		    /* FIXME: Should we do something about "--" also? */
-		    int level = ctxt->level;
-		    int indent = ctxt->format;
-
-		    ctxt->level = 0;
-		    ctxt->format = 0;
-		    xmlOutputBufferWriteString(buf, (const char *) child->content);
-		    /* (We cannot use xhtmlNodeDumpOutput() here because
-		     * we wish to leave '>' unescaped!) */
-		    ctxt->level = level;
-		    ctxt->format = indent;
-		} else {
-		    /* We must use a CDATA section.  Unfortunately,
-		     * this will break CSS and JavaScript when read by
-		     * a browser in HTML4-compliant mode. :-( */
-		    start = end = child->content;
-		    while (*end != '\0') {
-			if (*end == ']' &&
-			    *(end + 1) == ']' &&
-			    *(end + 2) == '>') {
-			    end = end + 2;
-			    xmlOutputBufferWrite(buf, 9, "<![CDATA[");
-			    xmlOutputBufferWrite(buf, end - start,
-						 (const char *)start);
-			    xmlOutputBufferWrite(buf, 3, "]]>");
-			    start = end;
-			}
-			end++;
-		    }
-		    if (start != end) {
-			xmlOutputBufferWrite(buf, 9, "<![CDATA[");
-			xmlOutputBufferWrite(buf, end - start,
-			                     (const char *)start);
-			xmlOutputBufferWrite(buf, 3, "]]>");
-		    }
-		}
-	    } else {
-		int level = ctxt->level;
-		int indent = ctxt->format;
-
-		ctxt->level = 0;
-		ctxt->format = 0;
-		xhtmlNodeDumpOutput(ctxt, child);
-		ctxt->level = level;
-		ctxt->format = indent;
-	    }
-	    child = child->next;
-	}
-    }
-#endif
-
-    if (cur->children != NULL) {
-	int indent = ctxt->format;
-
-	if (format == 1) xmlOutputBufferWrite(buf, 1, "\n");
-	if (ctxt->level >= 0) ctxt->level++;
-	ctxt->format = format;
-	xhtmlNodeListDumpOutput(ctxt, cur->children);
-	if (ctxt->level > 0) ctxt->level--;
-	ctxt->format = indent;
-	if ((xmlIndentTreeOutput) && (format == 1))
-	    xmlOutputBufferWrite(buf, ctxt->indent_size *
-	                         (ctxt->level > ctxt->indent_nr ?
-				  ctxt->indent_nr : ctxt->level),
-				 ctxt->indent);
-    }
-    xmlOutputBufferWrite(buf, 2, "</");
-    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
-        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
-	xmlOutputBufferWrite(buf, 1, ":");
-    }
-
-    xmlOutputBufferWriteString(buf, (const char *)cur->name);
-    xmlOutputBufferWrite(buf, 1, ">");
 }
 #endif
 
@@ -1932,12 +1884,25 @@
  * Returns the number of byte written or -1 in case of error
  */
 long
-xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node)
+xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur)
 {
     long ret = 0;
 
-    if ((ctxt == NULL) || (node == NULL)) return(-1);
-    xmlNodeDumpOutputInternal(ctxt, node);
+    if ((ctxt == NULL) || (cur == NULL)) return(-1);
+#ifdef LIBXML_HTML_ENABLED
+    if (ctxt->options & XML_SAVE_XHTML) {
+        xhtmlNodeDumpOutput(ctxt, cur);
+        return(ret);
+    }
+    if (((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL) &&
+         (cur->doc->type == XML_HTML_DOCUMENT_NODE) &&
+         ((ctxt->options & XML_SAVE_AS_XML) == 0)) ||
+        (ctxt->options & XML_SAVE_AS_HTML)) {
+	htmlNodeDumpOutputInternal(ctxt, cur);
+	return(ret);
+    }
+#endif
+    xmlNodeDumpOutputInternal(ctxt, cur);
     return(ret);
 }
 
diff --git a/src/xmlstring.c b/src/xmlstring.c
index 780c643..62d3053 100644
--- a/src/xmlstring.c
+++ b/src/xmlstring.c
@@ -130,16 +130,18 @@
 
 int
 xmlStrcmp(const xmlChar *str1, const xmlChar *str2) {
-    register int tmp;
-
     if (str1 == str2) return(0);
     if (str1 == NULL) return(-1);
     if (str2 == NULL) return(1);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+    return(strcmp((const char *)str1, (const char *)str2));
+#else
     do {
-        tmp = *str1++ - *str2;
+        int tmp = *str1++ - *str2;
         if (tmp != 0) return(tmp);
     } while (*str2++ != 0);
     return 0;
+#endif
 }
 
 /**
@@ -158,10 +160,14 @@
     if (str1 == str2) return(1);
     if (str1 == NULL) return(0);
     if (str2 == NULL) return(0);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+    return(strcmp((const char *)str1, (const char *)str2) == 0);
+#else
     do {
         if (*str1++ != *str2) return(0);
     } while (*str2++);
     return(1);
+#endif
 }
 
 /**
@@ -204,18 +210,15 @@
 
 int
 xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len) {
-    register int tmp;
-
     if (len <= 0) return(0);
     if (str1 == str2) return(0);
     if (str1 == NULL) return(-1);
     if (str2 == NULL) return(1);
-#ifdef __GNUC__
-    tmp = strncmp((const char *)str1, (const char *)str2, len);
-    return tmp;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+    return(strncmp((const char *)str1, (const char *)str2, len));
 #else
     do {
-        tmp = *str1++ - *str2;
+        int tmp = *str1++ - *str2;
         if (tmp != 0 || --len == 0) return(tmp);
     } while (*str2++ != 0);
     return 0;
diff --git a/src/xpath.c b/src/xpath.c
index 0d5aa68..90f10ca 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -136,6 +136,17 @@
 #define XPATH_MAX_NODESET_LENGTH 10000000
 
 /*
+ * XPATH_MAX_RECRUSION_DEPTH:
+ * Maximum amount of nested functions calls when parsing or evaluating
+ * expressions
+ */
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+#define XPATH_MAX_RECURSION_DEPTH 500
+#else
+#define XPATH_MAX_RECURSION_DEPTH 5000
+#endif
+
+/*
  * TODO:
  * There are a few spots where some tests are done which depend upon ascii
  * data.  These should be enhanced for full UTF8 support (see particularly
@@ -1746,7 +1757,6 @@
 static int xmlXPathDebugObjMaxXSLTTree = 0;
 static int xmlXPathDebugObjMaxAll = 0;
 
-/* REVISIT TODO: Make this static when committing */
 static void
 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
 {
@@ -2061,7 +2071,6 @@
     xmlXPathDebugObjCounterAll--;
 }
 
-/* REVISIT TODO: Make this static when committing */
 static void
 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
 {
@@ -6120,9 +6129,6 @@
     ret->contextSize = -1;
     ret->proximityPosition = -1;
 
-    ret->maxDepth = INT_MAX;
-    ret->maxParserDepth = INT_MAX;
-
 #ifdef XP_DEFAULT_CACHE_ON
     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
 	xmlXPathFreeContext(ret);
@@ -10950,9 +10956,13 @@
     xmlXPathContextPtr xpctxt = ctxt->context;
 
     if (xpctxt != NULL) {
-        if (xpctxt->depth >= xpctxt->maxParserDepth)
+        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
-        xpctxt->depth += 1;
+        /*
+         * Parsing a single '(' pushes about 10 functions on the call stack
+         * before recursing!
+         */
+        xpctxt->depth += 10;
     }
 
     xmlXPathCompAndExpr(ctxt);
@@ -11667,11 +11677,11 @@
         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
 
         if (ctxt->error != XPATH_EXPRESSION_OK)
-            goto exit;
+            break;
         if (res < 0) {
             /* Shouldn't happen */
             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
-            goto exit;
+            break;
         }
 
         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
@@ -11690,15 +11700,7 @@
 
         if (res != 0) {
             if (pos == maxPos) {
-                /* Clear remaining nodes and exit loop. */
-                if (hasNsNodes) {
-                    for (i++; i < set->nodeNr; i++) {
-                        node = set->nodeTab[i];
-                        if ((node != NULL) &&
-                            (node->type == XML_NAMESPACE_DECL))
-                            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
-                    }
-                }
+                i += 1;
                 break;
             }
 
@@ -11706,6 +11708,15 @@
         }
     }
 
+    /* Free remaining nodes. */
+    if (hasNsNodes) {
+        for (; i < set->nodeNr; i++) {
+            xmlNodePtr node = set->nodeTab[i];
+            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
+                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
+        }
+    }
+
     set->nodeNr = j;
 
     /* If too many elements were removed, shrink table to preserve memory. */
@@ -11726,7 +11737,6 @@
         }
     }
 
-exit:
     xpctxt->node = oldnode;
     xpctxt->doc = olddoc;
     xpctxt->contextSize = oldcs;
@@ -11791,11 +11801,11 @@
         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
 
         if (ctxt->error != XPATH_EXPRESSION_OK)
-            goto exit;
+            break;
         if (res < 0) {
             /* Shouldn't happen */
             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
-            goto exit;
+            break;
         }
 
         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
@@ -11813,10 +11823,7 @@
 
         if (res != 0) {
             if (pos == maxPos) {
-                /* Clear remaining nodes and exit loop. */
-                for (i++; i < locset->locNr; i++) {
-                    xmlXPathFreeObject(locset->locTab[i]);
-                }
+                i += 1;
                 break;
             }
 
@@ -11824,6 +11831,10 @@
         }
     }
 
+    /* Free remaining nodes. */
+    for (; i < locset->locNr; i++)
+        xmlXPathFreeObject(locset->locTab[i]);
+
     locset->locNr = j;
 
     /* If too many elements were removed, shrink table to preserve memory. */
@@ -11844,7 +11855,6 @@
         }
     }
 
-exit:
     xpctxt->node = oldnode;
     xpctxt->doc = olddoc;
     xpctxt->contextSize = oldcs;
@@ -11882,7 +11892,7 @@
                 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
             XP_ERROR(XPATH_INVALID_OPERAND);
 	}
-        if (ctxt->context->depth >= ctxt->context->maxDepth)
+        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
         ctxt->context->depth += 1;
 	xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
@@ -12598,7 +12608,7 @@
     CHECK_ERROR0;
     if (OP_LIMIT_EXCEEDED(ctxt, 1))
         return(0);
-    if (ctxt->context->depth >= ctxt->context->maxDepth)
+    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
     ctxt->context->depth += 1;
     comp = ctxt->comp;
@@ -12739,7 +12749,7 @@
     CHECK_ERROR0;
     if (OP_LIMIT_EXCEEDED(ctxt, 1))
         return(0);
-    if (ctxt->context->depth >= ctxt->context->maxDepth)
+    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
     ctxt->context->depth += 1;
     comp = ctxt->comp;
@@ -12957,7 +12967,7 @@
     CHECK_ERROR0;
     if (OP_LIMIT_EXCEEDED(ctxt, 1))
         return(0);
-    if (ctxt->context->depth >= ctxt->context->maxDepth)
+    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
     ctxt->context->depth += 1;
     comp = ctxt->comp;
@@ -13833,7 +13843,8 @@
 	do {
 	    cur = cur->parent;
 	    depth--;
-	    if ((cur == NULL) || (cur == limit))
+	    if ((cur == NULL) || (cur == limit) ||
+                (cur->type == XML_DOCUMENT_NODE))
 	        goto done;
 	    if (cur->type == XML_ELEMENT_NODE) {
 		ret = xmlStreamPop(patstream);
@@ -14104,8 +14115,7 @@
 	    }
 	}
 
-	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
-			&namespaces[0]);
+	stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
 	if (namespaces != NULL) {
 	    xmlFree((xmlChar **)namespaces);
 	}
@@ -14191,7 +14201,7 @@
     /* Recurse */
     ctxt = pctxt->context;
     if (ctxt != NULL) {
-        if (ctxt->depth >= ctxt->maxDepth)
+        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
             return;
         ctxt->depth += 1;
     }
@@ -14224,7 +14234,7 @@
         return(comp);
 #endif
 
-    xmlXPathInit();
+    xmlInitParser();
 
     pctxt = xmlXPathNewParserContext(str, ctxt);
     if (pctxt == NULL)
@@ -14313,7 +14323,7 @@
 
     if (comp == NULL)
 	return(-1);
-    xmlXPathInit();
+    xmlInitParser();
 
 #ifndef LIBXML_THREAD_ENABLED
     reentance++;
@@ -14458,7 +14468,7 @@
 
     CHECK_CTXT(ctx)
 
-    xmlXPathInit();
+    xmlInitParser();
 
     ctxt = xmlXPathNewParserContext(str, ctx);
     if (ctxt == NULL)
diff --git a/win32/config.h b/win32/config.h
index 324b74f..54392f4 100644
--- a/win32/config.h
+++ b/win32/config.h
@@ -5,7 +5,8 @@
 #define HAVE_STDARG_H
 #define HAVE_MALLOC_H
 #define HAVE_ERRNO_H
-#define HAVE_STDINT_H
+#define SEND_ARG2_CAST
+#define GETHOSTBYNAME_ARG_CAST
 
 #if defined(_WIN32_WCE)
 #undef HAVE_ERRNO_H
@@ -90,7 +91,7 @@
 
 #if defined(_MSC_VER)
 #define mkdir(p,m) _mkdir(p)
-#if _MSC_VER < 1900 // Cannot define this in VS 2015 and above!
+#if _MSC_VER < 1900
 #define snprintf _snprintf
 #endif
 #if _MSC_VER < 1500