Roll libxml from f19a9510 to c444c96e

This CL adds an additional patch on top of libxml which
removes calls to getentropy() and BCryptGetRandom() because they
aren't implemented or supported on certain platforms based on the trybot
results I saw. I will try upstreaming a configure script flag soon to replace
this patch file. This patch is safe because it reverts the random number
generation behavior before a recent libxml upstream patch.

2024-02-13 wellnhofer@aevum.de parser: Report OOM errors even after parser was stopped
2024-02-13 wellnhofer@aevum.de valid: Fix xmlAddIDSafe in "streaming" mode
2024-02-13 wellnhofer@aevum.de autotools: Remove useless substitution
2024-02-13 wellnhofer@aevum.de parser: Fix column number in attribute values
2024-02-12 wellnhofer@aevum.de xmllint: Return error code if XPath returns empty nodeset
2024-02-11 wellnhofer@aevum.de catalog: Remove Windows hack
2024-02-11 wellnhofer@aevum.de examples: Readd xpath1 test
2023-10-15 wellnhofer@aevum.de xmlreader: Clean up error handling
2024-02-06 wellnhofer@aevum.de xmlreader: Make xmlTextReaderValidateEntity return an error code
2024-02-06 wellnhofer@aevum.de valid: Fix another use-after-free in xmlAddIDSafe
2024-02-05 wellnhofer@aevum.de xpath: Report malloc failure in xmlXPathTranslateFunction
2023-10-14 wellnhofer@aevum.de [CVE-2024-25062] xmlreader: Don't expand XIncludes when backtracking
2024-02-04 wellnhofer@aevum.de c14n: Improve error handling
2024-02-04 wellnhofer@aevum.de valid: Fix use-after-free in xmlAddIDSafe
2024-02-01 wellnhofer@aevum.de fuzz: Reenable malloc failure check when serializing
2024-02-01 wellnhofer@aevum.de valid: Deprecate old DTD serialization API
2024-02-01 wellnhofer@aevum.de save: Move DTD serialization code to xmlsave.c
2024-02-01 wellnhofer@aevum.de fuzz: Don't check for malloc failures when serializing
2024-02-01 wellnhofer@aevum.de tree: Fix error condition in xmlNodeListGetString
2024-02-01 wellnhofer@aevum.de Update .gitignore
2024-02-01 wellnhofer@aevum.de io: Report malloc failure in xmlOutputBufferWrite
2024-01-30 wellnhofer@aevum.de doc: Mark `xmllint --xpath` as experimental
2024-01-30 wellnhofer@aevum.de doc: Update xmllint man page after fixing #180
2024-01-30 wellnhofer@aevum.de parser: Fix crash in xmlParseInNodeContext with HTML documents
2024-01-26 wellnhofer@aevum.de SAX2: Make sure that OOM errors aren't overwritten
2024-01-25 wellnhofer@aevum.de dict: Fix warnings with older clang
2024-01-23 wellnhofer@aevum.de parser: Make experimental input API private
2024-01-22 wellnhofer@aevum.de parser: Report fatal error if document entity couldn't be loaded
2024-01-17 wellnhofer@aevum.de xpath: Fix return of empty node-set in xmlXPathNodeCollectAndTest
2024-01-15 wellnhofer@aevum.de tests: Add test for issue #661
2024-01-11 wellnhofer@aevum.de tests: Remove testOOM
2024-01-10 wellnhofer@aevum.de autotools: Readd --with-xptr-locs configuration option
2024-01-10 wellnhofer@aevum.de xpath: Report malloc failure in xmlXPtrEvalXPtrPart
2024-01-10 wellnhofer@aevum.de gitlab-ci: Disable Python tests on MinGW for now
2024-01-07 wellnhofer@aevum.de SAX2: Limit entity URI length to 2000 bytes
2024-01-07 wellnhofer@aevum.de parser: Account for full size of non-well-formed entities
2024-01-02 wellnhofer@aevum.de parser: Pop inputs if parsing DTD failed
2024-01-10 wellnhofer@aevum.de parser: Handle NOCDATA properly when expanding entities
2024-01-07 wellnhofer@aevum.de fuzz: Cap URL size
2024-01-07 wellnhofer@aevum.de fuzz: Add missing include
2024-01-07 wellnhofer@aevum.de parser: Fix quadratic behavior when copying entities
2024-01-05 wellnhofer@aevum.de writer: Implement xmlTextWriterClose
2024-01-05 wellnhofer@aevum.de parser: Avoid duplicate namespace errors
2024-01-05 wellnhofer@aevum.de parser: Add XML_PARSE_NO_XXE parser option
2024-01-05 wellnhofer@aevum.de parser: Synchronize more options
2024-01-05 wellnhofer@aevum.de parser: Mark 'token' member as unused in xmlParserCtxt
2024-01-04 wellnhofer@aevum.de parser: Rework xmlCtxtParseDocument
2024-01-04 wellnhofer@aevum.de fuzz: Abort on invalid UTF-8
2023-12-22 jazzinghen@gmail.com Set LIBXML2_FOUND if it has been properly configured
2024-01-04 wellnhofer@aevum.de parser: Remove remnants of runtime debugging feature
2024-01-04 wellnhofer@aevum.de parser: Make xmlParseContent more useful
2024-01-04 wellnhofer@aevum.de tests: Move away from global error handlers
2024-01-04 wellnhofer@aevum.de error: Make xmlFormatError public
2024-01-03 wellnhofer@aevum.de parser: Remove xmlErrEncodingInt
2024-01-03 wellnhofer@aevum.de fuzz: Add assertion in xmlCopyCharMultibyte
2024-01-03 wellnhofer@aevum.de parser: Clear invalid entity content
2024-01-04 wellnhofer@aevum.de fuzz: Disable catalogs
2024-01-02 wellnhofer@aevum.de save: Report more malloc failures
2024-01-02 wellnhofer@aevum.de fuzz: Abort on internal errors
2024-01-02 wellnhofer@aevum.de valid: Fix some error codes
2024-01-02 wellnhofer@aevum.de encoding: Check whether encoding handlers support input/output
2024-01-02 wellnhofer@aevum.de parser: Fix buffer size checks
2024-01-02 wellnhofer@aevum.de parser: Convert some "internal errors" to meaningful codes
2024-01-02 wellnhofer@aevum.de SAX2: Enforce size limit in xmlSAX2Text with XML_PARSE_HUGE
2024-01-02 wellnhofer@aevum.de parser: Lower maximum entity nesting depth
2024-01-02 wellnhofer@aevum.de parser: Set depth limit to 2048 with XML_PARSE_HUGE
2023-09-07 wellnhofer@aevum.de parser: Implement xmlCtxtSetOptions
2023-09-07 wellnhofer@aevum.de parser: Always prefer option members over bitmask
2023-09-06 wellnhofer@aevum.de parser: Don't modify SAX2 handler if XML_PARSE_SAX1 is set
2023-12-30 wellnhofer@aevum.de parser: Rework parsing of attribute and entity values
2024-01-02 wellnhofer@aevum.de save: Output U+FFFD replacement characters
2023-12-29 wellnhofer@aevum.de parser: Simplify entity size accounting
2023-12-29 wellnhofer@aevum.de parser: Support namespace scope in NsData struct
2023-12-29 wellnhofer@aevum.de parser: Simplify error handling when parsing entities
2023-12-29 wellnhofer@aevum.de parser: Move cleanup of element stacks to xmlParseContent
2023-12-29 wellnhofer@aevum.de parser: Avoid unwanted expansion of parameter entities
2023-12-29 wellnhofer@aevum.de parser: Fix XML_ERR_UNSUPPORTED_ENCODING errors
2023-12-29 wellnhofer@aevum.de io: Always forward IO errors to global handler
2023-12-29 wellnhofer@aevum.de parser: Remove extraneous error message
2023-12-27 wellnhofer@aevum.de parser: New input API
2023-12-27 wellnhofer@aevum.de parser: Downgrade XML_ERR_UNSUPPORTED_ENCODING to warning
2023-12-27 wellnhofer@aevum.de parser: More refactoring of entity parsing
2023-12-27 wellnhofer@aevum.de parser: Fix encoding handling in xmlParserInputBufferCreateIO
2023-12-27 wellnhofer@aevum.de parser: Always copy content from entity to target.
2023-12-27 wellnhofer@aevum.de parser: Simplify control flow in xmlParseReference
2023-12-27 wellnhofer@aevum.de parser: Remove xmlSetEntityReferenceFunc feature
2023-12-27 wellnhofer@aevum.de parser: More refactoring of entity loading
2023-12-27 wellnhofer@aevum.de parser: Push general entity input streams on the stack
2023-12-26 wellnhofer@aevum.de parser: Mark more parser context members as unused
2023-12-26 wellnhofer@aevum.de parser: Move progressive flag into input struct
2023-12-26 wellnhofer@aevum.de parser: Remove remaining ctxt->instate checks
2023-12-26 wellnhofer@aevum.de parser: Fix in-parameter-entity and in-external-dtd checks
2023-12-28 wellnhofer@aevum.de html: Abort earlier on fatal errors
2023-12-28 wellnhofer@aevum.de SAX2: Fix error code
2023-12-28 wellnhofer@aevum.de uri: Keep fragment intact when resolving filesystem paths
2023-12-26 wellnhofer@aevum.de xpath: Rewrite substring-before and substring-after
2023-12-26 wellnhofer@aevum.de tests: Remove unneeded error formatting code
2023-12-28 wellnhofer@aevum.de xinclude: Only set xml:base if necessary
2023-12-26 wellnhofer@aevum.de xinclude: Allow empty nodesets
2023-12-26 wellnhofer@aevum.de parser: Fix general entity parsing
2023-12-25 wellnhofer@aevum.de parser: Rework general entity parsing
2023-12-24 wellnhofer@aevum.de io: Fix close error handling
2023-12-24 wellnhofer@aevum.de io: Fix read/write error handling
2023-12-23 wellnhofer@aevum.de io: More refactoring and unescaping fixes
2023-12-23 wellnhofer@aevum.de error: Reenable full error reports to default handler
2023-12-23 wellnhofer@aevum.de parser: Mark 'length' member of xmlParserInput as unused
2023-12-23 wellnhofer@aevum.de parser: Stop using 'directory' struct member
2023-12-25 wellnhofer@aevum.de parser: Make XML_IO_NETWORK_ATTEMPT behave as before
2023-12-23 wellnhofer@aevum.de io: Move some code from xmlIO.c to parserInternals.c
2023-12-23 wellnhofer@aevum.de Fix filename and URI handling
2023-12-22 wellnhofer@aevum.de uri: Clean up special parsing modes
2023-12-22 wellnhofer@aevum.de xinclude: Rework xml:base fixup
2023-12-22 wellnhofer@aevum.de xinclude: Report to xmlGenericError
2023-12-22 wellnhofer@aevum.de parser: Also set document properties when push parsing
2023-12-23 wellnhofer@aevum.de include: Move non-generated parts from xmlversion.h.in
2023-12-21 wellnhofer@aevum.de Update NEWS
2023-12-21 wellnhofer@aevum.de io: Remove support for HTTP POST
2023-12-24 wellnhofer@aevum.de dict: Move local RNG state to global state
2023-12-24 wellnhofer@aevum.de dict: Get random seed from system PRNG
2023-12-23 wellnhofer@aevum.de malloc-fail: Fix erroneous report in xmlStringGetNodeList
2023-12-21 wellnhofer@aevum.de doc: Improve documentation of error handlers
2023-12-21 wellnhofer@aevum.de runtest: Fix return code in rngTest
2023-12-21 wellnhofer@aevum.de tests: Try to fix RelaxNG test cases
2023-12-21 wellnhofer@aevum.de html: Don't close fd in htmlCtxtReadFd
2023-12-20 wellnhofer@aevum.de io: Don't use "-" to read from stdin
2023-12-20 wellnhofer@aevum.de io: Rework initialization
2023-12-20 wellnhofer@aevum.de io: Rearrange code
2023-12-20 wellnhofer@aevum.de parser: Rename xmlErrParser to xmlCtxtErr
2023-12-19 wellnhofer@aevum.de parser: Remove xmlErrEncoding
2023-12-19 wellnhofer@aevum.de io: Consolidate error messages
2023-12-19 wellnhofer@aevum.de io: Report IO errors through xmlCtxtErrIO
2023-12-19 wellnhofer@aevum.de xzlib: Fix harmless unsigned integer overflow
2023-12-19 wellnhofer@aevum.de io: Always use unbuffered input
2023-12-19 wellnhofer@aevum.de io: Fix detection of compressed streams
2023-12-19 wellnhofer@aevum.de io: Pass error codes from xmlFileOpenReal to xmlNewInputFromFile
2023-12-19 wellnhofer@aevum.de io: Rework default callbacks
2023-12-18 wellnhofer@aevum.de error: Stop printing some errors by default
2023-12-18 wellnhofer@aevum.de error: Remove xmlSimpleError
2023-12-18 wellnhofer@aevum.de xmllint: Don't use xmlGenericError
2023-12-18 wellnhofer@aevum.de runtest: Test with per-context error handlers
2023-12-18 wellnhofer@aevum.de regexp: Improve error handling
2023-12-18 wellnhofer@aevum.de misc: Improve error handling
2023-12-18 wellnhofer@aevum.de save: Improve error handling
2023-12-18 wellnhofer@aevum.de schematron: Improve error handling
2023-12-18 wellnhofer@aevum.de relaxng: Improve error handling
2023-12-18 wellnhofer@aevum.de debug: Improve error handling
2023-12-18 wellnhofer@aevum.de c14n: Improve error handling
2023-12-18 wellnhofer@aevum.de catalog: Improve error handling
2023-12-18 wellnhofer@aevum.de schemas: Improve error handling
2023-12-18 wellnhofer@aevum.de reader: Simplify error handling
2023-12-18 wellnhofer@aevum.de xinclude: Improve error handling
2023-12-18 wellnhofer@aevum.de xpath: Improve error handling
2023-12-18 wellnhofer@aevum.de parser: Improve error handling
2023-12-18 wellnhofer@aevum.de error: Refactor error reporting
2023-12-20 mike.dalessio@gmail.com Makefile.am: omit $(top_builddir) from DEPS and LDADDS
2023-12-20 wellnhofer@aevum.de xpath: Don't free nodes of XSLT result value trees
2023-12-20 wellnhofer@aevum.de malloc-fail: Report malloc failure in xmlXPathNumberFunction
2023-12-16 wellnhofer@aevum.de valid: Fix handling of enumerations
2023-12-15 wellnhofer@aevum.de malloc-fail: Report malloc failure in xmlXPathTranslateFunction
2023-12-15 wellnhofer@aevum.de malloc-fail: Fix OOM error handling in xmlSwitchInputEncoding
2023-12-14 wellnhofer@aevum.de save: Fix build --without-html
2023-12-14 wellnhofer@aevum.de parser: Fix build --without-output
2023-12-14 wellnhofer@aevum.de Fix compiler warnings with disabled modules
2023-12-13 wellnhofer@aevum.de parser: Allow recovery in xmlParseInNodeContext
2023-12-13 wellnhofer@aevum.de encoding: Support ASCII in xmlLookupCharEncodingHandler
2023-12-13 wellnhofer@aevum.de parser: Don't grow or shrink pull parser memory buffers
2023-12-13 wellnhofer@aevum.de python: Fix callback signature
2023-12-13 wellnhofer@aevum.de malloc-fail: Fix use-of-uninitialized-value in xmlParseConditionalSections
2023-12-13 wellnhofer@aevum.de malloc-fail: Fix memory leak in xmlNodeGetBaseSafe
2023-12-12 wellnhofer@aevum.de io: Fix memory lifetime issue with input buffers
2023-12-12 wellnhofer@aevum.de doc: Add notes about breaking ABI in MAINTAINERS.md
2023-12-12 wellnhofer@aevum.de malloc-fail: Don't truncate parser input buffer
2023-12-12 wellnhofer@aevum.de malloc-fail: Fix null deref in xmlXPathTranslateFunction
2023-12-12 wellnhofer@aevum.de malloc-fail: Fix erroneous reports in xmlNodeListGetString
2023-12-10 wellnhofer@aevum.de fuzz: Enable value profile
2023-12-10 wellnhofer@aevum.de html: Report malloc failures
2023-12-10 wellnhofer@aevum.de fuzz: Check malloc failure reports in XML fuzzers
2023-12-10 wellnhofer@aevum.de writer: Don't call SAX error handler directly
2023-12-10 wellnhofer@aevum.de valid: Report malloc failures
2023-12-10 wellnhofer@aevum.de xmlreader: Report malloc failures
2023-12-10 wellnhofer@aevum.de xinclude: Report malloc failures
2023-12-10 wellnhofer@aevum.de SAX2: Report malloc failures

Fixed: 325094430
Bug: 934413
Change-Id: I3c2a81b06a229e4597b2023d650ee32132321588
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5162147
Auto-Submit: Joey Arhar <jarhar@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: David Baron <dbaron@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1260630}
NOKEYCHECK=True
GitOrigin-RevId: 7d5a313f1aa52a85503699a4b4d37f20a05529d1
diff --git a/README.chromium b/README.chromium
index 9d79579..291f832 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,7 +1,7 @@
 Name: libxml
 URL: http://xmlsoft.org
-Version: f19a95108a32b40eaa3b16b41d7a687896e61ce5
-CPEPrefix: cpe:/a:xmlsoft:libxml2:2.12.3
+Version: c444c96e20253e5996f4209a123b96a6c273dac6
+CPEPrefix: cpe:/a:xmlsoft:libxml2:2.12.5
 License: MIT
 License File: src/Copyright
 Security Critical: yes
@@ -15,6 +15,8 @@
 
 - undo-sax-deprecation.patch: Un-deprecate xmlSAXParseMemory because it is used
   in chromium's copy of maldoca. See https://github.com/google/maldoca/issues/87
+- remove-getentropy.patch: Removes calls to getentropy() and BCrypt because they
+  aren't implemented or don't work on several platforms.
 - Add helper classes in the chromium/ subdirectory.
 - Delete various unused files, see chromium/roll.py
 - Disable various unused libxml features:
diff --git a/chromium/remove-getentropy.patch b/chromium/remove-getentropy.patch
new file mode 100644
index 0000000..7d19136
--- /dev/null
+++ b/chromium/remove-getentropy.patch
@@ -0,0 +1,63 @@
+This patch removes calls to getentropy() and BCryptGetRandom() because they
+aren't implemented or supported on certain platforms based on the trybot
+results I saw. I will try upstreaming a configure script flag soon to replace
+this patch file. This patch is safe because it reverts the random number
+generation behavior before a recent libxml upstream patch.
+
+diff --git a/dict.c b/dict.c
+index 5c9f3aa2..7a492895 100644
+--- a/dict.c
++++ b/dict.c
+@@ -24,14 +24,10 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <time.h>
+-#ifdef HAVE_SYS_RANDOM_H
+-#include <sys/random.h>
+-#endif
+ 
+ #ifdef _WIN32
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+-#include <bcrypt.h>
+ #endif
+ 
+ #include "private/dict.h"
+@@ -926,29 +922,6 @@ xmlInitRandom(void) {
+     xmlInitMutex(&xmlRngMutex);
+ 
+     {
+-#ifdef _WIN32
+-        NTSTATUS status;
+-
+-        status = BCryptGenRandom(NULL, (unsigned char *) globalRngState,
+-                                 sizeof(globalRngState),
+-                                 BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+-        if (!BCRYPT_SUCCESS(status)) {
+-            fprintf(stderr, "libxml2: BCryptGenRandom failed with "
+-                    "error code %lu\n", GetLastError());
+-            abort();
+-        }
+-#elif defined(HAVE_GETENTROPY)
+-        while (1) {
+-            if (getentropy(globalRngState, sizeof(globalRngState)) == 0)
+-                break;
+-
+-            if (errno != EINTR) {
+-                fprintf(stderr, "libxml2: getentropy failed with "
+-                        "error code %d\n", errno);
+-                abort();
+-            }
+-        }
+-#else
+         int var;
+ 
+         globalRngState[0] =
+@@ -957,7 +930,6 @@ xmlInitRandom(void) {
+         globalRngState[1] =
+                 HASH_ROL((unsigned) ((size_t) &xmlRngMutex & 0xFFFFFFFF), 16) ^
+                 HASH_ROL((unsigned) ((size_t) &var & 0xFFFFFFFF), 24);
+-#endif
+     }
+ }
+ 
diff --git a/chromium/roll.py b/chromium/roll.py
index a954af3..fbb7b5b 100755
--- a/chromium/roll.py
+++ b/chromium/roll.py
@@ -73,6 +73,7 @@
 
 PATCHES = [
     'undo-sax-deprecation.patch',
+    'remove-getentropy.patch',
 ]
 
 
diff --git a/linux/config.h b/linux/config.h
index 91df9bd..59b8e8c 100644
--- a/linux/config.h
+++ b/linux/config.h
@@ -25,6 +25,9 @@
 /* Define to 1 if you have the `ftime' function. */
 #define HAVE_FTIME 1
 
+/* Define to 1 if you have the `getentropy' function. */
+#define HAVE_GETENTROPY 1
+
 /* Define to 1 if you have the `gettimeofday' function. */
 #define HAVE_GETTIMEOFDAY 1
 
@@ -93,6 +96,9 @@
 /* Define to 1 if you have the <sys/mman.h> header file. */
 #define HAVE_SYS_MMAN_H 1
 
+/* Define to 1 if you have the <sys/random.h> header file. */
+#define HAVE_SYS_RANDOM_H 1
+
 /* Define to 1 if you have the <sys/select.h> header file. */
 #define HAVE_SYS_SELECT_H 1
 
diff --git a/linux/include/libxml/xmlversion.h b/linux/include/libxml/xmlversion.h
index 3f4f851..c6fbdae 100644
--- a/linux/include/libxml/xmlversion.h
+++ b/linux/include/libxml/xmlversion.h
@@ -10,20 +10,6 @@
 #ifndef __XML_VERSION_H__
 #define __XML_VERSION_H__
 
-#include <libxml/xmlexports.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * use those to be sure nothing nasty will happen if
- * your library and includes mismatch
- */
-#ifndef LIBXML2_COMPILING_MSCCDEF
-XMLPUBFUN void xmlCheckVersion(int version);
-#endif /* LIBXML2_COMPILING_MSCCDEF */
-
 /**
  * LIBXML_DOTTED_VERSION:
  *
@@ -286,15 +272,6 @@
 #endif
 
 /**
- * LIBXML_DEBUG_RUNTIME:
- *
- * Removed
- */
-#if 0
-#define LIBXML_DEBUG_RUNTIME
-#endif
-
-/**
  * LIBXML_UNICODE_ENABLED:
  *
  * Whether the Unicode related interfaces are compiled in
@@ -322,17 +299,6 @@
 #endif
 
 /**
- * LIBXML_EXPR_ENABLED:
- *
- * Whether the formal expressions interfaces are compiled in
- *
- * This code is unused and disabled unconditionally for now.
- */
-#if 0
-#define LIBXML_EXPR_ENABLED
-#endif
-
-/**
  * LIBXML_SCHEMAS_ENABLED:
  *
  * Whether the Schemas validation interfaces are compiled in
@@ -383,108 +349,8 @@
 #define LIBXML_LZMA_ENABLED
 #endif
 
-#ifdef __GNUC__
-/** DOC_DISABLE */
+#include <libxml/xmlexports.h>
 
-#ifndef ATTRIBUTE_UNUSED
-# if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7)))
-#  define ATTRIBUTE_UNUSED __attribute__((unused))
-# else
-#  define ATTRIBUTE_UNUSED
-# endif
-#endif
-
-#ifndef LIBXML_ATTR_ALLOC_SIZE
-# if (!defined(__clang__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))))
-#  define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
-# else
-#  define LIBXML_ATTR_ALLOC_SIZE(x)
-# endif
-#else
-# define LIBXML_ATTR_ALLOC_SIZE(x)
-#endif
-
-#ifndef LIBXML_ATTR_FORMAT
-# if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))
-#  define LIBXML_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args)))
-# else
-#  define LIBXML_ATTR_FORMAT(fmt,args)
-# endif
-#else
-# define LIBXML_ATTR_FORMAT(fmt,args)
-#endif
-
-#ifndef XML_DEPRECATED
-#  if defined (IN_LIBXML) || (__GNUC__ * 100 + __GNUC_MINOR__ < 301)
-#    define XML_DEPRECATED
-/* Available since at least GCC 3.1 */
-#  else
-#    define XML_DEPRECATED __attribute__((deprecated))
-#  endif
-#endif
-
-#if defined(__LCC__)
-  #define XML_IGNORE_FPTR_CAST_WARNINGS
-  #define XML_POP_WARNINGS \
-    _Pragma("diag_default 1215")
-#elif defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)
-  #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800)
-    #define XML_IGNORE_FPTR_CAST_WARNINGS \
-      _Pragma("GCC diagnostic push") \
-      _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
-      _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"")
-  #else
-    #define XML_IGNORE_FPTR_CAST_WARNINGS \
-      _Pragma("GCC diagnostic push") \
-      _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
-  #endif
-  #define XML_POP_WARNINGS \
-    _Pragma("GCC diagnostic pop")
-#else
-  #define XML_IGNORE_FPTR_CAST_WARNINGS
-  #define XML_POP_WARNINGS
-#endif
-
-#else /* ! __GNUC__ */
-#define ATTRIBUTE_UNUSED
-#define LIBXML_ATTR_ALLOC_SIZE(x)
-#define LIBXML_ATTR_FORMAT(fmt,args)
-#ifndef XML_DEPRECATED
-#  if defined (IN_LIBXML) || !defined (_MSC_VER)
-#    define XML_DEPRECATED
-/* Available since Visual Studio 2005 */
-#  elif defined (_MSC_VER) && (_MSC_VER >= 1400)
-#    define XML_DEPRECATED __declspec(deprecated)
-#  endif
-#endif
-#if defined (_MSC_VER) && (_MSC_VER >= 1400)
-#  define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push))
-#else
-#  define XML_IGNORE_FPTR_CAST_WARNINGS
-#endif
-#ifndef XML_POP_WARNINGS
-#  if defined (_MSC_VER) && (_MSC_VER >= 1400)
-#    define XML_POP_WARNINGS __pragma(warning(pop))
-#  else
-#    define XML_POP_WARNINGS
-#  endif
-#endif
-#endif /* __GNUC__ */
-
-#define XML_NO_ATTR
-
-#ifdef LIBXML_THREAD_ENABLED
-  #define XML_DECLARE_GLOBAL(name, type, attrs) \
-    attrs XMLPUBFUN type *__##name(void);
-  #define XML_GLOBAL_MACRO(name) (*__##name())
-#else
-  #define XML_DECLARE_GLOBAL(name, type, attrs) \
-    attrs XMLPUBVAR type name;
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
 #endif
 
 
diff --git a/linux/xml2-config b/linux/xml2-config
index bc629d5..bf1b08a 100755
--- a/linux/xml2-config
+++ b/linux/xml2-config
@@ -86,7 +86,7 @@
             shift
             libs="-lxml2 "
         else
-            libs="-lxml2  -licui18n -licuuc -licudata    -lm   "
+            libs="-lxml2  -licui18n -licuuc -licudata    -lm    "
         fi
 
         if [ "-L${libdir}" != "-L/usr/lib" -a "-L${libdir}" != "-L/usr/lib64" ]; then
diff --git a/mac/config.h b/mac/config.h
index 91df9bd..59b8e8c 100644
--- a/mac/config.h
+++ b/mac/config.h
@@ -25,6 +25,9 @@
 /* Define to 1 if you have the `ftime' function. */
 #define HAVE_FTIME 1
 
+/* Define to 1 if you have the `getentropy' function. */
+#define HAVE_GETENTROPY 1
+
 /* Define to 1 if you have the `gettimeofday' function. */
 #define HAVE_GETTIMEOFDAY 1
 
@@ -93,6 +96,9 @@
 /* Define to 1 if you have the <sys/mman.h> header file. */
 #define HAVE_SYS_MMAN_H 1
 
+/* Define to 1 if you have the <sys/random.h> header file. */
+#define HAVE_SYS_RANDOM_H 1
+
 /* Define to 1 if you have the <sys/select.h> header file. */
 #define HAVE_SYS_SELECT_H 1
 
diff --git a/mac/include/libxml/xmlversion.h b/mac/include/libxml/xmlversion.h
index 3f4f851..c6fbdae 100644
--- a/mac/include/libxml/xmlversion.h
+++ b/mac/include/libxml/xmlversion.h
@@ -10,20 +10,6 @@
 #ifndef __XML_VERSION_H__
 #define __XML_VERSION_H__
 
-#include <libxml/xmlexports.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * use those to be sure nothing nasty will happen if
- * your library and includes mismatch
- */
-#ifndef LIBXML2_COMPILING_MSCCDEF
-XMLPUBFUN void xmlCheckVersion(int version);
-#endif /* LIBXML2_COMPILING_MSCCDEF */
-
 /**
  * LIBXML_DOTTED_VERSION:
  *
@@ -286,15 +272,6 @@
 #endif
 
 /**
- * LIBXML_DEBUG_RUNTIME:
- *
- * Removed
- */
-#if 0
-#define LIBXML_DEBUG_RUNTIME
-#endif
-
-/**
  * LIBXML_UNICODE_ENABLED:
  *
  * Whether the Unicode related interfaces are compiled in
@@ -322,17 +299,6 @@
 #endif
 
 /**
- * LIBXML_EXPR_ENABLED:
- *
- * Whether the formal expressions interfaces are compiled in
- *
- * This code is unused and disabled unconditionally for now.
- */
-#if 0
-#define LIBXML_EXPR_ENABLED
-#endif
-
-/**
  * LIBXML_SCHEMAS_ENABLED:
  *
  * Whether the Schemas validation interfaces are compiled in
@@ -383,108 +349,8 @@
 #define LIBXML_LZMA_ENABLED
 #endif
 
-#ifdef __GNUC__
-/** DOC_DISABLE */
+#include <libxml/xmlexports.h>
 
-#ifndef ATTRIBUTE_UNUSED
-# if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7)))
-#  define ATTRIBUTE_UNUSED __attribute__((unused))
-# else
-#  define ATTRIBUTE_UNUSED
-# endif
-#endif
-
-#ifndef LIBXML_ATTR_ALLOC_SIZE
-# if (!defined(__clang__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))))
-#  define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
-# else
-#  define LIBXML_ATTR_ALLOC_SIZE(x)
-# endif
-#else
-# define LIBXML_ATTR_ALLOC_SIZE(x)
-#endif
-
-#ifndef LIBXML_ATTR_FORMAT
-# if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))
-#  define LIBXML_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args)))
-# else
-#  define LIBXML_ATTR_FORMAT(fmt,args)
-# endif
-#else
-# define LIBXML_ATTR_FORMAT(fmt,args)
-#endif
-
-#ifndef XML_DEPRECATED
-#  if defined (IN_LIBXML) || (__GNUC__ * 100 + __GNUC_MINOR__ < 301)
-#    define XML_DEPRECATED
-/* Available since at least GCC 3.1 */
-#  else
-#    define XML_DEPRECATED __attribute__((deprecated))
-#  endif
-#endif
-
-#if defined(__LCC__)
-  #define XML_IGNORE_FPTR_CAST_WARNINGS
-  #define XML_POP_WARNINGS \
-    _Pragma("diag_default 1215")
-#elif defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)
-  #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800)
-    #define XML_IGNORE_FPTR_CAST_WARNINGS \
-      _Pragma("GCC diagnostic push") \
-      _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
-      _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"")
-  #else
-    #define XML_IGNORE_FPTR_CAST_WARNINGS \
-      _Pragma("GCC diagnostic push") \
-      _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
-  #endif
-  #define XML_POP_WARNINGS \
-    _Pragma("GCC diagnostic pop")
-#else
-  #define XML_IGNORE_FPTR_CAST_WARNINGS
-  #define XML_POP_WARNINGS
-#endif
-
-#else /* ! __GNUC__ */
-#define ATTRIBUTE_UNUSED
-#define LIBXML_ATTR_ALLOC_SIZE(x)
-#define LIBXML_ATTR_FORMAT(fmt,args)
-#ifndef XML_DEPRECATED
-#  if defined (IN_LIBXML) || !defined (_MSC_VER)
-#    define XML_DEPRECATED
-/* Available since Visual Studio 2005 */
-#  elif defined (_MSC_VER) && (_MSC_VER >= 1400)
-#    define XML_DEPRECATED __declspec(deprecated)
-#  endif
-#endif
-#if defined (_MSC_VER) && (_MSC_VER >= 1400)
-#  define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push))
-#else
-#  define XML_IGNORE_FPTR_CAST_WARNINGS
-#endif
-#ifndef XML_POP_WARNINGS
-#  if defined (_MSC_VER) && (_MSC_VER >= 1400)
-#    define XML_POP_WARNINGS __pragma(warning(pop))
-#  else
-#    define XML_POP_WARNINGS
-#  endif
-#endif
-#endif /* __GNUC__ */
-
-#define XML_NO_ATTR
-
-#ifdef LIBXML_THREAD_ENABLED
-  #define XML_DECLARE_GLOBAL(name, type, attrs) \
-    attrs XMLPUBFUN type *__##name(void);
-  #define XML_GLOBAL_MACRO(name) (*__##name())
-#else
-  #define XML_DECLARE_GLOBAL(name, type, attrs) \
-    attrs XMLPUBVAR type name;
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
 #endif
 
 
diff --git a/src/HTMLparser.c b/src/HTMLparser.c
index f84b476..30b0fc8 100644
--- a/src/HTMLparser.c
+++ b/src/HTMLparser.c
@@ -58,25 +58,9 @@
  * Handle a redefinition of attribute error
  */
 static void
-htmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra)
+htmlErrMemory(xmlParserCtxtPtr ctxt)
 {
-    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
-        (ctxt->instate == XML_PARSER_EOF))
-	return;
-    if (ctxt != NULL) {
-        ctxt->errNo = XML_ERR_NO_MEMORY;
-        ctxt->instate = XML_PARSER_EOF;
-        ctxt->disableSAX = 1;
-    }
-    if (extra)
-        __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER,
-                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
-                        NULL, NULL, 0, 0,
-                        "Memory allocation failed : %s\n", extra);
-    else
-        __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER,
-                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
-                        NULL, NULL, 0, 0, "Memory allocation failed\n");
+    xmlCtxtErrMemory(ctxt);
 }
 
 /**
@@ -93,18 +77,8 @@
 htmlParseErr(xmlParserCtxtPtr ctxt, xmlParserErrors error,
              const char *msg, const xmlChar *str1, const xmlChar *str2)
 {
-    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
-        (ctxt->instate == XML_PARSER_EOF))
-	return;
-    if (ctxt != NULL)
-	ctxt->errNo = error;
-    __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error,
-                    XML_ERR_ERROR, NULL, 0,
-		    (const char *) str1, (const char *) str2,
-		    NULL, 0, 0,
-		    msg, str1, str2);
-    if (ctxt != NULL)
-	ctxt->wellFormed = 0;
+    xmlCtxtErr(ctxt, NULL, XML_FROM_HTML, error, XML_ERR_ERROR,
+               str1, str2, NULL, 0, msg, str1, str2);
 }
 
 /**
@@ -120,16 +94,8 @@
 htmlParseErrInt(xmlParserCtxtPtr ctxt, xmlParserErrors error,
              const char *msg, int val)
 {
-    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
-        (ctxt->instate == XML_PARSER_EOF))
-	return;
-    if (ctxt != NULL)
-	ctxt->errNo = error;
-    __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error,
-                    XML_ERR_ERROR, NULL, 0, NULL, NULL,
-		    NULL, val, 0, msg, val);
-    if (ctxt != NULL)
-	ctxt->wellFormed = 0;
+    xmlCtxtErr(ctxt, NULL, XML_FROM_HTML, error, XML_ERR_ERROR,
+               NULL, NULL, NULL, val, msg, val);
 }
 
 /************************************************************************
@@ -161,7 +127,7 @@
         tmp = xmlRealloc((xmlChar **) ctxt->nameTab,
                          newSize * sizeof(ctxt->nameTab[0]));
         if (tmp == NULL) {
-            htmlErrMemory(ctxt, NULL);
+            htmlErrMemory(ctxt);
             return (-1);
         }
         ctxt->nameTab = tmp;
@@ -219,7 +185,7 @@
                                     ctxt->nodeInfoMax *
                                     sizeof(ctxt->nodeInfoTab[0]));
         if (ctxt->nodeInfoTab == NULL) {
-            htmlErrMemory(ctxt, NULL);
+            htmlErrMemory(ctxt);
             return (0);
         }
     }
@@ -289,13 +255,16 @@
 #define CUR_PTR ctxt->input->cur
 #define BASE_PTR ctxt->input->base
 
-#define SHRINK if ((ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \
-		   (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \
-	xmlParserShrink(ctxt)
+#define SHRINK \
+    if ((!PARSER_PROGRESSIVE(ctxt)) && \
+        (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \
+	(ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \
+	xmlParserShrink(ctxt);
 
-#define GROW if ((ctxt->progressive == 0) &&				\
-		 (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK))	\
-	xmlParserGrow(ctxt)
+#define GROW \
+    if ((!PARSER_PROGRESSIVE(ctxt)) && \
+        (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \
+	xmlParserGrow(ctxt);
 
 #define SKIP_BLANKS htmlSkipBlankChars(ctxt)
 
@@ -304,14 +273,14 @@
 #define CUR (*ctxt->input->cur)
 #define NEXT xmlNextChar(ctxt)
 
-#define RAW (ctxt->token ? -1 : (*ctxt->input->cur))
+#define RAW (*ctxt->input->cur)
 
 
 #define NEXTL(l) do {							\
     if (*(ctxt->input->cur) == '\n') {					\
 	ctxt->input->line++; ctxt->input->col = 1;			\
     } else ctxt->input->col++;						\
-    ctxt->token = 0; ctxt->input->cur += l;				\
+    ctxt->input->cur += l;						\
   } while (0)
 
 /************
@@ -343,6 +312,7 @@
 static xmlChar *
 htmlFindEncoding(xmlParserCtxtPtr ctxt) {
     const xmlChar *start, *cur, *end;
+    xmlChar *ret;
 
     if ((ctxt == NULL) || (ctxt->input == NULL) ||
         (ctxt->input->flags & XML_INPUT_HAS_ENCODING))
@@ -374,7 +344,10 @@
            cur++;
     if (cur == start)
         return(NULL);
-    return(xmlStrndup(start, cur - start));
+    ret = xmlStrndup(start, cur - start);
+    if (ret == NULL)
+        htmlErrMemory(ctxt);
+    return(ret);
 }
 
 /**
@@ -397,23 +370,11 @@
     unsigned char c;
     unsigned int val;
 
-    if (ctxt->instate == XML_PARSER_EOF)
-	return(0);
-
-    if (ctxt->token != 0) {
-	*len = 0;
-	return(ctxt->token);
-    }
-
-    if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) {
+    if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)
         xmlParserGrow(ctxt);
-        if (ctxt->instate == XML_PARSER_EOF)
-            return(0);
-    }
 
     if ((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) {
         xmlChar * guess;
-        xmlCharEncodingHandlerPtr handler;
 
         /*
          * Assume it's a fixed length encoding (1) with
@@ -421,13 +382,18 @@
          * HTML constructs only use < 128 chars
          */
         if (*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(' ');
+            if (*ctxt->input->cur == 0) {
+                if (ctxt->input->cur < ctxt->input->end) {
+                    htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+                                    "Char 0x%X out of allowed range\n", 0);
+                    *len = 1;
+                    return(' ');
+                } else {
+                    *len = 0;
+                    return(0);
+                }
             }
+            *len = 1;
             return(*ctxt->input->cur);
         }
 
@@ -438,18 +404,7 @@
         if (guess == NULL) {
             xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
         } else {
-            handler = xmlFindCharEncodingHandler((const char *) guess);
-            if (handler != NULL) {
-                /*
-                 * Don't use UTF-8 encoder which isn't required and
-                 * can produce invalid UTF-8.
-                 */
-                if (!xmlStrEqual(BAD_CAST handler->name, BAD_CAST "UTF-8"))
-                    xmlSwitchToEncoding(ctxt, handler);
-            } else {
-                htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
-                             "Unsupported encoding %s", guess, NULL);
-            }
+            xmlSwitchEncodingName(ctxt, (const char *) guess);
             xmlFree(guess);
         }
         ctxt->input->flags |= XML_INPUT_HAS_ENCODING;
@@ -516,12 +471,16 @@
         }
         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(' ');
+        if (*ctxt->input->cur == 0) {
+            if (ctxt->input->cur < ctxt->input->end) {
+                htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
+                                "Char 0x%X out of allowed range\n", 0);
+                *len = 1;
+                return(' ');
+            } else {
+                *len = 0;
+                return(0);
+            }
         }
         /* 1-byte code */
         *len = 1;
@@ -529,20 +488,7 @@
     }
 
 encoding_error:
-    {
-        char buffer[150];
-
-	if (ctxt->input->end - ctxt->input->cur >= 4) {
-	    snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
-			    ctxt->input->cur[0], ctxt->input->cur[1],
-			    ctxt->input->cur[2], ctxt->input->cur[3]);
-	} else {
-	    snprintf(buffer, 149, "Bytes: 0x%02X\n", ctxt->input->cur[0]);
-	}
-	htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
-		     "Input is not proper UTF-8, indicate encoding !\n",
-		     BAD_CAST buffer, NULL);
-    }
+    xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL);
 
     if ((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0)
         xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
@@ -2035,7 +1981,7 @@
     buffer##_size *= 2;							\
     tmp = (xmlChar *) xmlRealloc(buffer, buffer##_size); 		\
     if (tmp == NULL) {							\
-	htmlErrMemory(ctxt, "growing buffer\n");			\
+	htmlErrMemory(ctxt);			\
 	xmlFree(buffer);						\
 	return(NULL);							\
     }									\
@@ -2294,47 +2240,6 @@
 
 /************************************************************************
  *									*
- *		Commodity functions to handle streams			*
- *									*
- ************************************************************************/
-
-#ifdef LIBXML_PUSH_ENABLED
-/**
- * htmlNewInputStream:
- * @ctxt:  an HTML parser context
- *
- * Create a new input stream structure
- * Returns the new input stream or NULL
- */
-static htmlParserInputPtr
-htmlNewInputStream(htmlParserCtxtPtr ctxt) {
-    htmlParserInputPtr input;
-
-    input = (xmlParserInputPtr) xmlMalloc(sizeof(htmlParserInput));
-    if (input == NULL) {
-        htmlErrMemory(ctxt, "couldn't allocate a new input stream\n");
-	return(NULL);
-    }
-    memset(input, 0, sizeof(htmlParserInput));
-    input->filename = NULL;
-    input->directory = NULL;
-    input->base = NULL;
-    input->cur = NULL;
-    input->buf = NULL;
-    input->line = 1;
-    input->col = 1;
-    input->buf = NULL;
-    input->free = NULL;
-    input->version = NULL;
-    input->consumed = 0;
-    input->length = 0;
-    return(input);
-}
-#endif
-
-
-/************************************************************************
- *									*
  *		Commodity functions, cleanup needed ?			*
  *									*
  ************************************************************************/
@@ -2438,10 +2343,8 @@
      * Allocate a new document and fill the fields.
      */
     cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
-    if (cur == NULL) {
-	htmlErrMemory(NULL, "HTML document creation failed\n");
+    if (cur == NULL)
 	return(NULL);
-    }
     memset(cur, 0, sizeof(xmlDoc));
 
     cur->type = XML_HTML_DOCUMENT_NODE;
@@ -2461,8 +2364,15 @@
     cur->charset = XML_CHAR_ENCODING_UTF8;
     cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT;
     if ((ExternalID != NULL) ||
-	(URI != NULL))
-	xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI);
+	(URI != NULL)) {
+        xmlDtdPtr intSubset;
+
+	intSubset = xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI);
+        if (intSubset == NULL) {
+            xmlFree(cur);
+            return(NULL);
+        }
+    }
     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
 	xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
     return(cur);
@@ -2510,12 +2420,14 @@
     htmlParseErr(ctxt, XML_HTML_INCORRECTLY_OPENED_COMMENT,
                  "Incorrectly opened comment\n", NULL, NULL);
 
-    do {
+    while (PARSER_STOPPED(ctxt) == 0) {
         c = CUR;
         if (c == 0)
             break;
         NEXT;
-    } while (c != '>');
+        if (c == '>')
+            break;
+    }
 }
 
 /**
@@ -2550,7 +2462,7 @@
 
     ret = xmlDictLookup(ctxt->dict, loc, i);
     if (ret == NULL)
-        htmlErrMemory(ctxt, NULL);
+        htmlErrMemory(ctxt);
 
     return(ret);
 }
@@ -2571,6 +2483,7 @@
 htmlParseHTMLName_nonInvasive(htmlParserCtxtPtr ctxt) {
     int i = 0;
     xmlChar loc[HTML_PARSER_BUFFER_SIZE];
+    const xmlChar *ret;
 
     if (!IS_ASCII_LETTER(NXT(1)) && (NXT(1) != '_') &&
         (NXT(1) != ':')) return(NULL);
@@ -2583,7 +2496,11 @@
 	i++;
     }
 
-    return(xmlDictLookup(ctxt->dict, loc, i));
+    ret = xmlDictLookup(ctxt->dict, loc, i);
+    if (ret == NULL)
+        htmlErrMemory(ctxt);
+
+    return(ret);
 }
 
 
@@ -2625,6 +2542,8 @@
 	if ((*in > 0) && (*in < 0x80)) {
 	    count = in - ctxt->input->cur;
 	    ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count);
+            if (ret == NULL)
+                htmlErrMemory(ctxt);
 	    ctxt->input->cur = in;
 	    ctxt->input->col += count;
 	    return(ret);
@@ -2641,6 +2560,7 @@
                     XML_MAX_TEXT_LENGTH :
                     XML_MAX_NAME_LENGTH;
     const xmlChar *base = ctxt->input->base;
+    const xmlChar *ret;
 
     /*
      * Handler for more complex cases
@@ -2673,8 +2593,6 @@
 	    return(htmlParseNameComplex(ctxt));
 	}
     }
-    if (ctxt->instate == XML_PARSER_EOF)
-        return(NULL);
 
     if (ctxt->input->cur - ctxt->input->base < len) {
         /* Sanity check */
@@ -2683,7 +2601,11 @@
         return (NULL);
     }
 
-    return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len));
+    ret = xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len);
+    if (ret == NULL)
+        htmlErrMemory(ctxt);
+
+    return(ret);
 }
 
 
@@ -2716,7 +2638,7 @@
     buffer_size = HTML_PARSER_BUFFER_SIZE;
     buffer = (xmlChar *) xmlMallocAtomic(buffer_size);
     if (buffer == NULL) {
-	htmlErrMemory(ctxt, "buffer allocation failed\n");
+	htmlErrMemory(ctxt);
 	return(NULL);
     }
     out = buffer;
@@ -2724,7 +2646,8 @@
     /*
      * Ok loop until we reach one of the ending chars
      */
-    while ((CUR != 0) && (CUR != stop)) {
+    while ((PARSER_STOPPED(ctxt) == 0) &&
+           (CUR != 0) && (CUR != stop)) {
 	if ((stop == 0) && (CUR == '>')) break;
 	if ((stop == 0) && (IS_BLANK_CH(CUR))) break;
         if (CUR == '&') {
@@ -2810,10 +2733,6 @@
 		out = &buffer[indx];
 	    }
 	    c = CUR_CHAR(l);
-            if (ctxt->instate == XML_PARSER_EOF) {
-                xmlFree(buffer);
-                return(NULL);
-            }
 	    if      (c <    0x80)
 		    { *out++  = c;                bits= -6; }
 	    else if (c <   0x800)
@@ -2966,7 +2885,8 @@
         return(ret);
     startPosition = CUR_PTR - BASE_PTR;
 
-    while ((CUR != 0) && (CUR != quote)) {
+    while ((PARSER_STOPPED(ctxt) == 0) &&
+           (CUR != 0) && (CUR != quote)) {
         /* TODO: Handle UTF-8 */
         if (!IS_CHAR_CH(CUR)) {
             htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
@@ -2980,8 +2900,13 @@
         htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
                      "Unfinished SystemLiteral\n", NULL, NULL);
     } else {
-        if (err == 0)
+        if (err == 0) {
             ret = xmlStrndup((BASE_PTR+startPosition), len);
+            if (ret == NULL) {
+                htmlErrMemory(ctxt);
+                return(NULL);
+            }
+        }
         NEXT;
     }
 
@@ -3021,7 +2946,8 @@
         return(ret);
     startPosition = CUR_PTR - BASE_PTR;
 
-    while ((CUR != 0) && (CUR != quote)) {
+    while ((PARSER_STOPPED(ctxt) == 0) &&
+           (CUR != 0) && (CUR != quote)) {
         if (!IS_PUBIDCHAR_CH(CUR)) {
             htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
                             "Invalid char in PubidLiteral 0x%X\n", CUR);
@@ -3035,8 +2961,13 @@
         htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
                      "Unfinished PubidLiteral\n", NULL, NULL);
     } else {
-        if (err == 0)
+        if (err == 0) {
             ret = xmlStrndup((BASE_PTR + startPosition), len);
+            if (ret == NULL) {
+                htmlErrMemory(ctxt);
+                return(NULL);
+            }
+        }
         NEXT;
     }
 
@@ -3125,9 +3056,6 @@
 	cur = CUR_CHAR(l);
     }
 
-    if (ctxt->instate == XML_PARSER_EOF)
-        return;
-
     if ((nbchar != 0) && (ctxt->sax != NULL) && (!ctxt->disableSAX)) {
         buf[nbchar] = 0;
 	if (ctxt->sax->cdataBlock!= NULL) {
@@ -3163,9 +3091,10 @@
         buf[nbchar++] = readahead;
 
     cur = CUR_CHAR(l);
-    while (((cur != '<') || (ctxt->token == '<')) &&
-           ((cur != '&') || (ctxt->token == '&')) &&
-	   (cur != 0)) {
+    while ((cur != '<') &&
+           (cur != '&') &&
+	   (cur != 0) &&
+           (!PARSER_STOPPED(ctxt))) {
 	if (!(IS_CHAR(cur))) {
 	    htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
 	                "Invalid char in CDATA 0x%X\n", cur);
@@ -3200,8 +3129,6 @@
 	}
 	cur = CUR_CHAR(l);
     }
-    if (ctxt->instate == XML_PARSER_EOF)
-        return;
     if (nbchar != 0) {
         buf[nbchar] = 0;
 
@@ -3301,12 +3228,11 @@
 }
 
 /**
- * xmlParsePI:
- * @ctxt:  an XML parser context
+ * htmlParsePI:
+ * @ctxt:  an HTML parser context
  *
- * parse an XML Processing Instruction.
- *
- * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
+ * Parse an XML Processing Instruction. HTML5 doesn't allow processing
+ * instructions, so this will be removed at some point.
  */
 static void
 htmlParsePI(htmlParserCtxtPtr ctxt) {
@@ -3344,13 +3270,11 @@
 		    (ctxt->sax->processingInstruction != NULL))
 		    ctxt->sax->processingInstruction(ctxt->userData,
 		                                     target, NULL);
-		ctxt->instate = state;
-		return;
+                goto done;
 	    }
 	    buf = (xmlChar *) xmlMallocAtomic(size);
 	    if (buf == NULL) {
-		htmlErrMemory(ctxt, NULL);
-		ctxt->instate = state;
+		htmlErrMemory(ctxt);
 		return;
 	    }
 	    cur = CUR;
@@ -3367,9 +3291,8 @@
 		    size *= 2;
 		    tmp = (xmlChar *) xmlRealloc(buf, size);
 		    if (tmp == NULL) {
-			htmlErrMemory(ctxt, NULL);
+			htmlErrMemory(ctxt);
 			xmlFree(buf);
-			ctxt->instate = state;
 			return;
 		    }
 		    buf = tmp;
@@ -3385,17 +3308,12 @@
                     htmlParseErr(ctxt, XML_ERR_PI_NOT_FINISHED,
                                  "PI %s too long", target, NULL);
                     xmlFree(buf);
-                    ctxt->instate = state;
-                    return;
+                    goto done;
                 }
 		NEXTL(l);
 		cur = CUR_CHAR(l);
 	    }
 	    buf[len] = 0;
-            if (ctxt->instate == XML_PARSER_EOF) {
-                xmlFree(buf);
-                return;
-            }
 	    if (cur != '>') {
 		htmlParseErr(ctxt, XML_ERR_PI_NOT_FINISHED,
 		      "ParsePI: PI %s never end ...\n", target, NULL);
@@ -3415,6 +3333,8 @@
 	    htmlParseErr(ctxt, XML_ERR_PI_NOT_STARTED,
                          "PI is not started correctly", NULL, NULL);
 	}
+
+done:
 	ctxt->instate = state;
     }
 }
@@ -3423,9 +3343,7 @@
  * htmlParseComment:
  * @ctxt:  an HTML parser context
  *
- * Parse an XML (SGML) comment <!-- .... -->
- *
- * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
+ * Parse an HTML comment
  */
 static void
 htmlParseComment(htmlParserCtxtPtr ctxt) {
@@ -3452,8 +3370,7 @@
     SKIP(4);
     buf = (xmlChar *) xmlMallocAtomic(size);
     if (buf == NULL) {
-        htmlErrMemory(ctxt, "buffer allocation failed\n");
-	ctxt->instate = state;
+        htmlErrMemory(ctxt);
 	return;
     }
     len = 0;
@@ -3497,8 +3414,7 @@
 	    tmp = (xmlChar *) xmlRealloc(buf, size);
 	    if (tmp == NULL) {
 	        xmlFree(buf);
-	        htmlErrMemory(ctxt, "growing buffer failed\n");
-		ctxt->instate = state;
+	        htmlErrMemory(ctxt);
 		return;
 	    }
 	    buf = tmp;
@@ -3526,10 +3442,6 @@
     }
 finished:
     buf[len] = 0;
-    if (ctxt->instate == XML_PARSER_EOF) {
-        xmlFree(buf);
-        return;
-    }
     if (cur == '>') {
         NEXT;
 	if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
@@ -3563,12 +3475,8 @@
 htmlParseCharRef(htmlParserCtxtPtr ctxt) {
     int val = 0;
 
-    if ((ctxt == NULL) || (ctxt->input == NULL)) {
-	htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
-		     "htmlParseCharRef: context error\n",
-		     NULL, NULL);
+    if ((ctxt == NULL) || (ctxt->input == NULL))
         return(0);
-    }
     if ((CUR == '&') && (NXT(1) == '#') &&
         ((NXT(2) == 'x') || NXT(2) == 'X')) {
 	SKIP(3);
@@ -3681,7 +3589,7 @@
 	             "DOCTYPE improperly terminated\n", NULL, NULL);
         /* Ignore bogus content */
         while ((CUR != 0) && (CUR != '>') &&
-               (ctxt->instate != XML_PARSER_EOF))
+               (PARSER_STOPPED(ctxt) == 0))
             NEXT;
     }
     if (CUR == '>')
@@ -3762,6 +3670,7 @@
 static void
 htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
     const xmlChar *encoding;
+    xmlChar *copy;
 
     if (!attvalue)
 	return;
@@ -3777,7 +3686,10 @@
 	encoding = xmlStrcasestr(attvalue, BAD_CAST"=");
     if (encoding && *encoding == '=') {
 	encoding ++;
-	xmlSetDeclaredEncoding(ctxt, xmlStrdup(encoding));
+        copy = xmlStrdup(encoding);
+        if (copy == NULL)
+            htmlErrMemory(ctxt);
+	xmlSetDeclaredEncoding(ctxt, copy);
     }
 }
 
@@ -3802,13 +3714,21 @@
     att = atts[i++];
     while (att != NULL) {
 	value = atts[i++];
-	if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"http-equiv"))
-	 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
-	    http = 1;
-	else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"charset")))
-	    xmlSetDeclaredEncoding(ctxt, xmlStrdup(value));
-	else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"content")))
-	    content = value;
+        if (value != NULL) {
+            if ((!xmlStrcasecmp(att, BAD_CAST "http-equiv")) &&
+                (!xmlStrcasecmp(value, BAD_CAST "Content-Type"))) {
+                http = 1;
+            } else if (!xmlStrcasecmp(att, BAD_CAST "charset")) {
+                xmlChar *copy;
+
+                copy = xmlStrdup(value);
+                if (copy == NULL)
+                    htmlErrMemory(ctxt);
+                xmlSetDeclaredEncoding(ctxt, copy);
+            } else if (!xmlStrcasecmp(att, BAD_CAST "content")) {
+                content = value;
+            }
+        }
 	att = atts[i++];
     }
     if ((http) && (content != NULL))
@@ -3848,13 +3768,8 @@
     int i;
     int discardtag = 0;
 
-    if ((ctxt == NULL) || (ctxt->input == NULL)) {
-	htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
-		     "htmlParseStartTag: context error\n", NULL, NULL);
+    if ((ctxt == NULL) || (ctxt->input == NULL))
 	return -1;
-    }
-    if (ctxt->instate == XML_PARSER_EOF)
-        return(-1);
     if (CUR != '<') return -1;
     NEXT;
 
@@ -3869,7 +3784,7 @@
 		     NULL, NULL);
 	/* Dump the bogus tag like browsers do */
 	while ((CUR != 0) && (CUR != '>') &&
-               (ctxt->instate != XML_PARSER_EOF))
+               (PARSER_STOPPED(ctxt) == 0))
 	    NEXT;
         return -1;
     }
@@ -3927,7 +3842,7 @@
     while ((CUR != 0) &&
            (CUR != '>') &&
 	   ((CUR != '/') || (NXT(1) != '>')) &&
-           (ctxt->instate != XML_PARSER_EOF)) {
+           (PARSER_STOPPED(ctxt) == 0)) {
 	GROW;
 	attname = htmlParseAttribute(ctxt, &attvalue);
         if (attname != NULL) {
@@ -3953,7 +3868,7 @@
 	        atts = (const xmlChar **)
 		       xmlMalloc(maxatts * sizeof(xmlChar *));
 		if (atts == NULL) {
-		    htmlErrMemory(ctxt, NULL);
+		    htmlErrMemory(ctxt);
 		    if (attvalue != NULL)
 			xmlFree(attvalue);
 		    goto failed;
@@ -3967,7 +3882,7 @@
 	        n = (const xmlChar **) xmlRealloc((void *) atts,
 					     maxatts * sizeof(const xmlChar *));
 		if (n == NULL) {
-		    htmlErrMemory(ctxt, NULL);
+		    htmlErrMemory(ctxt);
 		    if (attvalue != NULL)
 			xmlFree(attvalue);
 		    goto failed;
@@ -3989,7 +3904,7 @@
 	    while ((CUR != 0) &&
 	           !(IS_BLANK_CH(CUR)) && (CUR != '>') &&
 		   ((CUR != '/') || (NXT(1) != '>')) &&
-                   (ctxt->instate != XML_PARSER_EOF))
+                   (PARSER_STOPPED(ctxt) == 0))
 		NEXT;
 	}
 
@@ -4066,7 +3981,8 @@
         htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
 	             "End tag : expected '>'\n", NULL, NULL);
         /* Skip to next '>' */
-        while ((CUR != 0) && (CUR != '>'))
+        while ((PARSER_STOPPED(ctxt) == 0) &&
+               (CUR != 0) && (CUR != '>'))
             NEXT;
     }
     if (CUR == '>')
@@ -4227,12 +4143,9 @@
 
     currentNode = xmlStrdup(ctxt->name);
     depth = ctxt->nameNr;
-    while (1) {
+    while (!PARSER_STOPPED(ctxt)) {
         GROW;
 
-        if (ctxt->instate == XML_PARSER_EOF)
-            break;
-
 	/*
 	 * Our tag or one of it's parent or children is ending.
 	 */
@@ -4387,14 +4300,8 @@
     int depth;
     const xmlChar *oldptr;
 
-    if ((ctxt == NULL) || (ctxt->input == NULL)) {
-	htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
-		     "htmlParseElement: context error\n", NULL, NULL);
+    if ((ctxt == NULL) || (ctxt->input == NULL))
 	return;
-    }
-
-    if (ctxt->instate == XML_PARSER_EOF)
-        return;
 
     /* Capture start position */
     if (ctxt->record_info) {
@@ -4534,14 +4441,8 @@
     htmlParserNodeInfo node_info = { NULL, 0, 0, 0, 0 };
     int failed;
 
-    if ((ctxt == NULL) || (ctxt->input == NULL)) {
-	htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
-		     "htmlParseElementInternal: context error\n", NULL, NULL);
+    if ((ctxt == NULL) || (ctxt->input == NULL))
 	return;
-    }
-
-    if (ctxt->instate == XML_PARSER_EOF)
-        return;
 
     /* Capture start position */
     if (ctxt->record_info) {
@@ -4632,16 +4533,13 @@
     } else {
         currentNode = xmlStrdup(ctxt->name);
         if (currentNode == NULL) {
-            htmlErrMemory(ctxt, NULL);
+            htmlErrMemory(ctxt);
             return;
         }
     }
-    while (1) {
+    while (PARSER_STOPPED(ctxt) == 0) {
         GROW;
 
-        if (ctxt->instate == XML_PARSER_EOF)
-            break;
-
 	/*
 	 * Our tag or one of it's parent or children is ending.
 	 */
@@ -4657,7 +4555,7 @@
                 } else {
                     currentNode = xmlStrdup(ctxt->name);
                     if (currentNode == NULL) {
-                        htmlErrMemory(ctxt, NULL);
+                        htmlErrMemory(ctxt);
                         break;
                     }
                 }
@@ -4681,10 +4579,14 @@
 	        if (currentNode != NULL)
 	            xmlFree(currentNode);
 
-	        currentNode = xmlStrdup(ctxt->name);
-                if (currentNode == NULL) {
-                    htmlErrMemory(ctxt, NULL);
-                    break;
+                if (ctxt->name == NULL) {
+                    currentNode = NULL;
+                } else {
+                    currentNode = xmlStrdup(ctxt->name);
+                    if (currentNode == NULL) {
+                        htmlErrMemory(ctxt);
+                        break;
+                    }
                 }
 	        depth = ctxt->nameNr;
 	        continue;
@@ -4708,10 +4610,14 @@
 	    htmlParserFinishElementParsing(ctxt);
 	    if (currentNode != NULL) xmlFree(currentNode);
 
-	    currentNode = xmlStrdup(ctxt->name);
-            if (currentNode == NULL) {
-                htmlErrMemory(ctxt, NULL);
-                break;
+            if (ctxt->name == NULL) {
+                currentNode = NULL;
+            } else {
+                currentNode = xmlStrdup(ctxt->name);
+                if (currentNode == NULL) {
+                    htmlErrMemory(ctxt);
+                    break;
+                }
             }
 	    depth = ctxt->nameNr;
 	    continue;
@@ -4763,10 +4669,14 @@
             htmlParseElementInternal(ctxt);
             if (currentNode != NULL) xmlFree(currentNode);
 
-            currentNode = xmlStrdup(ctxt->name);
-            if (currentNode == NULL) {
-                htmlErrMemory(ctxt, NULL);
-                break;
+            if (ctxt->name == NULL) {
+                currentNode = NULL;
+            } else {
+                currentNode = xmlStrdup(ctxt->name);
+                if (currentNode == NULL) {
+                    htmlErrMemory(ctxt);
+                    break;
+                }
             }
             depth = ctxt->nameNr;
         }
@@ -4824,24 +4734,19 @@
  * htmlParseDocument:
  * @ctxt:  an HTML parser context
  *
- * parse an HTML document (and build a tree if using the standard SAX
- * interface).
+ * Parse an HTML document and invoke the SAX handlers. This is useful
+ * if you're only interested in custom SAX callbacks. If you want a
+ * document tree, use htmlCtxtParseDocument.
  *
- * Returns 0, -1 in case of error. the parser context is augmented
- *                as a result of the parsing.
+ * Returns 0, -1 in case of error.
  */
 
 int
 htmlParseDocument(htmlParserCtxtPtr ctxt) {
     xmlDtdPtr dtd;
 
-    xmlInitParser();
-
-    if ((ctxt == NULL) || (ctxt->input == NULL)) {
-	htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
-		     "htmlParseDocument: context error\n", NULL, NULL);
-	return(XML_ERR_INTERNAL_ERROR);
-    }
+    if ((ctxt == NULL) || (ctxt->input == NULL))
+	return(-1);
 
     /*
      * Document locator is unused. Only for backward compatibility.
@@ -4873,7 +4778,6 @@
     if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX))
 	ctxt->sax->startDocument(ctxt->userData);
 
-
     /*
      * Parse possible comments and PIs before any content
      */
@@ -4902,9 +4806,10 @@
     /*
      * Parse possible comments and PIs before any content
      */
-    while (((CUR == '<') && (NXT(1) == '!') &&
-            (NXT(2) == '-') && (NXT(3) == '-')) ||
-	   ((CUR == '<') && (NXT(1) == '?'))) {
+    while ((PARSER_STOPPED(ctxt) == 0) &&
+           (((CUR == '<') && (NXT(1) == '!') &&
+             (NXT(2) == '-') && (NXT(3) == '-')) ||
+	    ((CUR == '<') && (NXT(1) == '?')))) {
         htmlParseComment(ctxt);
         htmlParsePI(ctxt);
 	SKIP_BLANKS;
@@ -4930,11 +4835,14 @@
 
     if ((!(ctxt->options & HTML_PARSE_NODEFDTD)) && (ctxt->myDoc != NULL)) {
 	dtd = xmlGetIntSubset(ctxt->myDoc);
-	if (dtd == NULL)
+	if (dtd == NULL) {
 	    ctxt->myDoc->intSubset =
 		xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
 		    BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
 		    BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
+            if (ctxt->myDoc->intSubset == NULL)
+                htmlErrMemory(ctxt);
+        }
     }
     if (! ctxt->wellFormed) return(-1);
     return(0);
@@ -4966,17 +4874,13 @@
     memset(ctxt, 0, sizeof(htmlParserCtxt));
 
     ctxt->dict = xmlDictCreate();
-    if (ctxt->dict == NULL) {
-        htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
+    if (ctxt->dict == NULL)
 	return(-1);
-    }
 
     if (ctxt->sax == NULL)
         ctxt->sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler));
-    if (ctxt->sax == NULL) {
-        htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
+    if (ctxt->sax == NULL)
 	return(-1);
-    }
     if (sax == NULL) {
         memset(ctxt->sax, 0, sizeof(htmlSAXHandler));
         xmlSAX2InitHtmlDefaultSAXHandler(ctxt->sax);
@@ -4989,13 +4893,8 @@
     /* Allocate the Input stack */
     ctxt->inputTab = (htmlParserInputPtr *)
                       xmlMalloc(5 * sizeof(htmlParserInputPtr));
-    if (ctxt->inputTab == NULL) {
-        htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
-	ctxt->inputNr = 0;
-	ctxt->inputMax = 0;
-	ctxt->input = NULL;
+    if (ctxt->inputTab == NULL)
 	return(-1);
-    }
     ctxt->inputNr = 0;
     ctxt->inputMax = 5;
     ctxt->input = NULL;
@@ -5006,35 +4905,16 @@
 
     /* Allocate the Node stack */
     ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr));
-    if (ctxt->nodeTab == NULL) {
-        htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
-	ctxt->nodeNr = 0;
-	ctxt->nodeMax = 0;
-	ctxt->node = NULL;
-	ctxt->inputNr = 0;
-	ctxt->inputMax = 0;
-	ctxt->input = NULL;
+    if (ctxt->nodeTab == NULL)
 	return(-1);
-    }
     ctxt->nodeNr = 0;
     ctxt->nodeMax = 10;
     ctxt->node = NULL;
 
     /* Allocate the Name stack */
     ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
-    if (ctxt->nameTab == NULL) {
-        htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
-	ctxt->nameNr = 0;
-	ctxt->nameMax = 0;
-	ctxt->name = NULL;
-	ctxt->nodeNr = 0;
-	ctxt->nodeMax = 0;
-	ctxt->node = NULL;
-	ctxt->inputNr = 0;
-	ctxt->inputMax = 0;
-	ctxt->input = NULL;
+    if (ctxt->nameTab == NULL)
 	return(-1);
-    }
     ctxt->nameNr = 0;
     ctxt->nameMax = 10;
     ctxt->name = NULL;
@@ -5078,7 +4958,19 @@
 /**
  * htmlNewParserCtxt:
  *
- * Allocate and initialize a new parser context.
+ * Allocate and initialize a new HTML parser context.
+ *
+ * This can be used to parse HTML documents into DOM trees with
+ * functions like xmlCtxtReadFile or xmlCtxtReadMemory.
+ *
+ * See htmlCtxtUseOptions for parser options.
+ *
+ * See xmlCtxtSetErrorHandler for advanced error handling.
+ *
+ * See xmlNewInputURL, xmlNewInputMemory, xmlNewInputIO and similar
+ * functions for advanced input control.
+ *
+ * See htmlNewSAXParserCtxt for custom SAX parsers.
  *
  * Returns the htmlParserCtxtPtr or NULL in case of allocation error
  */
@@ -5094,8 +4986,14 @@
  * @sax:  SAX handler
  * @userData:  user data
  *
- * Allocate and initialize a new SAX parser context. If userData is NULL,
- * the parser context will be passed as user data.
+ * Allocate and initialize a new HTML SAX parser context. If userData
+ * is NULL, the parser context will be passed as user data.
+ *
+ * Available since 2.11.0. If you want support older versions,
+ * it's best to invoke htmlNewParserCtxt and set ctxt->sax with
+ * struct assignment.
+ *
+ * Also see htmlNewParserCtxt.
  *
  * Returns the htmlParserCtxtPtr or NULL in case of allocation error
  */
@@ -5105,11 +5003,11 @@
 {
     xmlParserCtxtPtr ctxt;
 
+    xmlInitParser();
+
     ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt));
-    if (ctxt == NULL) {
-        htmlErrMemory(NULL, "NewParserCtxt: out of memory\n");
+    if (ctxt == NULL)
 	return(NULL);
-    }
     memset(ctxt, 0, sizeof(xmlParserCtxt));
     if (htmlInitParserCtxt(ctxt, sax, userData) < 0) {
         htmlFreeParserCtxt(ctxt);
@@ -5118,68 +5016,65 @@
     return(ctxt);
 }
 
-/**
- * htmlCreateMemoryParserCtxt:
- * @buffer:  a pointer to a char array
- * @size:  the size of the array
- *
- * Create a parser context for an HTML in-memory document. The input buffer
- * must not contain a terminating null byte.
- *
- * Returns the new parser context or NULL
- */
-htmlParserCtxtPtr
-htmlCreateMemoryParserCtxt(const char *buffer, int size) {
+static htmlParserCtxtPtr
+htmlCreateMemoryParserCtxtInternal(const char *url,
+                                   const char *buffer, size_t size,
+                                   const char *encoding) {
     xmlParserCtxtPtr ctxt;
     xmlParserInputPtr input;
-    xmlParserInputBufferPtr buf;
 
     if (buffer == NULL)
 	return(NULL);
-    if (size <= 0)
-	return(NULL);
 
     ctxt = htmlNewParserCtxt();
     if (ctxt == NULL)
 	return(NULL);
 
-    buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
-    if (buf == NULL) {
+    input = xmlNewInputMemory(ctxt, url, buffer, size, encoding, 0);
+    if (input == NULL) {
 	xmlFreeParserCtxt(ctxt);
         return(NULL);
     }
 
-    input = xmlNewInputStream(ctxt);
-    if (input == NULL) {
-	xmlFreeParserInputBuffer(buf);
-	xmlFreeParserCtxt(ctxt);
-	return(NULL);
-    }
-
-    input->filename = NULL;
-    input->buf = buf;
-    xmlBufResetInput(buf->buffer, input);
-
     inputPush(ctxt, input);
+
     return(ctxt);
 }
 
 /**
+ * htmlCreateMemoryParserCtxt:
+ * @buffer:  a pointer to a char array
+ * @size:  the size of the array
+ *
+ * DEPRECATED: Use htmlNewParserCtxt and htmlCtxtReadMemory.
+ *
+ * Create a parser context for an HTML in-memory document. The input
+ * buffer must not contain any terminating null bytes.
+ *
+ * Returns the new parser context or NULL
+ */
+htmlParserCtxtPtr
+htmlCreateMemoryParserCtxt(const char *buffer, int size) {
+    if (size <= 0)
+	return(NULL);
+
+    return(htmlCreateMemoryParserCtxtInternal(NULL, buffer, size, NULL));
+}
+
+/**
  * htmlCreateDocParserCtxt:
  * @str:  a pointer to an array of xmlChar
- * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ * @encoding:  encoding (optional)
  *
- * Create a parser context for an HTML document.
+ * Create a parser context for a null-terminated string.
  *
- * TODO: check the need to add encoding handling there
- *
- * Returns the new parser context or NULL
+ * Returns the new parser context or NULL if a memory allocation failed.
  */
 static htmlParserCtxtPtr
-htmlCreateDocParserCtxt(const xmlChar *str, const char *encoding) {
+htmlCreateDocParserCtxt(const xmlChar *str, const char *url,
+                        const char *encoding) {
     xmlParserCtxtPtr ctxt;
     xmlParserInputPtr input;
-    xmlParserInputBufferPtr buf;
 
     if (str == NULL)
 	return(NULL);
@@ -5188,55 +5083,14 @@
     if (ctxt == NULL)
 	return(NULL);
 
-    buf = xmlParserInputBufferCreateString(str);
-    if (buf == NULL) {
-	xmlFreeParserCtxt(ctxt);
-        return(NULL);
-    }
-
-    input = xmlNewInputStream(ctxt);
+    input = xmlNewInputString(ctxt, url, (const char *) str, encoding, 0);
     if (input == NULL) {
-	xmlFreeParserInputBuffer(buf);
 	xmlFreeParserCtxt(ctxt);
 	return(NULL);
     }
 
-    input->filename = NULL;
-    input->buf = buf;
-    xmlBufResetInput(buf->buffer, input);
-
     inputPush(ctxt, input);
 
-    if (encoding != NULL) {
-	xmlCharEncoding enc;
-	xmlCharEncodingHandlerPtr handler;
-
-	enc = xmlParseCharEncoding(encoding);
-	/*
-	 * registered set of known encodings
-	 */
-	if (enc != XML_CHAR_ENCODING_ERROR) {
-	    xmlSwitchEncoding(ctxt, enc);
-	    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
-		htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
-		             "Unsupported encoding %s\n",
-			     (const xmlChar *) encoding, NULL);
-	    }
-	} else {
-	    /*
-	     * fallback for unknown encodings
-	     */
-	    handler = xmlFindCharEncodingHandler((const char *) encoding);
-	    if (handler != NULL) {
-		xmlSwitchToEncoding(ctxt, handler);
-	    } else {
-		htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
-		             "Unsupported encoding %s\n",
-			     (const xmlChar *) encoding, NULL);
-	    }
-	}
-    }
-
     return(ctxt);
 }
 
@@ -5382,7 +5236,7 @@
 
     htmlParserNodeInfo node_info;
 
-    while (1) {
+    while (PARSER_STOPPED(ctxt) == 0) {
 
 	in = ctxt->input;
 	if (in == NULL) break;
@@ -5444,8 +5298,6 @@
 		if ((ctxt->sax) && (ctxt->sax->startDocument) &&
 	            (!ctxt->disableSAX))
 		    ctxt->sax->startDocument(ctxt->userData);
-                if (ctxt->instate == XML_PARSER_EOF)
-                    goto done;
 
 		cur = in->cur[0];
 		next = in->cur[1];
@@ -5458,8 +5310,6 @@
 		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
 			goto done;
 		    htmlParseDocTypeDecl(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_PROLOG;
                 } else {
 		    ctxt->instate = XML_PARSER_MISC;
@@ -5490,16 +5340,12 @@
 		    if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0))
 			goto done;
 		    htmlParseComment(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_MISC;
 	        } else if ((cur == '<') && (next == '?')) {
 		    if ((!terminate) &&
 		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 			goto done;
 		    htmlParsePI(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_MISC;
 		} else if ((cur == '<') && (next == '!') &&
 		    (UPP(2) == 'D') && (UPP(3) == 'O') &&
@@ -5510,8 +5356,6 @@
 		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0))
 			goto done;
 		    htmlParseDocTypeDecl(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_PROLOG;
 		} else if ((cur == '<') && (next == '!') &&
 		           (avail < 9)) {
@@ -5532,16 +5376,12 @@
 		    if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0))
 			goto done;
 		    htmlParseComment(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_PROLOG;
 	        } else if ((cur == '<') && (next == '?')) {
 		    if ((!terminate) &&
 		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 			goto done;
 		    htmlParsePI(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_PROLOG;
 		} else if ((cur == '<') && (next == '!') &&
 		           (avail < 4)) {
@@ -5567,16 +5407,12 @@
 		    if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0))
 			goto done;
 		    htmlParseComment(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_EPILOG;
 	        } else if ((cur == '<') && (next == '?')) {
 		    if ((!terminate) &&
 		        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 			goto done;
 		    htmlParsePI(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_EPILOG;
 		} else if ((cur == '<') && (next == '!') &&
 		           (avail < 4)) {
@@ -5659,8 +5495,6 @@
 		    if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
 			ctxt->sax->endElement(ctxt->userData, name);
 		    htmlnamePop(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_CONTENT;
 		    break;
 		}
@@ -5683,8 +5517,6 @@
 		    if (ctxt->record_info)
 		        htmlNodeInfoPush(ctxt, &node_info);
 
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    ctxt->instate = XML_PARSER_CONTENT;
 		    break;
 		}
@@ -5701,8 +5533,6 @@
                 if (ctxt->record_info)
 	            htmlNodeInfoPush(ctxt, &node_info);
 
-                if (ctxt->instate == XML_PARSER_EOF)
-                    goto done;
 		ctxt->instate = XML_PARSER_CONTENT;
                 break;
 	    }
@@ -5712,14 +5542,6 @@
                 /*
 		 * Handle preparsed entities and charRef
 		 */
-		if (ctxt->token != 0) {
-		    chr[0] = ctxt->token;
-		    htmlCheckParagraph(ctxt);
-		    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
-			ctxt->sax->characters(ctxt->userData, chr, 1);
-		    ctxt->token = 0;
-		    ctxt->checkIndex = 0;
-		}
 		if ((avail == 1) && (terminate)) {
 		    cur = in->cur[0];
 		    if ((cur != '<') && (cur != '&')) {
@@ -5742,7 +5564,6 @@
 					    ctxt->userData, chr, 1);
 			    }
 			}
-			ctxt->token = 0;
 			ctxt->checkIndex = 0;
 			in->cur++;
 			break;
@@ -5775,8 +5596,6 @@
                         }
 		    }
 		    htmlParseScript(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
 		    if ((cur == '<') && (next == '/')) {
 			ctxt->instate = XML_PARSER_END_TAG;
 			ctxt->checkIndex = 0;
@@ -5804,8 +5623,6 @@
                             (htmlParseLookupCommentEnd(ctxt) < 0))
                             goto done;
                         htmlParseComment(ctxt);
-                        if (ctxt->instate == XML_PARSER_EOF)
-                            goto done;
                         ctxt->instate = XML_PARSER_CONTENT;
                     } else {
                         if ((!terminate) &&
@@ -5818,8 +5635,6 @@
                         (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
                         goto done;
                     htmlParsePI(ctxt);
-                    if (ctxt->instate == XML_PARSER_EOF)
-                        goto done;
                     ctxt->instate = XML_PARSER_CONTENT;
                 } else if ((cur == '<') && (next == '/')) {
                     ctxt->instate = XML_PARSER_END_TAG;
@@ -5848,7 +5663,7 @@
                         (htmlParseLookupSequence(ctxt, '<', 0, 0, 0) < 0))
                         goto done;
                     ctxt->checkIndex = 0;
-                    while ((ctxt->instate != XML_PARSER_EOF) &&
+                    while ((PARSER_STOPPED(ctxt) == 0) &&
                            (cur != '<') && (in->cur < in->end)) {
                         if (cur == '&') {
                             htmlParseReference(ctxt);
@@ -5868,8 +5683,6 @@
 		    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0))
 		    goto done;
 		htmlParseEndTag(ctxt);
-                if (ctxt->instate == XML_PARSER_EOF)
-                    goto done;
 		if (ctxt->nameNr == 0) {
 		    ctxt->instate = XML_PARSER_EPILOG;
 		} else {
@@ -5901,11 +5714,14 @@
 	 (ctxt->instate == XML_PARSER_EPILOG))) {
 	xmlDtdPtr dtd;
 	dtd = xmlGetIntSubset(ctxt->myDoc);
-	if (dtd == NULL)
+	if (dtd == NULL) {
 	    ctxt->myDoc->intSubset =
 		xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
 		    BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
 		    BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
+            if (ctxt->myDoc->intSubset == NULL)
+                htmlErrMemory(ctxt);
+        }
     }
     return(ret);
 }
@@ -5913,24 +5729,33 @@
 /**
  * htmlParseChunk:
  * @ctxt:  an HTML parser context
- * @chunk:  an char array
- * @size:  the size in byte of the chunk
+ * @chunk:  chunk of memory
+ * @size:  size of chunk in bytes
  * @terminate:  last chunk indicator
  *
- * Parse a Chunk of memory
+ * Parse a chunk of memory in push parser mode.
  *
- * Returns zero if no error, the xmlParserErrors otherwise.
+ * Assumes that the parser context was initialized with
+ * htmlCreatePushParserCtxt.
+ *
+ * The last chunk, which will often be empty, must be marked with
+ * the @terminate flag. With the default SAX callbacks, the resulting
+ * document will be available in ctxt->myDoc. This pointer will not
+ * be freed by the library.
+ *
+ * If the document isn't well-formed, ctxt->myDoc is set to NULL.
+ *
+ * Returns an xmlParserErrors code (0 on success).
  */
 int
 htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
               int terminate) {
-    if ((ctxt == NULL) || (ctxt->input == NULL)) {
-	htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
-		     "htmlParseChunk: context error\n", NULL, NULL);
-	return(XML_ERR_INTERNAL_ERROR);
-    }
+    if ((ctxt == NULL) || (ctxt->input == NULL))
+	return(XML_ERR_ARGUMENT);
+    if (PARSER_STOPPED(ctxt) != 0)
+        return(ctxt->errNo);
     if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
-        (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF))  {
+        (ctxt->input->buf != NULL))  {
 	size_t pos = ctxt->input->cur - ctxt->input->base;
 	int res;
 
@@ -5945,12 +5770,6 @@
     }
     htmlParseTryOrFinish(ctxt, terminate);
     if (terminate) {
-	if ((ctxt->instate != XML_PARSER_EOF) &&
-	    (ctxt->instate != XML_PARSER_EPILOG) &&
-	    (ctxt->instate != XML_PARSER_MISC)) {
-	    ctxt->errNo = XML_ERR_DOCUMENT_END;
-	    ctxt->wellFormed = 0;
-	}
 	if (ctxt->instate != XML_PARSER_EOF) {
 	    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
 		ctxt->sax->endDocument(ctxt->userData);
@@ -5968,74 +5787,37 @@
 
 /**
  * htmlCreatePushParserCtxt:
- * @sax:  a SAX handler
- * @user_data:  The user data returned on SAX callbacks
- * @chunk:  a pointer to an array of chars
+ * @sax:  a SAX handler (optional)
+ * @user_data:  The user data returned on SAX callbacks (optional)
+ * @chunk:  a pointer to an array of chars (optional)
  * @size:  number of chars in the array
- * @filename:  an optional file name or URI
- * @enc:  an optional encoding
+ * @filename:  only used for error reporting (optional)
+ * @enc:  encoding (deprecated, pass XML_CHAR_ENCODING_NONE)
  *
- * Create a parser context for using the HTML parser in push mode
- * The value of @filename is used for fetching external entities
- * and error/warning reports.
+ * Create a parser context for using the HTML parser in push mode.
  *
- * Returns the new parser context or NULL
+ * Returns the new parser context or NULL if a memory allocation
+ * failed.
  */
 htmlParserCtxtPtr
 htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
                          const char *chunk, int size, const char *filename,
 			 xmlCharEncoding enc) {
     htmlParserCtxtPtr ctxt;
-    htmlParserInputPtr inputStream;
-    xmlParserInputBufferPtr buf;
-
-    xmlInitParser();
-
-    buf = xmlAllocParserInputBuffer(enc);
-    if (buf == NULL) return(NULL);
+    htmlParserInputPtr input;
+    const char *encoding;
 
     ctxt = htmlNewSAXParserCtxt(sax, user_data);
-    if (ctxt == NULL) {
-	xmlFreeParserInputBuffer(buf);
+    if (ctxt == NULL)
+	return(NULL);
+
+    encoding = xmlGetCharEncodingName(enc);
+    input = xmlNewInputPush(ctxt, filename, chunk, size, encoding);
+    if (input == NULL) {
+	htmlFreeParserCtxt(ctxt);
 	return(NULL);
     }
-    if (filename == NULL) {
-	ctxt->directory = NULL;
-    } else {
-        ctxt->directory = xmlParserGetDirectory(filename);
-    }
-
-    inputStream = htmlNewInputStream(ctxt);
-    if (inputStream == NULL) {
-	xmlFreeParserCtxt(ctxt);
-	xmlFreeParserInputBuffer(buf);
-	return(NULL);
-    }
-
-    if (filename == NULL)
-	inputStream->filename = NULL;
-    else
-	inputStream->filename = (char *)
-	    xmlCanonicPath((const xmlChar *) filename);
-    inputStream->buf = buf;
-    xmlBufResetInput(buf->buffer, inputStream);
-
-    inputPush(ctxt, inputStream);
-
-    if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
-        (ctxt->input->buf != NULL))  {
-	size_t pos = ctxt->input->cur - ctxt->input->base;
-        int res;
-
-	res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
-        xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos);
-        if (res < 0) {
-            htmlParseErr(ctxt, ctxt->input->buf->error,
-                         "xmlParserInputBufferPush failed\n", NULL, NULL);
-            xmlHaltParser(ctxt);
-        }
-    }
-    ctxt->progressive = 1;
+    inputPush(ctxt, input);
 
     return(ctxt);
 }
@@ -6064,25 +5846,20 @@
     htmlDocPtr ret;
     htmlParserCtxtPtr ctxt;
 
-    xmlInitParser();
+    if (cur == NULL)
+        return(NULL);
 
-    if (cur == NULL) return(NULL);
+    ctxt = htmlCreateDocParserCtxt(cur, NULL, encoding);
+    if (ctxt == NULL)
+        return(NULL);
 
-
-    ctxt = htmlCreateDocParserCtxt(cur, encoding);
-    if (ctxt == NULL) return(NULL);
     if (sax != NULL) {
-        if (ctxt->sax != NULL) xmlFree (ctxt->sax);
-        ctxt->sax = sax;
+        *ctxt->sax = *sax;
         ctxt->userData = userData;
     }
 
     htmlParseDocument(ctxt);
     ret = ctxt->myDoc;
-    if (sax != NULL) {
-	ctxt->sax = NULL;
-	ctxt->userData = NULL;
-    }
     htmlFreeParserCtxt(ctxt);
 
     return(ret);
@@ -6091,9 +5868,13 @@
 /**
  * htmlParseDoc:
  * @cur:  a pointer to an array of xmlChar
- * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ * @encoding:  the encoding (optional)
  *
- * parse an HTML in-memory document and build a tree.
+ * DEPRECATED: Use htmlReadDoc.
+ *
+ * Parse an HTML in-memory document and build a tree.
+ *
+ * This function uses deprecated global parser options.
  *
  * Returns the resulting document tree
  */
@@ -6107,20 +5888,24 @@
 /**
  * htmlCreateFileParserCtxt:
  * @filename:  the filename
- * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ * @encoding:  optional encoding
  *
- * Create a parser context for a file content.
+ * DEPRECATED: Use htmlNewParserCtxt and htmlCtxtReadFile.
+ *
+ * Create a parser context to read from a file.
+ *
+ * A non-NULL encoding overrides encoding declarations in the document.
+ *
  * Automatic support for ZLIB/Compress compressed document is provided
  * by default if found at compile-time.
  *
- * Returns the new parser context or NULL
+ * Returns the new parser context or NULL if a memory allocation failed.
  */
 htmlParserCtxtPtr
 htmlCreateFileParserCtxt(const char *filename, const char *encoding)
 {
     htmlParserCtxtPtr ctxt;
-    htmlParserInputPtr inputStream;
-    char *canonicFilename;
+    htmlParserInputPtr input;
 
     if (filename == NULL)
         return(NULL);
@@ -6129,30 +5914,13 @@
     if (ctxt == NULL) {
 	return(NULL);
     }
-    canonicFilename = (char *) xmlCanonicPath((const xmlChar *) filename);
-    if (canonicFilename == NULL) {
+
+    input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0);
+    if (input == NULL) {
 	xmlFreeParserCtxt(ctxt);
 	return(NULL);
     }
-
-    inputStream = xmlLoadExternalEntity(canonicFilename, NULL, ctxt);
-    xmlFree(canonicFilename);
-    if (inputStream == NULL) {
-	xmlFreeParserCtxt(ctxt);
-	return(NULL);
-    }
-
-    inputPush(ctxt, inputStream);
-
-    /* set encoding */
-    if (encoding) {
-        xmlCharEncodingHandlerPtr hdlr;
-
-        hdlr = xmlFindCharEncodingHandler(encoding);
-        if (hdlr != NULL) {
-            xmlSwitchToEncoding(ctxt, hdlr);
-        }
-    }
+    inputPush(ctxt, input);
 
     return(ctxt);
 }
@@ -6160,7 +5928,7 @@
 /**
  * htmlSAXParseFile:
  * @filename:  the filename
- * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ * @encoding:  encoding (optional)
  * @sax:  the SAX handler block
  * @userData: if using SAX, this pointer will be provided on callbacks.
  *
@@ -6182,8 +5950,6 @@
     htmlParserCtxtPtr ctxt;
     htmlSAXHandlerPtr oldsax = NULL;
 
-    xmlInitParser();
-
     ctxt = htmlCreateFileParserCtxt(filename, encoding);
     if (ctxt == NULL) return(NULL);
     if (sax != NULL) {
@@ -6207,10 +5973,11 @@
 /**
  * htmlParseFile:
  * @filename:  the filename
- * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ * @encoding:  encoding (optional)
  *
- * parse an HTML file and build a tree. Automatic support for ZLIB/Compress
- * compressed document is provided by default if found at compile-time.
+ * Parse an HTML file and build a tree.
+ *
+ * See xmlNewInputURL for details.
  *
  * Returns the resulting document tree
  */
@@ -6381,7 +6148,6 @@
     if (ctxt == NULL)
         return;
 
-    xmlInitParser();
     dict = ctxt->dict;
 
     while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */
@@ -6411,8 +6177,6 @@
     ctxt->version = NULL;
     DICT_FREE(ctxt->encoding);
     ctxt->encoding = NULL;
-    DICT_FREE(ctxt->directory);
-    ctxt->directory = NULL;
     DICT_FREE(ctxt->extSubURI);
     ctxt->extSubURI = NULL;
     DICT_FREE(ctxt->extSubSystem);
@@ -6425,9 +6189,7 @@
     ctxt->hasExternalSubset = 0;
     ctxt->hasPErefs = 0;
     ctxt->html = 1;
-    ctxt->external = 0;
     ctxt->instate = XML_PARSER_START;
-    ctxt->token = 0;
 
     ctxt->wellFormed = 1;
     ctxt->nsWellFormed = 1;
@@ -6534,264 +6296,279 @@
 }
 
 /**
- * htmlDoRead:
+ * htmlCtxtParseDocument:
  * @ctxt:  an HTML parser context
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
- * @options:  a combination of htmlParserOption(s)
- * @reuse:  keep the context for reuse
  *
- * Common front-end for the htmlRead functions
+ * Parse an HTML document and return the resulting document tree.
  *
  * Returns the resulting document tree or NULL
  */
-static htmlDocPtr
-htmlDoRead(htmlParserCtxtPtr ctxt, const char *URL, const char *encoding,
-          int options, int reuse)
+htmlDocPtr
+htmlCtxtParseDocument(htmlParserCtxtPtr ctxt, xmlParserInputPtr input)
 {
     htmlDocPtr ret;
 
-    htmlCtxtUseOptions(ctxt, options);
-    ctxt->html = 1;
-    if (encoding != NULL) {
-        xmlCharEncodingHandlerPtr hdlr;
+    if ((ctxt == NULL) || (input == NULL))
+        return(NULL);
 
-	hdlr = xmlFindCharEncodingHandler(encoding);
-	if (hdlr != NULL) {
-	    xmlSwitchToEncoding(ctxt, hdlr);
-        }
+    /* assert(ctxt->inputNr == 0); */
+    while (ctxt->inputNr > 0)
+        xmlFreeInputStream(inputPop(ctxt));
+
+    if (inputPush(ctxt, input) < 0) {
+        xmlFreeInputStream(input);
+        return(NULL);
     }
-    if ((URL != NULL) && (ctxt->input != NULL) &&
-        (ctxt->input->filename == NULL))
-        ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL);
+
+    ctxt->html = 1;
     htmlParseDocument(ctxt);
-    ret = ctxt->myDoc;
-    ctxt->myDoc = NULL;
-    if (!reuse) {
-        if ((ctxt->dictNames) &&
-	    (ret != NULL) &&
-	    (ret->dict == ctxt->dict))
-	    ctxt->dict = NULL;
-	xmlFreeParserCtxt(ctxt);
+
+    if (ctxt->errNo != XML_ERR_NO_MEMORY) {
+        ret = ctxt->myDoc;
+    } else {
+        ret = NULL;
+        xmlFreeDoc(ctxt->myDoc);
     }
-    return (ret);
+    ctxt->myDoc = NULL;
+
+    /* assert(ctxt->inputNr == 1); */
+    while (ctxt->inputNr > 0)
+        xmlFreeInputStream(inputPop(ctxt));
+
+    return(ret);
 }
 
 /**
  * htmlReadDoc:
- * @cur:  a pointer to a zero terminated string
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
- * @options:  a combination of htmlParserOption(s)
+ * @str:  a pointer to a zero terminated string
+ * @url:  only used for error reporting (optoinal)
+ * @encoding:  the document encoding (optional)
+ * @options:  a combination of htmlParserOptions
  *
- * parse an XML in-memory document and build a tree.
+ * Convenience function to parse an HTML document from a zero-terminated
+ * string.
  *
- * Returns the resulting document tree
+ * See htmlCtxtReadDoc for details.
+ *
+ * Returns the resulting document tree.
  */
 htmlDocPtr
-htmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options)
+htmlReadDoc(const xmlChar *str, const char *url, const char *encoding,
+            int options)
 {
     htmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
+    htmlDocPtr doc;
 
-    if (cur == NULL)
-        return (NULL);
-
-    xmlInitParser();
-    ctxt = htmlCreateDocParserCtxt(cur, NULL);
+    ctxt = htmlNewParserCtxt();
     if (ctxt == NULL)
-        return (NULL);
-    return (htmlDoRead(ctxt, URL, encoding, options, 0));
+        return(NULL);
+
+    htmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputString(ctxt, url, (const char *) str, encoding,
+                              XML_INPUT_BUF_STATIC);
+
+    doc = htmlCtxtParseDocument(ctxt, input);
+
+    htmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * htmlReadFile:
  * @filename:  a file or URL
- * @encoding:  the document encoding, or NULL
- * @options:  a combination of htmlParserOption(s)
+ * @encoding:  the document encoding (optional)
+ * @options:  a combination of htmlParserOptions
  *
- * parse an XML file from the filesystem or the network.
+ * Convenience function to parse an HTML file from the filesystem,
+ * the network or a global user-defined resource loader.
  *
- * Returns the resulting document tree
+ * See htmlCtxtReadFile for details.
+ *
+ * Returns the resulting document tree.
  */
 htmlDocPtr
 htmlReadFile(const char *filename, const char *encoding, int options)
 {
     htmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
+    htmlDocPtr doc;
 
-    xmlInitParser();
-    ctxt = htmlCreateFileParserCtxt(filename, encoding);
+    ctxt = htmlNewParserCtxt();
     if (ctxt == NULL)
-        return (NULL);
-    return (htmlDoRead(ctxt, NULL, NULL, options, 0));
+        return(NULL);
+
+    htmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0);
+
+    doc = htmlCtxtParseDocument(ctxt, input);
+
+    htmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * htmlReadMemory:
  * @buffer:  a pointer to a char array
  * @size:  the size of the array
- * @URL:  the base URL to use for the document
+ * @url:  only used for error reporting (optional)
  * @encoding:  the document encoding, or NULL
  * @options:  a combination of htmlParserOption(s)
  *
- * Parse an HTML in-memory document and build a tree. The input buffer must
- * not contain a terminating null byte.
+ * Convenience function to parse an HTML document from memory.
+ * The input buffer must not contain any terminating null bytes.
+ *
+ * See htmlCtxtReadMemory for details.
  *
  * Returns the resulting document tree
  */
 htmlDocPtr
-htmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options)
+htmlReadMemory(const char *buffer, int size, const char *url,
+               const char *encoding, int options)
 {
     htmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
+    htmlDocPtr doc;
 
-    xmlInitParser();
-    ctxt = htmlCreateMemoryParserCtxt(buffer, size);
+    if (size < 0)
+	return(NULL);
+
+    ctxt = htmlNewParserCtxt();
     if (ctxt == NULL)
-        return (NULL);
-    return (htmlDoRead(ctxt, URL, encoding, options, 0));
+        return(NULL);
+
+    htmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputMemory(ctxt, url, buffer, size, encoding,
+                              XML_INPUT_BUF_STATIC);
+
+    doc = htmlCtxtParseDocument(ctxt, input);
+
+    htmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * htmlReadFd:
  * @fd:  an open file descriptor
- * @URL:  the base URL to use for the document
+ * @url:  only used for error reporting (optional)
  * @encoding:  the document encoding, or NULL
- * @options:  a combination of htmlParserOption(s)
+ * @options:  a combination of htmlParserOptions
  *
- * parse an HTML from a file descriptor and build a tree.
+ * Convenience function to parse an HTML document from a
+ * file descriptor.
+ *
  * NOTE that the file descriptor will not be closed when the
- *      reader is closed or reset.
+ * context is freed or reset.
+ *
+ * See htmlCtxtReadFd for details.
  *
  * Returns the resulting document tree
  */
 htmlDocPtr
-htmlReadFd(int fd, const char *URL, const char *encoding, int options)
+htmlReadFd(int fd, const char *url, const char *encoding, int options)
 {
     htmlParserCtxtPtr ctxt;
-    xmlParserInputBufferPtr input;
-    htmlParserInputPtr stream;
+    xmlParserInputPtr input;
+    htmlDocPtr doc;
 
-    if (fd < 0)
-        return (NULL);
-
-    xmlInitParser();
-    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
-    if (input == NULL)
-        return (NULL);
-    input->closecallback = NULL;
     ctxt = htmlNewParserCtxt();
-    if (ctxt == NULL) {
-        xmlFreeParserInputBuffer(input);
-        return (NULL);
-    }
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-        xmlFreeParserInputBuffer(input);
-	htmlFreeParserCtxt(ctxt);
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (htmlDoRead(ctxt, URL, encoding, options, 0));
+    if (ctxt == NULL)
+        return(NULL);
+
+    htmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputFd(ctxt, url, fd, encoding, 0);
+    input->buf->closecallback = NULL;
+
+    doc = htmlCtxtParseDocument(ctxt, input);
+
+    htmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * htmlReadIO:
  * @ioread:  an I/O read function
- * @ioclose:  an I/O close function
+ * @ioclose:  an I/O close function (optional)
  * @ioctx:  an I/O handler
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
+ * @url:  only used for error reporting (optional)
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of htmlParserOption(s)
  *
- * parse an HTML document from I/O functions and source and build a tree.
+ * Convenience function to parse an HTML document from I/O functions
+ * and context.
+ *
+ * See htmlCtxtReadIO for details.
  *
  * Returns the resulting document tree
  */
 htmlDocPtr
 htmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
-          void *ioctx, const char *URL, const char *encoding, int options)
+          void *ioctx, const char *url, const char *encoding, int options)
 {
     htmlParserCtxtPtr ctxt;
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
+    htmlDocPtr doc;
 
-    if (ioread == NULL)
-        return (NULL);
-    xmlInitParser();
-
-    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
-                                         XML_CHAR_ENCODING_NONE);
-    if (input == NULL) {
-        if (ioclose != NULL)
-            ioclose(ioctx);
-        return (NULL);
-    }
     ctxt = htmlNewParserCtxt();
-    if (ctxt == NULL) {
-        xmlFreeParserInputBuffer(input);
+    if (ctxt == NULL)
         return (NULL);
-    }
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-        xmlFreeParserInputBuffer(input);
-	xmlFreeParserCtxt(ctxt);
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (htmlDoRead(ctxt, URL, encoding, options, 0));
+
+    htmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputIO(ctxt, url, ioread, ioclose, ioctx, encoding, 0);
+
+    doc = htmlCtxtParseDocument(ctxt, input);
+
+    htmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * htmlCtxtReadDoc:
  * @ctxt:  an HTML parser context
  * @str:  a pointer to a zero terminated string
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
- * @options:  a combination of htmlParserOption(s)
+ * @URL:  only used for error reporting (optional)
+ * @encoding:  the document encoding (optional)
+ * @options:  a combination of htmlParserOptions
  *
- * parse an XML in-memory document and build a tree.
- * This reuses the existing @ctxt parser context
+ * Parse an HTML in-memory document and build a tree.
+ *
+ * See htmlCtxtUseOptions for details.
  *
  * Returns the resulting document tree
  */
 htmlDocPtr
 htmlCtxtReadDoc(htmlParserCtxtPtr ctxt, const xmlChar *str,
-               const char *URL, const char *encoding, int options)
+                const char *URL, const char *encoding, int options)
 {
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
     if (ctxt == NULL)
         return (NULL);
-    if (str == NULL)
-        return (NULL);
-    xmlInitParser();
 
     htmlCtxtReset(ctxt);
+    htmlCtxtUseOptions(ctxt, options);
 
-    input = xmlParserInputBufferCreateString(str);
-    if (input == NULL) {
-	return(NULL);
-    }
+    input = xmlNewInputString(ctxt, URL, (const char *) str, encoding, 0);
 
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-	xmlFreeParserInputBuffer(input);
-	return(NULL);
-    }
-
-    inputPush(ctxt, stream);
-    return (htmlDoRead(ctxt, URL, encoding, options, 1));
+    return(htmlCtxtParseDocument(ctxt, input));
 }
 
 /**
  * htmlCtxtReadFile:
  * @ctxt:  an HTML parser context
  * @filename:  a file or URL
- * @encoding:  the document encoding, or NULL
- * @options:  a combination of htmlParserOption(s)
+ * @encoding:  the document encoding (optional)
+ * @options:  a combination of htmlParserOptions
  *
- * parse an XML file from the filesystem or the network.
- * This reuses the existing @ctxt parser context
+ * Parse an HTML file from the filesystem, the network or a
+ * user-defined resource loader.
+ *
+ * See xmlNewInputURL and htmlCtxtUseOptions for details.
  *
  * Returns the resulting document tree
  */
@@ -6799,22 +6576,17 @@
 htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename,
                 const char *encoding, int options)
 {
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
-    if (filename == NULL)
-        return (NULL);
     if (ctxt == NULL)
         return (NULL);
-    xmlInitParser();
 
     htmlCtxtReset(ctxt);
+    htmlCtxtUseOptions(ctxt, options);
 
-    stream = xmlLoadExternalEntity(filename, NULL, ctxt);
-    if (stream == NULL) {
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (htmlDoRead(ctxt, NULL, encoding, options, 1));
+    input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0);
+
+    return(htmlCtxtParseDocument(ctxt, input));
 }
 
 /**
@@ -6822,13 +6594,14 @@
  * @ctxt:  an HTML parser context
  * @buffer:  a pointer to a char array
  * @size:  the size of the array
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
- * @options:  a combination of htmlParserOption(s)
+ * @URL:  only used for error reporting (optional)
+ * @encoding:  the document encoding (optinal)
+ * @options:  a combination of htmlParserOptions
  *
  * Parse an HTML in-memory document and build a tree. The input buffer must
- * not contain a terminating null byte.
- * This reuses the existing @ctxt parser context
+ * not contain any terminating null bytes.
+ *
+ * See htmlCtxtUseOptions for details.
  *
  * Returns the resulting document tree
  */
@@ -6836,42 +6609,34 @@
 htmlCtxtReadMemory(htmlParserCtxtPtr ctxt, const char *buffer, int size,
                   const char *URL, const char *encoding, int options)
 {
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
-    if (ctxt == NULL)
+    if ((ctxt == NULL) || (size < 0))
         return (NULL);
-    if (buffer == NULL)
-        return (NULL);
-    xmlInitParser();
 
     htmlCtxtReset(ctxt);
+    htmlCtxtUseOptions(ctxt, options);
 
-    input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
-    if (input == NULL) {
-	return(NULL);
-    }
+    input = xmlNewInputMemory(ctxt, URL, buffer, size, encoding,
+                              XML_INPUT_BUF_STATIC);
 
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-	xmlFreeParserInputBuffer(input);
-	return(NULL);
-    }
-
-    inputPush(ctxt, stream);
-    return (htmlDoRead(ctxt, URL, encoding, options, 1));
+    return(htmlCtxtParseDocument(ctxt, input));
 }
 
 /**
  * htmlCtxtReadFd:
  * @ctxt:  an HTML parser context
  * @fd:  an open file descriptor
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
- * @options:  a combination of htmlParserOption(s)
+ * @URL:  only used for error reporting (optional)
+ * @encoding:  the document encoding (optinal)
+ * @options:  a combination of htmlParserOptions
  *
- * parse an XML from a file descriptor and build a tree.
- * This reuses the existing @ctxt parser context
+ * Parse an HTML from a file descriptor and build a tree.
+ *
+ * See htmlCtxtUseOptions for details.
+ *
+ * NOTE that the file descriptor will not be closed when the
+ * context is freed or reset.
  *
  * Returns the resulting document tree
  */
@@ -6879,28 +6644,18 @@
 htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd,
               const char *URL, const char *encoding, int options)
 {
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
-    if (fd < 0)
-        return (NULL);
     if (ctxt == NULL)
-        return (NULL);
-    xmlInitParser();
+        return(NULL);
 
     htmlCtxtReset(ctxt);
+    htmlCtxtUseOptions(ctxt, options);
 
+    input = xmlNewInputFd(ctxt, URL, fd, encoding, 0);
+    input->buf->closecallback = NULL;
 
-    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
-    if (input == NULL)
-        return (NULL);
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-        xmlFreeParserInputBuffer(input);
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (htmlDoRead(ctxt, URL, encoding, options, 1));
+    return(htmlCtxtParseDocument(ctxt, input));
 }
 
 /**
@@ -6913,8 +6668,9 @@
  * @encoding:  the document encoding, or NULL
  * @options:  a combination of htmlParserOption(s)
  *
- * parse an HTML document from I/O functions and source and build a tree.
- * This reuses the existing @ctxt parser context
+ * Parse an HTML document from I/O functions and source and build a tree.
+ *
+ * See xmlNewInputIO and htmlCtxtUseOptions for details.
  *
  * Returns the resulting document tree
  */
@@ -6924,31 +6680,17 @@
 	      const char *URL,
               const char *encoding, int options)
 {
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
-    if (ioread == NULL)
-        return (NULL);
     if (ctxt == NULL)
         return (NULL);
-    xmlInitParser();
 
     htmlCtxtReset(ctxt);
+    htmlCtxtUseOptions(ctxt, options);
 
-    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
-                                         XML_CHAR_ENCODING_NONE);
-    if (input == NULL) {
-        if (ioclose != NULL)
-            ioclose(ioctx);
-        return (NULL);
-    }
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-        xmlFreeParserInputBuffer(input);
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (htmlDoRead(ctxt, URL, encoding, options, 1));
+    input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0);
+
+    return(htmlCtxtParseDocument(ctxt, input));
 }
 
 #endif /* LIBXML_HTML_ENABLED */
diff --git a/src/HTMLtree.c b/src/HTMLtree.c
index 8698f53..89d6181 100644
--- a/src/HTMLtree.c
+++ b/src/HTMLtree.c
@@ -334,17 +334,6 @@
  *			Output error handlers				*
  *									*
  ************************************************************************/
-/**
- * htmlSaveErrMemory:
- * @extra:  extra information
- *
- * Handle an out of memory condition
- */
-static void
-htmlSaveErrMemory(const char *extra)
-{
-    __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
-}
 
 /**
  * htmlSaveErr:
@@ -358,6 +347,7 @@
 htmlSaveErr(int code, xmlNodePtr node, const char *extra)
 {
     const char *msg = NULL;
+    int res;
 
     switch(code) {
         case XML_SAVE_NOT_UTF8:
@@ -375,7 +365,13 @@
 	default:
 	    msg = "unexpected error number\n";
     }
-    __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
+
+    res = __xmlRaiseError(NULL, NULL, NULL, NULL, node,
+                          XML_FROM_OUTPUT, code, XML_ERR_ERROR, NULL, 0,
+                          extra, NULL, NULL, 0, 0,
+                          msg, extra);
+    if (res < 0)
+        xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_OUTPUT, NULL);
 }
 
 /************************************************************************
@@ -384,6 +380,32 @@
  *									*
  ************************************************************************/
 
+static xmlCharEncodingHandler *
+htmlFindOutputEncoder(const char *encoding) {
+    xmlCharEncodingHandler *handler = NULL;
+
+    if (encoding != NULL) {
+	xmlCharEncoding enc;
+
+	enc = xmlParseCharEncoding(encoding);
+	if (enc != XML_CHAR_ENCODING_UTF8) {
+	    xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler);
+	    if (handler == NULL)
+		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
+	}
+    } else {
+        /*
+         * Fallback to HTML or ASCII when the encoding is unspecified
+         */
+        if (handler == NULL)
+            xmlOpenCharEncodingHandler("HTML", /* output */ 1, &handler);
+        if (handler == NULL)
+            xmlOpenCharEncodingHandler("ascii", /* output */ 1, &handler);
+    }
+
+    return(handler);
+}
+
 /**
  * htmlBufNodeDumpFormat:
  * @buf:  the xmlBufPtr output
@@ -409,10 +431,8 @@
 	return (-1);
     }
     outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
-    if (outbuf == NULL) {
-        htmlSaveErrMemory("allocating HTML output buffer");
+    if (outbuf == NULL)
 	return (-1);
-    }
     memset(outbuf, 0, sizeof(xmlOutputBuffer));
     outbuf->buffer = buf;
     outbuf->encoder = NULL;
@@ -479,33 +499,15 @@
 htmlNodeDumpFileFormat(FILE *out, xmlDocPtr doc,
 	               xmlNodePtr cur, const char *encoding, int format) {
     xmlOutputBufferPtr buf;
-    xmlCharEncodingHandlerPtr handler = NULL;
+    xmlCharEncodingHandlerPtr handler;
     int ret;
 
     xmlInitParser();
 
-    if (encoding != NULL) {
-	xmlCharEncoding enc;
-
-	enc = xmlParseCharEncoding(encoding);
-	if (enc != XML_CHAR_ENCODING_UTF8) {
-	    handler = xmlFindCharEncodingHandler(encoding);
-	    if (handler == NULL)
-		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
-	}
-    } else {
-        /*
-         * Fallback to HTML or ASCII when the encoding is unspecified
-         */
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("HTML");
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("ascii");
-    }
-
     /*
      * save the content to a temp buffer.
      */
+    handler = htmlFindOutputEncoder(encoding);
     buf = xmlOutputBufferCreateFile(out, handler);
     if (buf == NULL) return(0);
 
@@ -556,27 +558,7 @@
     }
 
     encoding = (const char *) htmlGetMetaEncoding(cur);
-
-    if (encoding != NULL) {
-	xmlCharEncoding enc;
-
-	enc = xmlParseCharEncoding(encoding);
-	if (enc != XML_CHAR_ENCODING_UTF8) {
-	    handler = xmlFindCharEncodingHandler(encoding);
-	    if (handler == NULL)
-                htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
-
-	}
-    } else {
-        /*
-         * Fallback to HTML or ASCII when the encoding is unspecified
-         */
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("HTML");
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("ascii");
-    }
-
+    handler = htmlFindOutputEncoder(encoding);
     buf = xmlAllocOutputBufferInternal(handler);
     if (buf == NULL) {
 	*mem = NULL;
@@ -712,14 +694,14 @@
 		    xmlBufWriteQuotedString(buf->buffer, escaped);
 		    xmlFree(escaped);
 		} else {
-		    xmlBufWriteQuotedString(buf->buffer, value);
+                    buf->error = XML_ERR_NO_MEMORY;
 		}
 	    } else {
 		xmlBufWriteQuotedString(buf->buffer, value);
 	    }
 	    xmlFree(value);
 	} else  {
-	    xmlOutputBufferWriteString(buf, "=\"\"");
+            buf->error = XML_ERR_NO_MEMORY;
 	}
     }
 }
@@ -860,10 +842,12 @@
                 xmlChar *buffer;
 
                 buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
-                if (buffer != NULL) {
-                    xmlOutputBufferWriteString(buf, (const char *)buffer);
-                    xmlFree(buffer);
+                if (buffer == NULL) {
+                    buf->error = XML_ERR_NO_MEMORY;
+                    return;
                 }
+                xmlOutputBufferWriteString(buf, (const char *)buffer);
+                xmlFree(buffer);
             } else {
                 xmlOutputBufferWriteString(buf, (const char *)cur->content);
             }
@@ -1039,26 +1023,7 @@
     }
 
     encoding = (const char *) htmlGetMetaEncoding(cur);
-
-    if (encoding != NULL) {
-	xmlCharEncoding enc;
-
-	enc = xmlParseCharEncoding(encoding);
-	if (enc != XML_CHAR_ENCODING_UTF8) {
-	    handler = xmlFindCharEncodingHandler(encoding);
-	    if (handler == NULL)
-		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
-	}
-    } else {
-        /*
-         * Fallback to HTML or ASCII when the encoding is unspecified
-         */
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("HTML");
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("ascii");
-    }
-
+    handler = htmlFindOutputEncoder(encoding);
     buf = xmlOutputBufferCreateFile(f, handler);
     if (buf == NULL) return(-1);
     htmlDocContentDumpOutput(buf, cur, NULL);
@@ -1089,29 +1054,7 @@
     xmlInitParser();
 
     encoding = (const char *) htmlGetMetaEncoding(cur);
-
-    if (encoding != NULL) {
-	xmlCharEncoding enc;
-
-	enc = xmlParseCharEncoding(encoding);
-	if (enc != XML_CHAR_ENCODING_UTF8) {
-	    handler = xmlFindCharEncodingHandler(encoding);
-	    if (handler == NULL)
-		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
-	}
-    } else {
-        /*
-         * Fallback to HTML or ASCII when the encoding is unspecified
-         */
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("HTML");
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("ascii");
-    }
-
-    /*
-     * save the content to a temp buffer.
-     */
+    handler = htmlFindOutputEncoder(encoding);
     buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
     if (buf == NULL) return(0);
 
@@ -1144,28 +1087,12 @@
 
     xmlInitParser();
 
-    if (encoding != NULL) {
-	xmlCharEncoding enc;
-
-	enc = xmlParseCharEncoding(encoding);
-	if (enc != XML_CHAR_ENCODING_UTF8) {
-	    handler = xmlFindCharEncodingHandler(encoding);
-	    if (handler == NULL)
-		htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
-	}
-        htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
-    } else {
+    handler = htmlFindOutputEncoder(encoding);
+    if (handler != NULL)
+        htmlSetMetaEncoding(cur, (const xmlChar *) handler->name);
+    else
 	htmlSetMetaEncoding(cur, (const xmlChar *) "UTF-8");
 
-        /*
-         * Fallback to HTML or ASCII when the encoding is unspecified
-         */
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("HTML");
-        if (handler == NULL)
-            handler = xmlFindCharEncodingHandler("ascii");
-    }
-
     /*
      * save the content to a temp buffer.
      */
diff --git a/src/Makefile.am b/src/Makefile.am
index a6f8166..441cf5f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -110,8 +110,8 @@
 libxml2_la_SOURCES += xlink.c xpointer.c
 endif
 
-DEPS = $(top_builddir)/libxml2.la
-LDADDS = $(top_builddir)/libxml2.la
+DEPS = libxml2.la
+LDADDS = libxml2.la
 
 
 m4datadir = $(datadir)/aclocal
@@ -183,10 +183,6 @@
 runxmlconf_DEPENDENCIES = $(DEPS)
 runxmlconf_LDADD= $(LDADDS)
 
-#testOOM_SOURCES=testOOM.c testOOMlib.h testOOMlib.c
-#testOOM_DEPENDENCIES = $(DEPS)
-#testOOM_LDADD= $(LDADDS)
-
 check-local:
 	[ -d test   ] || $(LN_S) $(srcdir)/test   .
 	[ -d result ] || $(LN_S) $(srcdir)/result .
diff --git a/src/NEWS b/src/NEWS
index 147f37b..6ebe8c5 100644
--- a/src/NEWS
+++ b/src/NEWS
@@ -1,5 +1,26 @@
 NEWS file for libxml2
 
+v2.13.0: not released yet
+
+### Major changes
+
+Most of the core code should now report malloc failures reliably.
+
+New API functions for error handling were added:
+
+- xmlCtxtSetErrorHandler
+- xmlXPathSetErrorHandler
+- xmlXIncludeSetErrorHandler
+
+This makes it possible to register per-context error handlers without
+resorting to global handlers.
+
+A few error messages were improved and consolidated. Please update
+downstream test suites accordingly.
+
+Support for HTTP POST was removed.
+
+
 v2.12.0: Nov 16 2023
 
 ### Major changes
diff --git a/src/SAX2.c b/src/SAX2.c
index ed21a55..f102bb6 100644
--- a/src/SAX2.c
+++ b/src/SAX2.c
@@ -31,52 +31,16 @@
 #include "private/parser.h"
 #include "private/tree.h"
 
-/**
- * TODO:
- *
- * macro to flag unimplemented blocks
- * XML_CATALOG_PREFER user env to select between system/public preferred
- * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk>
- *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with
- *> values "system" and "public".  I have made the default be "system" to
- *> match yours.
- */
-#define TODO								\
-    xmlGenericError(xmlGenericErrorContext,				\
-	    "Unimplemented block at %s:%d\n",				\
-            __FILE__, __LINE__);
+#define XML_MAX_URI_LENGTH 2000
 
 /*
  * xmlSAX2ErrMemory:
  * @ctxt:  an XML validation parser context
  * @msg:   a string to accompany the error message
  */
-static void LIBXML_ATTR_FORMAT(2,0)
-xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) {
-    xmlStructuredErrorFunc schannel = NULL;
-    const char *str1 = "out of memory\n";
-
-    if (ctxt != NULL) {
-	ctxt->errNo = XML_ERR_NO_MEMORY;
-	if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
-	    schannel = ctxt->sax->serror;
-	__xmlRaiseError(schannel,
-			ctxt->vctxt.error, ctxt->vctxt.userData,
-			ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY,
-			XML_ERR_ERROR, NULL, 0, (const char *) str1,
-			NULL, NULL, 0, 0,
-			msg, (const char *) str1, NULL);
-	ctxt->errNo = XML_ERR_NO_MEMORY;
-	ctxt->instate = XML_PARSER_EOF;
-	ctxt->disableSAX = 1;
-    } else {
-	__xmlRaiseError(schannel,
-			NULL, NULL,
-			ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY,
-			XML_ERR_ERROR, NULL, 0, (const char *) str1,
-			NULL, NULL, 0, 0,
-			msg, (const char *) str1, NULL);
-    }
+static void
+xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt) {
+    xmlCtxtErrMemory(ctxt);
 }
 
 /**
@@ -91,32 +55,12 @@
  */
 static void LIBXML_ATTR_FORMAT(3,0)
 xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error,
-            const char *msg, const char *str1, const char *str2)
+            const char *msg, const xmlChar *str1, const xmlChar *str2)
 {
-    xmlStructuredErrorFunc schannel = NULL;
-
-    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
-        (ctxt->instate == XML_PARSER_EOF))
-	return;
-    if (ctxt != NULL) {
-	ctxt->errNo = error;
-	if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC))
-	    schannel = ctxt->sax->serror;
-	__xmlRaiseError(schannel,
-			ctxt->vctxt.error, ctxt->vctxt.userData,
-			ctxt, NULL, XML_FROM_DTD, error,
-			XML_ERR_ERROR, NULL, 0, (const char *) str1,
-			(const char *) str2, NULL, 0, 0,
-			msg, (const char *) str1, (const char *) str2);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR,
+               str1, str2, NULL, 0, msg, str1, str2);
+    if (ctxt != NULL)
 	ctxt->valid = 0;
-    } else {
-	__xmlRaiseError(schannel,
-			NULL, NULL,
-			ctxt, NULL, XML_FROM_DTD, error,
-			XML_ERR_ERROR, NULL, 0, (const char *) str1,
-			(const char *) str2, NULL, 0, 0,
-			msg, (const char *) str1, (const char *) str2);
-    }
 }
 
 /**
@@ -133,21 +77,8 @@
 xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                const char *msg, const xmlChar *str1, const xmlChar *str2)
 {
-    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
-        (ctxt->instate == XML_PARSER_EOF))
-	return;
-    if (ctxt != NULL)
-	ctxt->errNo = error;
-    __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
-                    XML_ERR_FATAL, NULL, 0,
-		    (const char *) str1, (const char *) str2,
-		    NULL, 0, 0, msg, str1, str2);
-    if (ctxt != NULL) {
-	ctxt->wellFormed = 0;
-	ctxt->valid = 0;
-	if (ctxt->recovery == 0)
-	    ctxt->disableSAX = 1;
-    }
+    xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
+               str1, str2, NULL, 0, msg, str1, str2);
 }
 
 /**
@@ -164,15 +95,8 @@
 xmlWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                const char *msg, const xmlChar *str1)
 {
-    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
-        (ctxt->instate == XML_PARSER_EOF))
-	return;
-    if (ctxt != NULL)
-	ctxt->errNo = error;
-    __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,
-                    XML_ERR_WARNING, NULL, 0,
-		    (const char *) str1, NULL,
-		    NULL, 0, 0, msg, str1);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING,
+               str1, NULL, NULL, 0, msg, str1);
 }
 
 /**
@@ -188,15 +112,8 @@
 xmlNsWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
              const char *msg, const xmlChar *str1, const xmlChar *str2)
 {
-    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
-        (ctxt->instate == XML_PARSER_EOF))
-	return;
-    if (ctxt != NULL)
-	ctxt->errNo = error;
-    __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error,
-                    XML_ERR_WARNING, NULL, 0,
-		    (const char *) str1, (const char *) str2,
-		    NULL, 0, 0, msg, str1, str2);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_WARNING,
+               str1, str2, NULL, 0, msg, str1, str2);
 }
 
 /**
@@ -341,7 +258,7 @@
     ctxt->myDoc->intSubset =
 	xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
     if (ctxt->myDoc->intSubset == NULL)
-        xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset");
+        xmlSAX2ErrMemory(ctxt);
 }
 
 /**
@@ -359,8 +276,9 @@
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
     if (ctx == NULL) return;
-    if (((ExternalID != NULL) || (SystemID != NULL)) &&
-        (((ctxt->validate) || (ctxt->loadsubset != 0)) &&
+    if ((SystemID != NULL) &&
+        ((ctxt->options & XML_PARSE_NO_XXE) == 0) &&
+        (((ctxt->validate) || (ctxt->loadsubset)) &&
 	 (ctxt->wellFormed && ctxt->myDoc))) {
 	/*
 	 * Try to fetch and parse the external subset.
@@ -371,7 +289,6 @@
 	xmlParserInputPtr *oldinputTab;
 	xmlParserInputPtr input = NULL;
 	const xmlChar *oldencoding;
-	int oldprogressive;
         unsigned long consumed;
         size_t buffered;
 
@@ -385,7 +302,11 @@
 	    return;
 	}
 
-	xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
+	if (xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID) == NULL) {
+            xmlSAX2ErrMemory(ctxt);
+            xmlFreeInputStream(input);
+            return;
+        }
 
 	/*
 	 * make sure we won't destroy the main document context
@@ -395,21 +316,18 @@
 	oldinputMax = ctxt->inputMax;
 	oldinputTab = ctxt->inputTab;
 	oldencoding = ctxt->encoding;
-        oldprogressive = ctxt->progressive;
 	ctxt->encoding = NULL;
-        ctxt->progressive = 0;
 
 	ctxt->inputTab = (xmlParserInputPtr *)
 	                 xmlMalloc(5 * sizeof(xmlParserInputPtr));
 	if (ctxt->inputTab == NULL) {
-	    xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset");
+	    xmlSAX2ErrMemory(ctxt);
             xmlFreeInputStream(input);
 	    ctxt->input = oldinput;
 	    ctxt->inputNr = oldinputNr;
 	    ctxt->inputMax = oldinputMax;
 	    ctxt->inputTab = oldinputTab;
 	    ctxt->encoding = oldencoding;
-            ctxt->progressive = oldprogressive;
 	    return;
 	}
 	ctxt->inputNr = 0;
@@ -463,7 +381,6 @@
 	     (!xmlDictOwns(ctxt->dict, ctxt->encoding))))
 	    xmlFree((xmlChar *) ctxt->encoding);
 	ctxt->encoding = oldencoding;
-        ctxt->progressive = oldprogressive;
 	/* ctxt->wellFormed = oldwellFormed; */
     }
 }
@@ -486,22 +403,26 @@
 xmlSAX2ResolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
-    xmlParserInputPtr ret;
+    xmlParserInputPtr ret = NULL;
     xmlChar *URI;
     const char *base = NULL;
 
     if (ctx == NULL) return(NULL);
     if (ctxt->input != NULL)
 	base = ctxt->input->filename;
-    if (base == NULL)
-	base = ctxt->directory;
 
-    URI = xmlBuildURI(systemId, (const xmlChar *) base);
+    if (xmlBuildURISafe(systemId, (const xmlChar *) base, &URI) < 0) {
+        xmlSAX2ErrMemory(ctxt);
+        return(NULL);
+    }
+    if (xmlStrlen(URI) > XML_MAX_URI_LENGTH) {
+        xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, "URI too long");
+    } else {
+        ret = xmlLoadExternalEntity((const char *) URI,
+                                    (const char *) publicId, ctxt);
+    }
 
-    ret = xmlLoadExternalEntity((const char *) URI,
-				(const char *) publicId, ctxt);
-    if (URI != NULL)
-	xmlFree(URI);
+    xmlFree(URI);
     return(ret);
 }
 
@@ -590,50 +511,65 @@
 {
     xmlEntityPtr ent;
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    int extSubset;
+    int res;
 
-    if (ctx == NULL) return;
-    if (ctxt->inSubset == 1) {
-	ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
-		              systemId, content);
-	if ((ent == NULL) && (ctxt->pedantic))
-	    xmlWarnMsg(ctxt, XML_WAR_ENTITY_REDEFINED,
-	     "Entity(%s) already defined in the internal subset\n",
-	               name);
-	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
-	    xmlChar *URI;
-	    const char *base = NULL;
+    if ((ctxt == NULL) || (ctxt->myDoc == NULL))
+        return;
 
-	    if (ctxt->input != NULL)
-		base = ctxt->input->filename;
-	    if (base == NULL)
-		base = ctxt->directory;
+    extSubset = ctxt->inSubset == 2;
+    res = xmlAddEntity(ctxt->myDoc, extSubset, name, type, publicId, systemId,
+                       content, &ent);
+    switch (res) {
+        case XML_ERR_OK:
+            break;
+        case XML_ERR_NO_MEMORY:
+            xmlSAX2ErrMemory(ctxt);
+            return;
+        case XML_WAR_ENTITY_REDEFINED:
+            if (ctxt->pedantic) {
+                if (extSubset)
+                    xmlWarnMsg(ctxt, res, "Entity(%s) already defined in the"
+                               " external subset\n", name);
+                else
+                    xmlWarnMsg(ctxt, res, "Entity(%s) already defined in the"
+                               " internal subset\n", name);
+            }
+            return;
+        case XML_ERR_REDECL_PREDEF_ENTITY:
+            /*
+             * Technically an error but it's a common mistake to get double
+             * escaping according to "4.6 Predefined Entities" wrong.
+             */
+            xmlWarnMsg(ctxt, res, "Invalid redeclaration of predefined"
+                       " entity '%s'", name);
+            return;
+        default:
+            xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
+                           "Unexpected error code from xmlAddEntity\n",
+                           NULL, NULL);
+            return;
+    }
 
-	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
-	    ent->URI = URI;
-	}
-    } else if (ctxt->inSubset == 2) {
-	ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
-		              systemId, content);
-	if ((ent == NULL) && (ctxt->pedantic) &&
-	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
-	    ctxt->sax->warning(ctxt->userData,
-	     "Entity(%s) already defined in the external subset\n", name);
-	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
-	    xmlChar *URI;
-	    const char *base = NULL;
+    if ((ent->URI == NULL) && (systemId != NULL)) {
+        xmlChar *URI;
+        const char *base = NULL;
 
-	    if (ctxt->input != NULL)
-		base = ctxt->input->filename;
-	    if (base == NULL)
-		base = ctxt->directory;
+        if (ctxt->input != NULL)
+            base = ctxt->input->filename;
 
-	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
-	    ent->URI = URI;
-	}
-    } else {
-	xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_PROCESSING,
-	               "SAX.xmlSAX2EntityDecl(%s) called while not in subset\n",
-		       name, NULL);
+        if (base != NULL) {
+            if (xmlBuildURISafe(systemId, (const xmlChar *) base, &URI) < 0) {
+                xmlSAX2ErrMemory(ctxt);
+                return;
+            }
+            if (xmlStrlen(URI) > XML_MAX_URI_LENGTH) {
+                xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, "URI too long");
+                xmlFree(URI);
+            } else {
+                ent->URI = URI;
+            }
+        }
     }
 }
 
@@ -676,6 +612,8 @@
     }
     /* TODO: optimize name/prefix allocation */
     name = xmlSplitQName(ctxt, fullname, &prefix);
+    if (name == NULL)
+        xmlSAX2ErrMemory(ctxt);
     ctxt->vctxt.valid = 1;
     if (ctxt->inSubset == 1)
 	attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
@@ -690,6 +628,7 @@
 	     "SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n",
 	               name, NULL);
 	xmlFree(name);
+	xmlFree(prefix);
 	xmlFreeEnumeration(tree);
 	return;
     }
@@ -814,54 +753,8 @@
 		   const xmlChar *publicId, const xmlChar *systemId,
 		   const xmlChar *notationName)
 {
-    xmlEntityPtr ent;
-    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
-    if (ctx == NULL) return;
-    if (ctxt->inSubset == 1) {
-	ent = xmlAddDocEntity(ctxt->myDoc, name,
-			XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
-			publicId, systemId, notationName);
-	if ((ent == NULL) && (ctxt->pedantic) &&
-	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
-	    ctxt->sax->warning(ctxt->userData,
-	     "Entity(%s) already defined in the internal subset\n", name);
-	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
-	    xmlChar *URI;
-	    const char *base = NULL;
-
-	    if (ctxt->input != NULL)
-		base = ctxt->input->filename;
-	    if (base == NULL)
-		base = ctxt->directory;
-
-	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
-	    ent->URI = URI;
-	}
-    } else if (ctxt->inSubset == 2) {
-	ent = xmlAddDtdEntity(ctxt->myDoc, name,
-			XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
-			publicId, systemId, notationName);
-	if ((ent == NULL) && (ctxt->pedantic) &&
-	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
-	    ctxt->sax->warning(ctxt->userData,
-	     "Entity(%s) already defined in the external subset\n", name);
-	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
-	    xmlChar *URI;
-	    const char *base = NULL;
-
-	    if (ctxt->input != NULL)
-		base = ctxt->input->filename;
-	    if (base == NULL)
-		base = ctxt->directory;
-
-	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
-	    ent->URI = URI;
-	}
-    } else {
-        xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
-	     "SAX.xmlSAX2UnparsedEntityDecl(%s) called while not in subset\n",
-	               name, NULL);
-    }
+    xmlSAX2EntityDecl(ctx, name, XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
+                      publicId, systemId, (xmlChar *) notationName);
 }
 
 /**
@@ -891,25 +784,19 @@
 
     if (ctx == NULL) return;
 
-    if (ctxt->html) {
 #ifdef LIBXML_HTML_ENABLED
+    if (ctxt->html) {
 	if (ctxt->myDoc == NULL)
 	    ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
 	if (ctxt->myDoc == NULL) {
-	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
+	    xmlSAX2ErrMemory(ctxt);
 	    return;
 	}
 	ctxt->myDoc->properties = XML_DOC_HTML;
 	ctxt->myDoc->parseFlags = ctxt->options;
-#else
-        xmlGenericError(xmlGenericErrorContext,
-		"libxml2 built without HTML support\n");
-	ctxt->errNo = XML_ERR_INTERNAL_ERROR;
-	ctxt->instate = XML_PARSER_EOF;
-	ctxt->disableSAX = 1;
-	return;
+    } else
 #endif
-    } else {
+    {
 	doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
 	if (doc != NULL) {
 	    doc->properties = 0;
@@ -918,19 +805,23 @@
 	    doc->parseFlags = ctxt->options;
 	    doc->standalone = ctxt->standalone;
 	} else {
-	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
+	    xmlSAX2ErrMemory(ctxt);
 	    return;
 	}
 	if ((ctxt->dictNames) && (doc != NULL)) {
 	    doc->dict = ctxt->dict;
 	    xmlDictReference(doc->dict);
 	}
+        if (xmlTreeEnsureXMLDecl(doc) == NULL) {
+            xmlSAX2ErrMemory(ctxt);
+            return;
+        }
     }
     if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
 	(ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
 	ctxt->myDoc->URL = xmlPathToURI((const xmlChar *)ctxt->input->filename);
 	if (ctxt->myDoc->URL == NULL)
-	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument");
+	    xmlSAX2ErrMemory(ctxt);
     }
 }
 
@@ -970,7 +861,7 @@
         if (encoding != NULL) {
             doc->encoding = xmlStrdup(encoding);
             if (doc->encoding == NULL)
-                xmlSAX2ErrMemory(ctxt, "xmlSAX2EndDocument");
+                xmlSAX2ErrMemory(ctxt);
         }
     }
 }
@@ -990,15 +881,8 @@
 xmlNsErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
             const char *msg, const xmlChar *str1, const xmlChar *str2)
 {
-    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
-        (ctxt->instate == XML_PARSER_EOF))
-	return;
-    if (ctxt != NULL)
-	ctxt->errNo = error;
-    __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error,
-                    XML_ERR_ERROR, NULL, 0,
-		    (const char *) str1, (const char *) str2,
-		    NULL, 0, 0, msg, str1, str2);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_ERROR,
+               str1, str2, NULL, 0, msg, str1, str2);
 }
 
 /**
@@ -1051,7 +935,7 @@
 	}
     }
     if (name == NULL) {
-        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
+        xmlSAX2ErrMemory(ctxt);
 	if (ns != NULL)
 	    xmlFree(ns);
 	return;
@@ -1061,6 +945,8 @@
     if ((ctxt->html) &&
         (value == NULL) && (htmlIsBooleanAttr(fullname))) {
             nval = xmlStrdup(fullname);
+            if (nval == NULL)
+                xmlSAX2ErrMemory(ctxt);
             value = (const xmlChar *) nval;
     } else
 #endif
@@ -1098,12 +984,10 @@
         (void) nsret;
 
         if (!ctxt->replaceEntities) {
-	    ctxt->depth++;
-	    val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
-		                          0,0,0);
-	    ctxt->depth--;
+            /* TODO: normalize if needed */
+	    val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0);
 	    if (val == NULL) {
-	        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
+	        xmlSAX2ErrMemory(ctxt);
 		if (name != NULL)
 		    xmlFree(name);
                 if (nval != NULL)
@@ -1117,16 +1001,16 @@
 	if (val[0] != 0) {
 	    xmlURIPtr uri;
 
-	    uri = xmlParseURI((const char *)val);
+	    if (xmlParseURISafe((const char *)val, &uri) < 0)
+                xmlSAX2ErrMemory(ctxt);
 	    if (uri == NULL) {
-		if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
-		    ctxt->sax->warning(ctxt->userData,
-			 "xmlns: %s not a valid URI\n", val);
+                xmlNsWarnMsg(ctxt, XML_WAR_NS_URI,
+                             "xmlns:%s: %s not a valid URI\n", name, value);
 	    } else {
 		if (uri->scheme == NULL) {
-		    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
-			ctxt->sax->warning(ctxt->userData,
-			     "xmlns: URI %s is not absolute\n", val);
+                    xmlNsWarnMsg(ctxt, XML_WAR_NS_URI_RELATIVE,
+                                 "xmlns:%s: URI %s is not absolute\n",
+                                 name, value);
 		}
 		xmlFreeURI(uri);
 	    }
@@ -1134,16 +1018,19 @@
 
 	/* a default namespace definition */
 	nsret = xmlNewNs(ctxt->node, val, NULL);
-
+        if (nsret == NULL) {
+            xmlSAX2ErrMemory(ctxt);
+        }
 #ifdef LIBXML_VALID_ENABLED
 	/*
 	 * Validate also for namespace decls, they are attributes from
 	 * an XML-1.0 perspective
 	 */
-        if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
-	    ctxt->myDoc && ctxt->myDoc->intSubset)
+        else if (ctxt->validate && ctxt->wellFormed &&
+                 ctxt->myDoc && ctxt->myDoc->intSubset) {
 	    ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
 					   ctxt->node, prefix, nsret, val);
+        }
 #endif /* LIBXML_VALID_ENABLED */
 	if (name != NULL)
 	    xmlFree(name);
@@ -1163,12 +1050,10 @@
         (void) nsret;
 
         if (!ctxt->replaceEntities) {
-	    ctxt->depth++;
-	    val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
-		                          0,0,0);
-	    ctxt->depth--;
+            /* TODO: normalize if needed */
+	    val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0);
 	    if (val == NULL) {
-	        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
+	        xmlSAX2ErrMemory(ctxt);
 	        xmlFree(ns);
 		if (name != NULL)
 		    xmlFree(name);
@@ -1187,7 +1072,8 @@
 	if ((ctxt->pedantic != 0) && (val[0] != 0)) {
 	    xmlURIPtr uri;
 
-	    uri = xmlParseURI((const char *)val);
+	    if (xmlParseURISafe((const char *)val, &uri) < 0)
+                xmlSAX2ErrMemory(ctxt);
 	    if (uri == NULL) {
 	        xmlNsWarnMsg(ctxt, XML_WAR_NS_URI,
 			 "xmlns:%s: %s not a valid URI\n", name, value);
@@ -1203,15 +1089,20 @@
 	/* a standard namespace definition */
 	nsret = xmlNewNs(ctxt->node, val, name);
 	xmlFree(ns);
+
+        if (nsret == NULL) {
+            xmlSAX2ErrMemory(ctxt);
+        }
 #ifdef LIBXML_VALID_ENABLED
 	/*
 	 * Validate also for namespace decls, they are attributes from
 	 * an XML-1.0 perspective
 	 */
-        if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
-	    ctxt->myDoc && ctxt->myDoc->intSubset)
+        else if (ctxt->validate && ctxt->wellFormed &&
+	         ctxt->myDoc && ctxt->myDoc->intSubset) {
 	    ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
 					   ctxt->node, prefix, nsret, value);
+        }
 #endif /* LIBXML_VALID_ENABLED */
 	if (name != NULL)
 	    xmlFree(name);
@@ -1238,11 +1129,11 @@
                     if ((xmlStrEqual(name, prop->name)) &&
                         ((namespace == prop->ns) ||
                          (xmlStrEqual(namespace->href, prop->ns->href)))) {
-                            xmlNsErrMsg(ctxt, XML_ERR_ATTRIBUTE_REDEFINED,
-                                    "Attribute %s in %s redefined\n",
-                                             name, namespace->href);
-                        ctxt->wellFormed = 0;
-                        if (ctxt->recovery == 0) ctxt->disableSAX = 1;
+                        xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER,
+                                   XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL,
+                                   name, NULL, NULL, 0,
+                                   "Attribute %s in %s redefined\n",
+                                   name, namespace->href);
                         if (name != NULL)
                             xmlFree(name);
                         goto error;
@@ -1257,13 +1148,19 @@
 
     /* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */
     ret = xmlNewNsPropEatName(ctxt->node, namespace, name, NULL);
-    if (ret == NULL)
+    if (ret == NULL) {
+        xmlSAX2ErrMemory(ctxt);
         goto error;
+    }
 
     if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
         xmlNodePtr tmp;
 
-        ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
+        if ((value != NULL) && (value[0] != 0)) {
+            ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
+            if (ret->children == NULL)
+                xmlSAX2ErrMemory(ctxt);
+        }
         tmp = ret->children;
         while (tmp != NULL) {
             tmp->parent = (xmlNodePtr) ret;
@@ -1273,9 +1170,12 @@
         }
     } else if (value != NULL) {
         ret->children = xmlNewDocText(ctxt->myDoc, value);
-        ret->last = ret->children;
-        if (ret->children != NULL)
+        if (ret->children == NULL) {
+            xmlSAX2ErrMemory(ctxt);
+        } else {
+            ret->last = ret->children;
             ret->children->parent = (xmlNodePtr) ret;
+        }
     }
 
 #ifdef LIBXML_VALID_ENABLED
@@ -1289,10 +1189,8 @@
         if (!ctxt->replaceEntities) {
 	    xmlChar *val;
 
-	    ctxt->depth++;
-	    val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
-		                          0,0,0);
-	    ctxt->depth--;
+            /* TODO: normalize if needed */
+	    val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0);
 
 	    if (val == NULL)
 		ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
@@ -1305,8 +1203,9 @@
 		 * It need to be done twice ... it's an extra burden related
 		 * to the ability to keep xmlSAX2References in attributes
 		 */
-		nvalnorm = xmlValidNormalizeAttributeValue(ctxt->myDoc,
-					    ctxt->node, fullname, val);
+                nvalnorm = xmlValidCtxtNormalizeAttributeValue(
+                                 &ctxt->vctxt, ctxt->myDoc,
+                                 ctxt->node, fullname, val);
 		if (nvalnorm != NULL) {
 		    xmlFree(val);
 		    val = nvalnorm;
@@ -1323,8 +1222,6 @@
     } else
 #endif /* LIBXML_VALID_ENABLED */
            if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) &&
-	       (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
-	        ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) &&
                /* Don't create IDs containing entity references */
                (ret->children != NULL) &&
                (ret->children->type == XML_TEXT_NODE) &&
@@ -1342,14 +1239,20 @@
 	     */
 	    if (xmlValidateNCName(content, 1) != 0) {
 	        xmlErrValid(ctxt, XML_DTD_XMLID_VALUE,
-		      "xml:id : attribute value %s is not an NCName\n",
-			    (const char *) content, NULL);
+		            "xml:id : attribute value %s is not an NCName\n",
+		            content, NULL);
 	    }
 	    xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
-	} else if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
-	    xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
-	else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
-	    xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret);
+	} else {
+            int res = xmlIsID(ctxt->myDoc, ctxt->node, ret);
+
+            if (res < 0)
+                xmlCtxtErrMemory(ctxt);
+            else if (res > 0)
+                xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
+            else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
+                xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret);
+        }
     }
 
 error:
@@ -1407,7 +1310,7 @@
 			fulln = xmlStrdup(attr->name);
 		    }
                     if (fulln == NULL) {
-                        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
+                        xmlSAX2ErrMemory(ctxt);
                         break;
                     }
 
@@ -1429,8 +1332,8 @@
 		    if (att == NULL) {
 		        xmlErrValid(ctxt, XML_DTD_STANDALONE_DEFAULTED,
       "standalone: attribute %s on %s defaulted from external subset\n",
-				    (const char *)fulln,
-				    (const char *)attr->elem);
+				    fulln,
+				    attr->elem);
 		    }
                     xmlFree(fulln);
 		}
@@ -1473,7 +1376,7 @@
 
                         fulln = xmlBuildQName(attr->name, attr->prefix, fn, 50);
 			if (fulln == NULL) {
-			    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
+			    xmlSAX2ErrMemory(ctxt);
 			    return;
 			}
 
@@ -1557,6 +1460,10 @@
          * Split the full name into a namespace prefix and the tag name
          */
         name = xmlSplitQName(ctxt, fullname, &prefix);
+        if (name == NULL) {
+            xmlSAX2ErrMemory(ctxt);
+            return;
+        }
     }
 
     /*
@@ -1566,9 +1473,8 @@
      */
     ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, name, NULL);
     if (ret == NULL) {
-        if (prefix != NULL)
-	    xmlFree(prefix);
-	xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement");
+	xmlFree(prefix);
+	xmlSAX2ErrMemory(ctxt);
         return;
     }
     ctxt->nodemem = -1;
@@ -1637,10 +1543,12 @@
         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);
+            ns = xmlNewNs(ret, NULL, prefix);
+            if (ns == NULL)
+                xmlSAX2ErrMemory(ctxt);
         }
 
         /*
@@ -1761,7 +1669,7 @@
 	ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
     }
     if (ret == NULL) {
-        xmlErrMemory(ctxt, "xmlSAX2Characters");
+        xmlCtxtErrMemory(ctxt);
 	return(NULL);
     }
     memset(ret, 0, sizeof(xmlNode));
@@ -1782,6 +1690,11 @@
 	} else if ((len <= 3) && ((cur == '"') || (cur == '\'') ||
 	    ((cur == '<') && (str[len + 1] != '!')))) {
 	    intern = xmlDictLookup(ctxt->dict, str, len);
+            if (intern == NULL) {
+                xmlSAX2ErrMemory(ctxt);
+                xmlFree(ret);
+                return(NULL);
+            }
 	} else if (IS_BLANK_CH(*str) && (len < 60) && (cur == '<') &&
 	           (str[len + 1] != '!')) {
 	    int i;
@@ -1790,6 +1703,11 @@
 		if (!IS_BLANK_CH(str[i])) goto skip;
 	    }
 	    intern = xmlDictLookup(ctxt->dict, str, len);
+            if (intern == NULL) {
+                xmlSAX2ErrMemory(ctxt);
+                xmlFree(ret);
+                return(NULL);
+            }
 	}
     }
 skip:
@@ -1799,7 +1717,7 @@
     if (intern == NULL) {
 	ret->content = xmlStrndup(str, len);
 	if (ret->content == NULL) {
-	    xmlSAX2ErrMemory(ctxt, "xmlSAX2TextNode");
+	    xmlSAX2ErrMemory(ctxt);
 	    xmlFree(ret);
 	    return(NULL);
 	}
@@ -1826,7 +1744,6 @@
 xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str,
                           const xmlChar *end) {
     const xmlChar *in;
-    xmlChar *ret;
 
     in = str;
     while (in < end)
@@ -1834,11 +1751,12 @@
 	    goto decode;
     return(NULL);
 decode:
-    ctxt->depth++;
-    ret = xmlStringLenDecodeEntities(ctxt, str, end - str,
-				     XML_SUBSTITUTE_REF, 0,0,0);
-    ctxt->depth--;
-    return(ret);
+    /*
+     * If the value contains '&', we can be sure it was allocated and is
+     * zero-terminated.
+     */
+    /* TODO: normalize if needed */
+    return(xmlExpandEntitiesInAttValue(ctxt, str, /* normalize */ 0));
 }
 #endif /* LIBXML_VALID_ENABLED */
 
@@ -1889,7 +1807,7 @@
     } else {
         ret = xmlMalloc(sizeof(*ret));
         if (ret == NULL) {
-            xmlSAX2ErrMemory(ctxt, NULL);
+            xmlSAX2ErrMemory(ctxt);
             return(NULL);
         }
     }
@@ -1910,10 +1828,13 @@
     ret->doc = ctxt->node->doc;
     ret->ns = namespace;
 
-    if (ctxt->dictNames)
+    if (ctxt->dictNames) {
         ret->name = localname;
-    else
+    } else {
         ret->name = xmlStrdup(localname);
+        if (ret->name == NULL)
+            xmlSAX2ErrMemory(ctxt);
+    }
 
     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
         xmlRegisterNodeDefaultValue((xmlNodePtr)ret);
@@ -1934,9 +1855,11 @@
 		tmp->doc = ret->doc;
 		tmp->parent = (xmlNodePtr) ret;
 	    }
-	} else {
+	} else if (valueend > value) {
 	    ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value,
 						    valueend - value);
+            if (ret->children == NULL)
+                xmlSAX2ErrMemory(ctxt);
 	    tmp = ret->children;
 	    while (tmp != NULL) {
 	        tmp->doc = ret->doc;
@@ -1978,6 +1901,8 @@
 		     * entry points in the full validation code
 		     */
 		    dup = xmlStrndup(value, valueend - value);
+                    if (dup == NULL)
+                        xmlSAX2ErrMemory(ctxt);
 
 		    ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
 				    ctxt->myDoc, ctxt->node, ret, dup);
@@ -2022,6 +1947,8 @@
 	     * the attribute as passed is already normalized
 	     */
 	    dup = xmlStrndup(value, valueend - value);
+            if (dup == NULL)
+                xmlSAX2ErrMemory(ctxt);
 
 	    ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
 	                             ctxt->myDoc, ctxt->node, ret, dup);
@@ -2029,8 +1956,6 @@
     } else
 #endif /* LIBXML_VALID_ENABLED */
            if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) &&
-	       (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) ||
-	        ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) &&
                /* Don't create IDs containing entity references */
                (ret->children != NULL) &&
                (ret->children->type == XML_TEXT_NODE) &&
@@ -2050,14 +1975,19 @@
 	     */
 	    if (xmlValidateNCName(content, 1) != 0) {
 	        xmlErrValid(ctxt, XML_DTD_XMLID_VALUE,
-		      "xml:id : attribute value %s is not an NCName\n",
-			    (const char *) content, NULL);
+                            "xml:id : attribute value %s is not an NCName\n",
+                            content, NULL);
 	    }
 	    xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
-	} else if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) {
-	    xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
-	} else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) {
-	    xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret);
+	} else {
+            int res = xmlIsID(ctxt->myDoc, ctxt->node, ret);
+
+            if (res < 0)
+                xmlCtxtErrMemory(ctxt);
+            else if (res > 0)
+                xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret);
+            else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
+                xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret);
 	}
     }
     if (dup != NULL)
@@ -2125,10 +2055,17 @@
 	    const xmlChar *fullname;
 
 	    fullname = xmlDictQLookup(ctxt->dict, prefix, localname);
-	    if (fullname != NULL)
-	        localname = fullname;
+	    if (fullname == NULL) {
+                xmlSAX2ErrMemory(ctxt);
+                return;
+            }
+	    localname = fullname;
 	} else {
 	    lname = xmlBuildQName(localname, prefix, NULL, 0);
+            if (lname == NULL) {
+                xmlSAX2ErrMemory(ctxt);
+                return;
+            }
 	}
     }
     /*
@@ -2150,7 +2087,7 @@
 	    else
 	        ret->name = lname;
 	    if (ret->name == NULL) {
-	        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
+	        xmlSAX2ErrMemory(ctxt);
                 xmlFree(ret);
 		return;
 	    }
@@ -2167,7 +2104,7 @@
 	    ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL,
 	                               (xmlChar *) lname, NULL);
 	if (ret == NULL) {
-	    xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
+	    xmlSAX2ErrMemory(ctxt);
 	    return;
 	}
     }
@@ -2197,11 +2134,7 @@
 	    if ((URI != NULL) && (prefix == pref))
 		ret->ns = ns;
 	} else {
-            /*
-             * any out of memory error would already have been raised
-             * but we can't be guaranteed it's the actual error due to the
-             * API, best is to skip in this case
-             */
+            xmlSAX2ErrMemory(ctxt);
 	    continue;
 	}
 
@@ -2256,7 +2189,7 @@
 	    ns = xmlNewNs(ret, NULL, prefix);
 	    if (ns == NULL) {
 
-	        xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs");
+	        xmlSAX2ErrMemory(ctxt);
 		return;
 	    }
             if (prefix != NULL)
@@ -2288,22 +2221,26 @@
 
 		    fullname = xmlDictQLookup(ctxt->dict, attributes[j+1],
 		                              attributes[j]);
-		    if (fullname != NULL) {
-                        attr = xmlSAX2AttributeNs(ctxt, fullname, NULL,
-                                                  attributes[j+3],
-                                                  attributes[j+4]);
-                        goto have_attr;
-		    }
+		    if (fullname == NULL) {
+                        xmlSAX2ErrMemory(ctxt);
+                        return;
+                    }
+                    attr = xmlSAX2AttributeNs(ctxt, fullname, NULL,
+                                              attributes[j+3],
+                                              attributes[j+4]);
+                    goto have_attr;
 		} else {
 		    lname = xmlBuildQName(attributes[j], attributes[j+1],
 		                          NULL, 0);
-		    if (lname != NULL) {
-                        attr = xmlSAX2AttributeNs(ctxt, lname, NULL,
-                                                  attributes[j+3],
-                                                  attributes[j+4]);
-			xmlFree(lname);
-                        goto have_attr;
-		    }
+		    if (lname == NULL) {
+                        xmlSAX2ErrMemory(ctxt);
+                        return;
+                    }
+                    attr = xmlSAX2AttributeNs(ctxt, lname, NULL,
+                                              attributes[j+3],
+                                              attributes[j+4]);
+                    xmlFree(lname);
+                    goto have_attr;
 		}
 	    }
             attr = xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1],
@@ -2393,6 +2330,10 @@
 
     if (ctx == NULL) return;
     ret = xmlNewReference(ctxt->myDoc, name);
+    if (ret == NULL) {
+        xmlSAX2ErrMemory(ctxt);
+        return;
+    }
     if (xmlAddChild(ctxt->node, ret) == NULL) {
         xmlFreeNode(ret);
     }
@@ -2442,7 +2383,7 @@
 	    ctxt->nodelen = len;
 	    ctxt->nodemem = len + 1;
 	} else {
-	    xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters");
+	    xmlSAX2ErrMemory(ctxt);
 	    return;
 	}
     } else {
@@ -2451,6 +2392,10 @@
 	    ((type != XML_TEXT_NODE) ||
              (lastChild->name == xmlStringText));
 	if ((coalesceText) && (ctxt->nodemem != 0)) {
+            int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+                            XML_MAX_HUGE_LENGTH :
+                            XML_MAX_TEXT_LENGTH;
+
 	    /*
 	     * The whole point of maintaining nodelen and nodemem,
 	     * xmlTextConcat is too costly, i.e. compute length,
@@ -2466,16 +2411,13 @@
 		lastChild->content = xmlStrdup(lastChild->content);
 	    }
 	    if (lastChild->content == NULL) {
-		xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: xmlStrdup returned NULL");
+		xmlSAX2ErrMemory(ctxt);
 		return;
  	    }
-	    if (ctxt->nodelen > INT_MAX - len) {
-                xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters overflow prevented");
-                return;
-	    }
-            if ((ctxt->nodelen + len > XML_MAX_TEXT_LENGTH) &&
-                ((ctxt->options & XML_PARSE_HUGE) == 0)) {
-                xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: huge text node");
+            if ((len > maxLength) || (ctxt->nodelen > maxLength - len)) {
+                xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT,
+                            "Text node too long, try XML_PARSE_HUGE");
+                xmlHaltParser(ctxt);
                 return;
             }
 	    if (ctxt->nodelen + len >= ctxt->nodemem) {
@@ -2488,7 +2430,7 @@
 		size = size > INT_MAX / 2 ? INT_MAX : size * 2;
                 newbuf = (xmlChar *) xmlRealloc(lastChild->content,size);
 		if (newbuf == NULL) {
-		    xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters");
+		    xmlSAX2ErrMemory(ctxt);
 		    return;
 		}
 		ctxt->nodemem = size;
@@ -2499,7 +2441,7 @@
 	    lastChild->content[ctxt->nodelen] = 0;
 	} else if (coalesceText) {
 	    if (xmlTextConcat(lastChild, ch, len)) {
-		xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters");
+		xmlSAX2ErrMemory(ctxt);
 	    }
 	    if (ctxt->node->children != NULL) {
 		ctxt->nodelen = xmlStrlen(lastChild->content);
@@ -2513,7 +2455,9 @@
                     lastChild->doc = ctxt->myDoc;
             } else
                 lastChild = xmlNewCDataBlock(ctxt->myDoc, ch, len);
-	    if (lastChild != NULL) {
+	    if (lastChild == NULL) {
+                xmlSAX2ErrMemory(ctxt);
+            } else {
 		xmlAddChild(ctxt->node, lastChild);
 		if (ctxt->node->children != NULL) {
 		    ctxt->nodelen = len;
@@ -2585,7 +2529,10 @@
     parent = ctxt->node;
 
     ret = xmlNewDocPI(ctxt->myDoc, target, data);
-    if (ret == NULL) return;
+    if (ret == NULL) {
+        xmlSAX2ErrMemory(ctxt);
+        return;
+    }
 
     if (ctxt->linenumbers) {
 	if (ctxt->input != NULL) {
@@ -2630,7 +2577,10 @@
     if (ctx == NULL) return;
     parent = ctxt->node;
     ret = xmlNewDocComment(ctxt->myDoc, value);
-    if (ret == NULL) return;
+    if (ret == NULL) {
+        xmlSAX2ErrMemory(ctxt);
+        return;
+    }
     if (ctxt->linenumbers) {
 	if (ctxt->input != NULL) {
 	    if ((unsigned) ctxt->input->line < (unsigned) USHRT_MAX)
diff --git a/src/buf.c b/src/buf.c
index ac412ad..7e860f7 100644
--- a/src/buf.c
+++ b/src/buf.c
@@ -972,32 +972,6 @@
 }
 
 /**
- * xmlBufMergeBuffer:
- * @buf: an xmlBufPtr
- * @buffer: the buffer to consume into @buf
- *
- * The content of @buffer is appended to @buf and @buffer is freed
- *
- * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
- */
-int
-xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
-    int ret = 0;
-
-    if ((buf == NULL) || (buf->error)) {
-	xmlBufferFree(buffer);
-        return(-1);
-    }
-    CHECK_COMPAT(buf)
-    if ((buffer != NULL) && (buffer->content != NULL) &&
-             (buffer->use > 0)) {
-        ret = xmlBufAdd(buf, buffer->content, buffer->use);
-    }
-    xmlBufferFree(buffer);
-    return(ret);
-}
-
-/**
  * xmlBufResetInput:
  * @buf: an xmlBufPtr
  * @input: an xmlParserInputPtr
@@ -1008,16 +982,7 @@
  */
 int
 xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
-    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 = input->cur = buf->content;
-    input->end = &buf->content[buf->use];
-    return(0);
+    return(xmlBufUpdateInput(buf, input, 0));
 }
 
 /**
@@ -1033,16 +998,8 @@
  */
 int
 xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) {
-    if (input == NULL)
+    if ((buf == NULL) || (input == NULL))
         return(-1);
-    /*
-     * TODO: It might be safer to keep using the buffer content if there
-     * was an error.
-     */
-    if ((buf == NULL) || (buf->error)) {
-        input->base = input->cur = input->end = BAD_CAST "";
-        return(-1);
-    }
     CHECK_COMPAT(buf)
     input->base = buf->content;
     input->cur = input->base + pos;
diff --git a/src/config.h.cmake.in b/src/config.h.cmake.in
index 461e53a..2c1f911 100644
--- a/src/config.h.cmake.in
+++ b/src/config.h.cmake.in
@@ -22,6 +22,9 @@
 /* Define to 1 if you have the `ftime' function. */
 #cmakedefine HAVE_FTIME 1
 
+/* Define to 1 if you have the `getentropy' function. */
+#cmakedefine HAVE_GETENTROPY 1
+
 /* Define to 1 if you have the `gettimeofday' function. */
 #cmakedefine HAVE_GETTIMEOFDAY 1
 
@@ -72,6 +75,9 @@
 /* Define to 1 if you have the <sys/mman.h> header file. */
 #cmakedefine HAVE_SYS_MMAN_H 1
 
+/* Define to 1 if you have the <sys/random.h> header file. */
+#cmakedefine HAVE_SYS_RANDOM_H 1
+
 /* Define to 1 if you have the <sys/select.h> header file. */
 #cmakedefine HAVE_SYS_SELECT_H 1
 
diff --git a/src/config.h.in b/src/config.h.in
index 41f3812..f07ca83 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -24,6 +24,9 @@
 /* Define to 1 if you have the `ftime' function. */
 #undef HAVE_FTIME
 
+/* Define to 1 if you have the `getentropy' function. */
+#undef HAVE_GETENTROPY
+
 /* Define to 1 if you have the `gettimeofday' function. */
 #undef HAVE_GETTIMEOFDAY
 
@@ -92,6 +95,9 @@
 /* Define to 1 if you have the <sys/mman.h> header file. */
 #undef HAVE_SYS_MMAN_H
 
+/* Define to 1 if you have the <sys/random.h> header file. */
+#undef HAVE_SYS_RANDOM_H
+
 /* Define to 1 if you have the <sys/select.h> header file. */
 #undef HAVE_SYS_SELECT_H
 
diff --git a/src/configure.ac b/src/configure.ac
index 2326f9f..4529af1 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -21,7 +21,7 @@
 LIBXML_VERSION_NUMBER=`expr $LIBXML_MAJOR_VERSION \* 10000 + $LIBXML_MINOR_VERSION \* 100 + $LIBXML_MICRO_VERSION`
 
 if test -d .git ; then
-  extra=`git describe 2>/dev/null | sed 's+LIBXML[[0-9.]]*-++'`
+  extra=`git describe 2>/dev/null`
   echo extra=$extra
   if test "$extra" != ""
   then
@@ -103,8 +103,6 @@
 [  --with-reader           xmlReader parsing interface (on)])
 AC_ARG_WITH(regexps,
 [  --with-regexps          regular expressions support (on)])
-AC_ARG_WITH(run_debug,
-[  --with-run-debug        runtime debugging module (off)])
 AC_ARG_WITH(sax1,
 [  --with-sax1             older SAX1 interface (on)])
 AC_ARG_WITH(schemas,
@@ -127,6 +125,8 @@
 [  --with-xpath            XPath 1.0 support (on)])
 AC_ARG_WITH(xptr,
 [  --with-xptr             XPointer support (on)])
+AC_ARG_WITH(xptr-locs,
+[  --with-xptr-locs        XPointer ranges and points (off)])
 AC_ARG_WITH(zlib,
 [  --with-zlib[[=DIR]]       use libz in DIR (on)])
 
@@ -241,7 +241,6 @@
     test "$with_reader" = "" && with_reader=no
     test "$with_readline" = "" && with_readline=no
     test "$with_regexps" = "" && with_regexps=no
-    test "$with_run_debug" = "" && with_run_debug=no
     test "$with_sax1" = "" && with_sax1=no
     test "$with_schemas" = "" && with_schemas=no
     test "$with_schematron" = "" && with_schematron=no
@@ -300,6 +299,7 @@
 AC_CHECK_HEADERS([sys/socket.h netinet/in.h arpa/inet.h netdb.h])
 AC_CHECK_HEADERS([sys/select.h poll.h])
 AC_CHECK_HEADERS([sys/time.h sys/timeb.h])
+AC_CHECK_HEADERS([sys/random.h])
 AC_CHECK_HEADERS([dl.h dlfcn.h])
 AC_CHECK_HEADERS([glob.h])
 AM_CONDITIONAL(WITH_GLOB, test "$ac_cv_header_glob_h" = "yes")
@@ -310,7 +310,7 @@
 AC_TYPE_UINT32_T
 
 dnl Checks for library functions.
-AC_CHECK_FUNCS([gettimeofday ftime stat isascii mmap munmap])
+AC_CHECK_FUNCS([getentropy gettimeofday ftime isascii stat mmap munmap])
 
 AH_VERBATIM([HAVE_MUNMAP_AFTER],[/* mmap() is no good without munmap() */
 #if defined(HAVE_MMAP) && !defined(HAVE_MUNMAP)
@@ -1104,6 +1104,15 @@
 fi
 AC_SUBST(WITH_ICU)
 
+dnl
+dnl Crypto libraries
+dnl
+case "$host" in
+    *-*-mingw*)
+        CRYPTO_LIBS="-lbcrypt"
+        ;;
+esac
+
 if test "$with_coverage" = "yes" && test "${GCC}" = "yes"
 then
     echo Enabling code coverage for GCC
@@ -1115,7 +1124,7 @@
 
 XML_LIBS="-lxml2"
 XML_LIBTOOLLIBS="libxml2.la"
-NON_PC_LIBS="${THREAD_LIBS} ${ICONV_LIBS} ${LIBM} ${NET_LIBS}"
+NON_PC_LIBS="${THREAD_LIBS} ${ICONV_LIBS} ${LIBM} ${NET_LIBS} ${CRYPTO_LIBS}"
 XML_PC_LIBS="${XML_PC_LIBS} ${NON_PC_LIBS}"
 XML_PRIVATE_LIBS="${XML_PRIVATE_LIBS} ${NON_PC_LIBS}"
 XML_PRIVATE_CFLAGS="${XML_PRIVATE_CFLAGS} ${THREAD_CFLAGS} ${ICONV_CFLAGS}"
diff --git a/src/dict.c b/src/dict.c
index a0d311a..7a49289 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -19,11 +19,19 @@
 #define IN_LIBXML
 #include "libxml.h"
 
+#include <errno.h>
 #include <limits.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
 
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
 #include "private/dict.h"
+#include "private/globals.h"
 #include "private/threads.h"
 
 #include <libxml/parser.h>
@@ -908,24 +916,21 @@
 
 static unsigned globalRngState[2];
 
-#ifdef XML_THREAD_LOCAL
-static XML_THREAD_LOCAL int localRngInitialized = 0;
-static XML_THREAD_LOCAL unsigned localRngState[2];
-#endif
-
 ATTRIBUTE_NO_SANITIZE_INTEGER
 void
 xmlInitRandom(void) {
-    int var;
-
     xmlInitMutex(&xmlRngMutex);
 
-    /* TODO: Get seed values from system PRNG */
+    {
+        int var;
 
-    globalRngState[0] = (unsigned) time(NULL) ^
-                        HASH_ROL((unsigned) ((size_t) &xmlInitRandom & 0xFFFFFFFF), 8);
-    globalRngState[1] = HASH_ROL((unsigned) ((size_t) &xmlRngMutex & 0xFFFFFFFF), 16) ^
-                        HASH_ROL((unsigned) ((size_t) &var & 0xFFFFFFFF), 24);
+        globalRngState[0] =
+                (unsigned) time(NULL) ^
+                HASH_ROL((unsigned) ((size_t) &xmlInitRandom & 0xFFFFFFFF), 8);
+        globalRngState[1] =
+                HASH_ROL((unsigned) ((size_t) &xmlRngMutex & 0xFFFFFFFF), 16) ^
+                HASH_ROL((unsigned) ((size_t) &var & 0xFFFFFFFF), 24);
+    }
 }
 
 void
@@ -948,18 +953,7 @@
 }
 
 unsigned
-xmlRandom(void) {
-#ifdef XML_THREAD_LOCAL
-    if (!localRngInitialized) {
-        xmlMutexLock(&xmlRngMutex);
-        localRngState[0] = xoroshiro64ss(globalRngState);
-        localRngState[1] = xoroshiro64ss(globalRngState);
-        localRngInitialized = 1;
-        xmlMutexUnlock(&xmlRngMutex);
-    }
-
-    return(xoroshiro64ss(localRngState));
-#else
+xmlGlobalRandom(void) {
     unsigned ret;
 
     xmlMutexLock(&xmlRngMutex);
@@ -967,6 +961,14 @@
     xmlMutexUnlock(&xmlRngMutex);
 
     return(ret);
+}
+
+unsigned
+xmlRandom(void) {
+#ifdef LIBXML_THREAD_ENABLED
+    return(xoroshiro64ss(xmlGetLocalRngState()));
+#else
+    return(xmlGlobalRandom());
 #endif
 }
 
diff --git a/src/encoding.c b/src/encoding.c
index 7d80e16..0f58029 100644
--- a/src/encoding.c
+++ b/src/encoding.c
@@ -1324,6 +1324,7 @@
 static const xmlCharEncodingHandler *xmlUTF16LEHandler = &defaultHandlers[1];
 static const xmlCharEncodingHandler *xmlUTF16BEHandler = &defaultHandlers[2];
 static const xmlCharEncodingHandler *xmlLatin1Handler = &defaultHandlers[4];
+static const xmlCharEncodingHandler *xmlAsciiHandler = &defaultHandlers[5];
 
 /* the size should be growable, but it's not a big deal ... */
 #define MAX_ENCODING_HANDLERS 50
@@ -1658,6 +1659,7 @@
 /**
  * xmlFindExtraHandler:
  * @name:  a string describing the char encoding.
+ * @output:  boolean, use handler for output
  * @out:  pointer to resulting handler
  *
  * Search the non-default handlers for an exact match.
@@ -1666,7 +1668,8 @@
  * allocation failed.
  */
 static int
-xmlFindExtraHandler(const char *name, xmlCharEncodingHandler **out) {
+xmlFindExtraHandler(const char *name, int output,
+                    xmlCharEncodingHandler **out) {
     int ret;
     int i;
 
@@ -1674,10 +1677,21 @@
 
     if (handlers != NULL) {
         for (i = 0; i < nbCharEncodingHandler; i++) {
+            xmlCharEncodingHandler *handler = handlers[i];
+
             if (!xmlStrcasecmp((const xmlChar *) name,
-                               (const xmlChar *) handlers[i]->name)) {
-                *out = handlers[i];
-                return(0);
+                               (const xmlChar *) handler->name)) {
+                if (output) {
+                    if (handler->output != NULL) {
+                        *out = handler;
+                        return(0);
+                    }
+                } else {
+                    if (handler->input != NULL) {
+                        *out = handler;
+                        return(0);
+                    }
+                }
             }
         }
     }
@@ -1704,6 +1718,7 @@
 /**
  * xmlFindHandler:
  * @name:  a string describing the char encoding.
+ * @output:  boolean, use handler for output
  * @out:  pointer to resulting handler
  *
  * Search all handlers for an exact match.
@@ -1712,24 +1727,37 @@
  * allocation failed.
  */
 static int
-xmlFindHandler(const char *name, xmlCharEncodingHandler **out) {
+xmlFindHandler(const char *name, int output, xmlCharEncodingHandler **out) {
     int i;
 
     /*
      * Check for default handlers
      */
     for (i = 0; i < (int) NUM_DEFAULT_HANDLERS; i++) {
+        xmlCharEncodingHandler *handler;
+
+        handler = (xmlCharEncodingHandler *) &defaultHandlers[i];
+
         if (xmlStrcasecmp((const xmlChar *) name,
-                          (const xmlChar *) defaultHandlers[i].name) == 0) {
-            *out = (xmlCharEncodingHandler *) &defaultHandlers[i];
-            return(0);
+                          (const xmlChar *) handler->name) == 0) {
+            if (output) {
+                if (handler->output != NULL) {
+                    *out = handler;
+                    return(0);
+                }
+            } else {
+                if (handler->input != NULL) {
+                    *out = handler;
+                    return(0);
+                }
+            }
         }
     }
 
     /*
      * Check for other handlers
      */
-    return(xmlFindExtraHandler(name, out));
+    return(xmlFindExtraHandler(name, output, out));
 }
 
 /**
@@ -1803,6 +1831,9 @@
             numNames = sizeof(ucs2Names) / sizeof(ucs2Names[0]);
 	    break;
 
+        case XML_CHAR_ENCODING_ASCII:
+	    *out = (xmlCharEncodingHandler *) xmlAsciiHandler;
+            return(0);
         case XML_CHAR_ENCODING_8859_1:
 	    *out = (xmlCharEncodingHandler *) xmlLatin1Handler;
             return(0);
@@ -1846,11 +1877,11 @@
     }
 
     if (name != NULL)
-        return(xmlFindExtraHandler(name, out));
+        return(xmlFindExtraHandler(name, 0, out));
 
     if (names != NULL) {
         for (i = 0; i < numNames; i++) {
-            ret = xmlFindExtraHandler(names[i], out);
+            ret = xmlFindExtraHandler(names[i], 0, out);
             if (*out != NULL)
                 return(0);
             if (ret != XML_ERR_UNSUPPORTED_ENCODING)
@@ -1882,6 +1913,7 @@
 /**
  * xmlOpenCharEncodingHandler:
  * @name:  a string describing the char encoding.
+ * @output:  boolean, use handler for output
  * @out:  pointer to result
  *
  * Find or create a handler matching the encoding. If no default or
@@ -1895,7 +1927,8 @@
  * Returns an xmlParserErrors error code.
  */
 int
-xmlOpenCharEncodingHandler(const char *name, xmlCharEncodingHandler **out) {
+xmlOpenCharEncodingHandler(const char *name, int output,
+                           xmlCharEncodingHandler **out) {
     const char *nalias;
     const char *norig;
     xmlCharEncoding enc;
@@ -1916,7 +1949,7 @@
     if (nalias != NULL)
 	name = nalias;
 
-    ret = xmlFindHandler(name, out);
+    ret = xmlFindHandler(name, output, out);
     if (*out != NULL)
         return(0);
     if (ret != XML_ERR_UNSUPPORTED_ENCODING)
@@ -1943,7 +1976,7 @@
 xmlFindCharEncodingHandler(const char *name) {
     xmlCharEncodingHandler *ret;
 
-    xmlOpenCharEncodingHandler(name, &ret);
+    xmlOpenCharEncodingHandler(name, 0, &ret);
     return(ret);
 }
 
diff --git a/src/entities.c b/src/entities.c
index e8a0721..9e951c3 100644
--- a/src/entities.c
+++ b/src/entities.c
@@ -24,6 +24,7 @@
 #include <libxml/parserInternals.h>
 #include <libxml/xmlerror.h>
 #include <libxml/dict.h>
+#include <libxml/xmlsave.h>
 
 #include "private/entities.h"
 #include "private/error.h"
@@ -83,7 +84,7 @@
         dict = entity->doc->dict;
 
 
-    if ((entity->children) && (entity->owner == 1) &&
+    if ((entity->children) &&
         (entity == (xmlEntityPtr) entity->children->parent))
         xmlFreeNodeList(entity->children);
     if ((entity->name != NULL) &&
@@ -152,7 +153,6 @@
     ret->URI = NULL; /* to be computed by the layer knowing
 			the defining entity */
     ret->orig = NULL;
-    ret->owner = 0;
 
     return(ret);
 
@@ -653,13 +653,18 @@
 
                 l = 4;
                 val = xmlGetUTF8Char(cur, &l);
-                if ((val < 0) || (!IS_CHAR(val))) {
-		    snprintf(buf, sizeof(buf), "&#%d;", *cur);
-		    buf[sizeof(buf) - 1] = 0;
-		    ptr = buf;
-		    while (*ptr != 0) *out++ = *ptr++;
-		    cur++;
-		    continue;
+                if (val < 0) {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+                    fprintf(stderr, "xmlEncodeEntitiesInternal: "
+                            "invalid UTF-8\n");
+                    abort();
+#endif
+                    val = 0xFFFD;
+                    cur++;
+                } else {
+                    if (!IS_CHAR(val))
+                        val = 0xFFFD;
+                    cur += l;
 		}
 		/*
 		 * We could do multiple things here. Just save as a char ref
@@ -668,7 +673,6 @@
 		buf[sizeof(buf) - 1] = 0;
 		ptr = buf;
 		while (*ptr != 0) *out++ = *ptr++;
-		cur += l;
 		continue;
 	    }
 	} else if (IS_BYTE_CHAR(*cur)) {
@@ -918,46 +922,6 @@
 #ifdef LIBXML_OUTPUT_ENABLED
 
 /**
- * xmlDumpEntityContent:
- * @buf:  An XML buffer.
- * @content:  The entity content.
- *
- * This will dump the quoted string value, taking care of the special
- * treatment required by %
- */
-static void
-xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) {
-    if (xmlStrchr(content, '%')) {
-        const xmlChar * base, *cur;
-
-	xmlBufferCCat(buf, "\"");
-	base = cur = content;
-	while (*cur != 0) {
-	    if (*cur == '"') {
-		if (base != cur)
-		    xmlBufferAdd(buf, base, cur - base);
-		xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
-		cur++;
-		base = cur;
-	    } else if (*cur == '%') {
-		if (base != cur)
-		    xmlBufferAdd(buf, base, cur - base);
-		xmlBufferAdd(buf, BAD_CAST "&#x25;", 6);
-		cur++;
-		base = cur;
-	    } else {
-		cur++;
-	    }
-	}
-	if (base != cur)
-	    xmlBufferAdd(buf, base, cur - base);
-	xmlBufferCCat(buf, "\"");
-    } else {
-        xmlBufferWriteQuotedString(buf, content);
-    }
-}
-
-/**
  * xmlDumpEntityDecl:
  * @buf:  An XML buffer.
  * @ent:  An entity table
@@ -966,80 +930,14 @@
  */
 void
 xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
-    if ((buf == NULL) || (ent == NULL)) return;
-    switch (ent->etype) {
-	case XML_INTERNAL_GENERAL_ENTITY:
-	    xmlBufferWriteChar(buf, "<!ENTITY ");
-	    xmlBufferWriteCHAR(buf, ent->name);
-	    xmlBufferWriteChar(buf, " ");
-	    if (ent->orig != NULL)
-		xmlBufferWriteQuotedString(buf, ent->orig);
-	    else
-		xmlDumpEntityContent(buf, ent->content);
-	    xmlBufferWriteChar(buf, ">\n");
-	    break;
-	case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
-	    xmlBufferWriteChar(buf, "<!ENTITY ");
-	    xmlBufferWriteCHAR(buf, ent->name);
-	    if (ent->ExternalID != NULL) {
-		 xmlBufferWriteChar(buf, " PUBLIC ");
-		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
-		 xmlBufferWriteChar(buf, " ");
-		 xmlBufferWriteQuotedString(buf, ent->SystemID);
-	    } else {
-		 xmlBufferWriteChar(buf, " SYSTEM ");
-		 xmlBufferWriteQuotedString(buf, ent->SystemID);
-	    }
-	    xmlBufferWriteChar(buf, ">\n");
-	    break;
-	case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
-	    xmlBufferWriteChar(buf, "<!ENTITY ");
-	    xmlBufferWriteCHAR(buf, ent->name);
-	    if (ent->ExternalID != NULL) {
-		 xmlBufferWriteChar(buf, " PUBLIC ");
-		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
-		 xmlBufferWriteChar(buf, " ");
-		 xmlBufferWriteQuotedString(buf, ent->SystemID);
-	    } else {
-		 xmlBufferWriteChar(buf, " SYSTEM ");
-		 xmlBufferWriteQuotedString(buf, ent->SystemID);
-	    }
-	    if (ent->content != NULL) { /* Should be true ! */
-		xmlBufferWriteChar(buf, " NDATA ");
-		if (ent->orig != NULL)
-		    xmlBufferWriteCHAR(buf, ent->orig);
-		else
-		    xmlBufferWriteCHAR(buf, ent->content);
-	    }
-	    xmlBufferWriteChar(buf, ">\n");
-	    break;
-	case XML_INTERNAL_PARAMETER_ENTITY:
-	    xmlBufferWriteChar(buf, "<!ENTITY % ");
-	    xmlBufferWriteCHAR(buf, ent->name);
-	    xmlBufferWriteChar(buf, " ");
-	    if (ent->orig == NULL)
-		xmlDumpEntityContent(buf, ent->content);
-	    else
-		xmlBufferWriteQuotedString(buf, ent->orig);
-	    xmlBufferWriteChar(buf, ">\n");
-	    break;
-	case XML_EXTERNAL_PARAMETER_ENTITY:
-	    xmlBufferWriteChar(buf, "<!ENTITY % ");
-	    xmlBufferWriteCHAR(buf, ent->name);
-	    if (ent->ExternalID != NULL) {
-		 xmlBufferWriteChar(buf, " PUBLIC ");
-		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
-		 xmlBufferWriteChar(buf, " ");
-		 xmlBufferWriteQuotedString(buf, ent->SystemID);
-	    } else {
-		 xmlBufferWriteChar(buf, " SYSTEM ");
-		 xmlBufferWriteQuotedString(buf, ent->SystemID);
-	    }
-	    xmlBufferWriteChar(buf, ">\n");
-	    break;
-	default:
-            break;
-    }
+    xmlSaveCtxtPtr save;
+
+    if ((buf == NULL) || (ent == NULL))
+        return;
+
+    save = xmlSaveToBuffer(buf, NULL, 0);
+    xmlSaveTree(save, (xmlNodePtr) ent);
+    xmlSaveClose(save);
 }
 
 /**
diff --git a/src/error.c b/src/error.c
index 9480d63..e5553d5 100644
--- a/src/error.c
+++ b/src/error.c
@@ -11,69 +11,169 @@
 
 #include <string.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <libxml/parser.h>
 #include <libxml/xmlerror.h>
 #include <libxml/xmlmemory.h>
 
 #include "private/error.h"
+#include "private/string.h"
 
-#ifndef va_copy
-  #ifdef __va_copy
-    #define va_copy(dest, src) __va_copy(dest, src)
-  #else
-    #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list))
-  #endif
-#endif
+/************************************************************************
+ *									*
+ *			Error struct					*
+ *									*
+ ************************************************************************/
 
-#define XML_MAX_ERRORS 100
+static int
+xmlVSetError(xmlError *err,
+             void *ctxt, xmlNodePtr node,
+             int domain, int code, xmlErrorLevel level,
+             const char *file, int line,
+             const char *str1, const char *str2, const char *str3,
+             int int1, int col,
+             const char *fmt, va_list ap)
+{
+    char *message = NULL;
+    char *fileCopy = NULL;
+    char *str1Copy = NULL;
+    char *str2Copy = NULL;
+    char *str3Copy = NULL;
 
-#define XML_GET_VAR_STR(msg, str) \
-    do { \
-        va_list ap; \
-        va_start(ap, msg); \
-        str = xmlVsnprintf(msg, ap); \
-        va_end(ap); \
-    } while (0);
-
-static char *
-xmlVsnprintf(const char *msg, va_list ap) {
-    int size, prev_size = -1;
-    int chars;
-    char *larger;
-    char *str;
-
-    str = (char *) xmlMalloc(150);
-    if (str == NULL)
-        return(NULL);
-
-    size = 150;
-
-    while (size < 64000) {
-        va_list copy;
-
-        va_copy(copy, ap);
-        chars = vsnprintf(str, size, msg, copy);
-        va_end(copy);
-        if ((chars > -1) && (chars < size)) {
-            if (prev_size == chars) {
-                break;
-            } else {
-                prev_size = chars;
-            }
-        }
-        if (chars > -1)
-            size += chars + 1;
-        else
-            size += 100;
-        larger = (char *) xmlRealloc(str, size);
-        if (larger == NULL) {
-            xmlFree(str);
-            return(NULL);
-        }
-        str = larger;
+    if (code == XML_ERR_OK) {
+        xmlResetError(err);
+        return(0);
     }
 
-    return(str);
+    /*
+     * Formatting the message
+     */
+    if (fmt == NULL) {
+        message = xmlMemStrdup("No error message provided");
+    } else {
+        xmlChar *tmp;
+        int res;
+
+        res = xmlStrVASPrintf(&tmp, MAX_ERR_MSG_SIZE, fmt, ap);
+        if (res < 0)
+            goto err_memory;
+        message = (char *) tmp;
+    }
+    if (message == NULL)
+        goto err_memory;
+
+    if (file != NULL) {
+        fileCopy = (char *) xmlStrdup((const xmlChar *) file);
+        if (fileCopy == NULL)
+            goto err_memory;
+    }
+    if (str1 != NULL) {
+        str1Copy = (char *) xmlStrdup((const xmlChar *) str1);
+        if (str1Copy == NULL)
+            goto err_memory;
+    }
+    if (str2 != NULL) {
+        str2Copy = (char *) xmlStrdup((const xmlChar *) str2);
+        if (str2Copy == NULL)
+            goto err_memory;
+    }
+    if (str3 != NULL) {
+        str3Copy = (char *) xmlStrdup((const xmlChar *) str3);
+        if (str3Copy == NULL)
+            goto err_memory;
+    }
+
+    xmlResetError(err);
+
+    err->domain = domain;
+    err->code = code;
+    err->message = message;
+    err->level = level;
+    err->file = fileCopy;
+    err->line = line;
+    err->str1 = str1Copy;
+    err->str2 = str2Copy;
+    err->str3 = str3Copy;
+    err->int1 = int1;
+    err->int2 = col;
+    err->node = node;
+    err->ctxt = ctxt;
+
+    return(0);
+
+err_memory:
+    xmlFree(message);
+    xmlFree(fileCopy);
+    xmlFree(str1Copy);
+    xmlFree(str2Copy);
+    xmlFree(str3Copy);
+    return(-1);
+}
+
+static int LIBXML_ATTR_FORMAT(14,15)
+xmlSetError(xmlError *err,
+            void *ctxt, xmlNodePtr node,
+            int domain, int code, xmlErrorLevel level,
+            const char *file, int line,
+            const char *str1, const char *str2, const char *str3,
+            int int1, int col,
+            const char *fmt, ...)
+{
+    va_list ap;
+    int res;
+
+    va_start(ap, fmt);
+    res = xmlVSetError(err, ctxt, node, domain, code, level, file, line,
+                       str1, str2, str3, int1, col, fmt, ap);
+    va_end(ap);
+
+    return(res);
+}
+
+static int
+xmlVUpdateError(xmlError *err,
+                void *ctxt, xmlNodePtr node,
+                int domain, int code, xmlErrorLevel level,
+                const char *file, int line,
+                const char *str1, const char *str2, const char *str3,
+                int int1, int col,
+                const char *fmt, va_list ap)
+{
+    int res;
+
+    /*
+     * Find first element parent.
+     */
+    if (node != NULL) {
+        int i;
+
+        for (i = 0; i < 10; i++) {
+            if ((node->type == XML_ELEMENT_NODE) ||
+                (node->parent == NULL))
+                break;
+            node = node->parent;
+        }
+    }
+
+    /*
+     * Get file and line from node.
+     */
+    if (node != NULL) {
+        if ((file == NULL) && (node->doc != NULL))
+            file = (const char *) node->doc->URL;
+
+        if (line == 0) {
+            if (node->type == XML_ELEMENT_NODE)
+                line = node->line;
+            if ((line == 0) || (line == 65535))
+                line = xmlGetLineNo(node);
+        }
+    }
+
+    res = xmlVSetError(err, ctxt, node, domain, code, level, file, line,
+                       str1, str2, str3, int1, col, fmt, ap);
+
+    return(res);
 }
 
 /************************************************************************
@@ -125,14 +225,21 @@
  * @ctx:  the new error handling context
  * @handler:  the new handler function
  *
- * Function to reset the handler and the error context for out of
- * context error messages.
- * This simply means that @handler will be called for subsequent
- * error messages while not parsing nor validating. And @ctx will
- * be passed as first argument to @handler
- * One can simply force messages to be emitted to another FILE * than
- * stderr by setting @ctx to this file handle and @handler to NULL.
- * For multi-threaded applications, this must be set separately for each thread.
+ * DEPRECATED: See xmlSetStructuredErrorFunc for alternatives.
+ *
+ * Set the global "generic" handler and context for error messages.
+ * The generic error handler will only receive fragments of error
+ * messages which should be concatenated or printed to a stream.
+ *
+ * If handler is NULL, use the built-in default handler which prints
+ * to stderr.
+ *
+ * Since this is a global setting, it's a good idea to reset the
+ * error handler to its default value after collecting the errors
+ * you're interested in.
+ *
+ * For multi-threaded applications, this must be set separately for
+ * each thread.
  */
 void
 xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
@@ -148,12 +255,30 @@
  * @ctx:  the new error handling context
  * @handler:  the new handler function
  *
- * Function to reset the handler and the error context for out of
- * context structured error messages.
- * This simply means that @handler will be called for subsequent
- * error messages while not parsing nor validating. And @ctx will
- * be passed as first argument to @handler
- * For multi-threaded applications, this must be set separately for each thread.
+ * DEPRECATED: Use a per-context error handler.
+ *
+ * It's recommended to use the per-context error handlers instead:
+ *
+ * - xmlCtxtSetErrorHandler (since 2.13.0)
+ * - xmlTextReaderSetStructuredErrorHandler
+ * - xmlXPathSetErrorHandler (since 2.13.0)
+ * - xmlXIncludeSetErrorHandler (since 2.13.0)
+ * - xmlSchemaSetParserStructuredErrors
+ * - xmlSchemaSetValidStructuredErrors
+ * - xmlRelaxNGSetParserStructuredErrors
+ * - xmlRelaxNGSetValidStructuredErrors
+ *
+ * Set the global "structured" handler and context for error messages.
+ * If handler is NULL, the error handler is deactivated.
+ *
+ * The structured error handler takes precedence over "generic"
+ * handlers, even per-context generic handlers.
+ *
+ * Since this is a global setting, it's a good idea to deactivate the
+ * error handler after collecting the errors you're interested in.
+ *
+ * For multi-threaded applications, this must be set separately for
+ * each thread.
  */
 void
 xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
@@ -171,6 +296,8 @@
  * xmlParserPrintFileInfo:
  * @input:  an xmlParserInputPtr input
  *
+ * DEPRECATED: Use xmlFormatError.
+ *
  * Displays the associated file and line information for the current input
  */
 
@@ -262,6 +389,8 @@
  * xmlParserPrintFileContext:
  * @input:  an xmlParserInputPtr input
  *
+ * DEPRECATED: Use xmlFormatError.
+ *
  * Displays current context within the input content for error tracking
  */
 void
@@ -271,35 +400,35 @@
 }
 
 /**
- * xmlReportError:
- * @err: the error
- * @ctx: the parser context or NULL
- * @str: the formatted error message
+ * xmlFormatError:
+ * @err:  the error
+ * @channel:  callback
+ * @data:  user data for callback
  *
- * Report an error with its context, replace the 4 old error/warning
- * routines.
+ * Report a formatted error to a printf-like callback.
+ *
+ * This can result in a verbose multi-line report including additional
+ * information from the parser context.
  */
-static void
-xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str,
-               xmlGenericErrorFunc channel, void *data)
+void
+xmlFormatError(const xmlError *err, xmlGenericErrorFunc channel, void *data)
 {
-    char *file = NULL;
-    int line = 0;
-    int code = -1;
+    const char *message;
+    const char *file;
+    int line;
+    int code;
     int domain;
     const xmlChar *name = NULL;
     xmlNodePtr node;
     xmlErrorLevel level;
+    xmlParserCtxtPtr ctxt = NULL;
     xmlParserInputPtr input = NULL;
     xmlParserInputPtr cur = NULL;
 
-    if (err == NULL)
+    if ((err == NULL) || (channel == NULL))
         return;
 
-    if (channel == NULL) {
-	channel = xmlGenericError;
-	data = xmlGenericErrorContext;
-    }
+    message = err->message;
     file = err->file;
     line = err->line;
     code = err->code;
@@ -310,7 +439,14 @@
     if (code == XML_ERR_OK)
         return;
 
-    if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
+    if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
+        (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
+	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
+	ctxt = err->ctxt;
+    }
+
+    if ((node != NULL) && (node->type == XML_ELEMENT_NODE) &&
+        (domain != XML_FROM_SCHEMASV))
         name = node->name;
 
     /*
@@ -427,19 +563,35 @@
             channel(data, "error : ");
             break;
     }
-    if (str != NULL) {
+    if (message != NULL) {
         int len;
-	len = xmlStrlen((const xmlChar *)str);
-	if ((len > 0) && (str[len - 1] != '\n'))
-	    channel(data, "%s\n", str);
+	len = xmlStrlen((const xmlChar *) message);
+	if ((len > 0) && (message[len - 1] != '\n'))
+	    channel(data, "%s\n", message);
 	else
-	    channel(data, "%s", str);
+	    channel(data, "%s", message);
     } else {
-        channel(data, "%s\n", "out of memory error");
+        channel(data, "%s\n", "No error message provided");
     }
 
     if (ctxt != NULL) {
+        if ((input != NULL) &&
+            ((input->buf == NULL) || (input->buf->encoder == NULL)) &&
+            (code == XML_ERR_INVALID_ENCODING) &&
+            (input->cur < input->end)) {
+            int i;
+
+            channel(data, "Bytes:");
+            for (i = 0; i < 4; i++) {
+                if (input->cur + i >= input->end)
+                    break;
+                channel(data, " 0x%02X", input->cur[i]);
+            }
+            channel(data, "\n");
+        }
+
         xmlParserPrintFileContextInternal(input, channel, data);
+
         if (cur != NULL) {
             if (cur->filename)
                 channel(data, "%s:%d: \n", cur->filename, cur->line);
@@ -464,6 +616,47 @@
 }
 
 /**
+ * xmlRaiseMemoryError:
+ * @schannel: the structured callback channel
+ * @channel: the old callback channel
+ * @data: the callback data
+ * @domain: the domain for the error
+ * @error: optional error struct to be filled
+ *
+ * Update the global and optional error structure, then forward the
+ * error to an error handler.
+ *
+ * This function doesn't make memory allocations which are likely
+ * to fail after an OOM error.
+ */
+void
+xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel,
+                    void *data, int domain, xmlError *error)
+{
+    xmlError *lastError = &xmlLastError;
+
+    xmlResetLastError();
+    lastError->domain = domain;
+    lastError->code = XML_ERR_NO_MEMORY;
+    lastError->level = XML_ERR_FATAL;
+
+    if (error != NULL) {
+        xmlResetError(error);
+        error->domain = domain;
+        error->code = XML_ERR_NO_MEMORY;
+        error->level = XML_ERR_FATAL;
+    }
+
+    if (schannel != NULL) {
+        schannel(data, lastError);
+    } else if (xmlStructuredError != NULL) {
+        xmlStructuredError(xmlStructuredErrorContext, lastError);
+    } else if (channel != NULL) {
+        channel(data, "libxml2: out of memory\n");
+    }
+}
+
+/**
  * xmlVRaiseError:
  * @schannel: the structured callback channel
  * @channel: the old callback channel
@@ -492,233 +685,58 @@
 int
 xmlVRaiseError(xmlStructuredErrorFunc schannel,
                xmlGenericErrorFunc channel, void *data, void *ctx,
-               void *nod, int domain, int code, xmlErrorLevel level,
+               xmlNode *node, int domain, int code, xmlErrorLevel level,
                const char *file, int line, const char *str1,
                const char *str2, const char *str3, int int1, int col,
                const char *msg, va_list ap)
 {
     xmlParserCtxtPtr ctxt = NULL;
-    xmlNodePtr node = (xmlNodePtr) nod;
-    char *str = NULL;
-    xmlParserInputPtr input = NULL;
-
     /* xmlLastError is a macro retrieving the per-thread global. */
     xmlErrorPtr lastError = &xmlLastError;
     xmlErrorPtr to = lastError;
-    xmlNodePtr baseptr = NULL;
 
     if (code == XML_ERR_OK)
         return(0);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+    if ((code == XML_ERR_INTERNAL_ERROR) ||
+        (code == XML_ERR_ARGUMENT)) {
+        fprintf(stderr, "Unexpected error: %d\n", code);
+        abort();
+    }
+#endif
     if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING))
         return(0);
+
     if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
         (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
 	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
 	ctxt = (xmlParserCtxtPtr) ctx;
 
-        if (ctxt != NULL) {
-            if (level == XML_ERR_WARNING) {
-                if (ctxt->nbWarnings >= XML_MAX_ERRORS)
-                    return(0);
-                ctxt->nbWarnings += 1;
-            } else {
-                if (ctxt->nbErrors >= XML_MAX_ERRORS)
-                    return(0);
-                ctxt->nbErrors += 1;
-            }
-
-            if ((schannel == NULL) && (ctxt->sax != NULL) &&
-                (ctxt->sax->initialized == XML_SAX2_MAGIC) &&
-                (ctxt->sax->serror != NULL)) {
-                schannel = ctxt->sax->serror;
-                data = ctxt->userData;
-            }
-        }
-    }
-    /*
-     * Check if structured error handler set
-     */
-    if (schannel == NULL) {
-	schannel = xmlStructuredError;
-	/*
-	 * if user has defined handler, change data ptr to user's choice
-	 */
-	if (schannel != NULL)
-	    data = xmlStructuredErrorContext;
-    }
-    /*
-     * Formatting the message
-     */
-    if (msg == NULL) {
-        str = (char *) xmlStrdup(BAD_CAST "No error message provided");
-    } else {
-        str = xmlVsnprintf(msg, ap);
-    }
-    if (str == NULL)
-        goto err_memory;
-
-    /*
-     * specific processing if a parser context is provided
-     */
-    if ((ctxt != NULL) && (ctxt->input != NULL)) {
-        if (file == NULL) {
-            input = ctxt->input;
-            if ((input->filename == NULL) && (ctxt->inputNr > 1)) {
-                input = ctxt->inputTab[ctxt->inputNr - 2];
-            }
-            file = input->filename;
-            line = input->line;
-            col = input->col;
-        }
-        to = &ctxt->lastError;
-    } else if ((node != NULL) && (file == NULL)) {
-	int i;
-
-	if ((node->doc != NULL) && (node->doc->URL != NULL)) {
-	    baseptr = node;
-/*	    file = (const char *) node->doc->URL; */
-	}
-	for (i = 0;
-	     ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
-	     i++)
-	     node = node->parent;
-        if ((baseptr == NULL) && (node != NULL) &&
-	    (node->doc != NULL) && (node->doc->URL != NULL))
-	    baseptr = node;
-
-	if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
-	    line = node->line;
-	if ((line == 0) || (line == 65535))
-	    line = xmlGetLineNo(node);
+        if (ctxt != NULL)
+            to = &ctxt->lastError;
     }
 
-    /*
-     * Save the information about the error
-     */
-    xmlResetError(to);
-    to->domain = domain;
-    to->code = code;
-    to->message = str;
-    to->level = level;
-    if (file != NULL) {
-        to->file = (char *) xmlStrdup((const xmlChar *) file);
-        if (to->file == NULL)
-            goto err_memory;
-    }
-    else if (baseptr != NULL) {
-#ifdef LIBXML_XINCLUDE_ENABLED
-	/*
-	 * We check if the error is within an XInclude section and,
-	 * if so, attempt to print out the href of the XInclude instead
-	 * of the usual "base" (doc->URL) for the node (bug 152623).
-	 */
-        xmlNodePtr prev = baseptr;
-        xmlChar *href = NULL;
-	int inclcount = 0;
-	while (prev != NULL) {
-	    if (prev->prev == NULL)
-	        prev = prev->parent;
-	    else {
-	        prev = prev->prev;
-		if (prev->type == XML_XINCLUDE_START) {
-		    if (inclcount > 0) {
-                        --inclcount;
-                    } else {
-                        if (xmlNodeGetAttrValue(prev, BAD_CAST "href", NULL,
-                                                &href) < 0)
-                            goto err_memory;
-                        if (href != NULL)
-		            break;
-                    }
-		} else if (prev->type == XML_XINCLUDE_END)
-		    inclcount++;
-	    }
-	}
-        if (href != NULL) {
-            to->file = (char *) href;
-        } else
-#endif
-        if (baseptr->doc->URL != NULL) {
-	    to->file = (char *) xmlStrdup(baseptr->doc->URL);
-            if (to->file == NULL)
-                goto err_memory;
-        }
-    }
-    to->line = line;
-    if (str1 != NULL) {
-        to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
-        if (to->str1 == NULL)
-            goto err_memory;
-    }
-    if (str2 != NULL) {
-        to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
-        if (to->str2 == NULL)
-            goto err_memory;
-    }
-    if (str3 != NULL) {
-        to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
-        if (to->str3 == NULL)
-            goto err_memory;
-    }
-    to->int1 = int1;
-    to->int2 = col;
-    to->node = node;
-    to->ctxt = ctx;
+    if (xmlVUpdateError(to, ctxt, node, domain, code, level, file, line,
+                        str1, str2, str3, int1, col, msg, ap))
+        return(-1);
 
     if (to != lastError) {
         if (xmlCopyError(to, lastError) < 0)
-            goto err_memory;
+            return(-1);
     }
 
     if (schannel != NULL) {
 	schannel(data, to);
-	return(0);
-    }
-
-    /*
-     * Find the callback channel if channel param is NULL
-     */
-    if ((ctxt != NULL) && (channel == NULL) &&
-        (xmlStructuredError == NULL) && (ctxt->sax != NULL)) {
-        if (level == XML_ERR_WARNING)
-	    channel = ctxt->sax->warning;
+    } else if (xmlStructuredError != NULL) {
+        xmlStructuredError(xmlStructuredErrorContext, to);
+    } else if (channel != NULL) {
+        if ((ctxt == NULL) && (channel == xmlGenericErrorDefaultFunc))
+            xmlFormatError(to, xmlGenericError, xmlGenericErrorContext);
         else
-	    channel = ctxt->sax->error;
-	data = ctxt->userData;
-    } else if (channel == NULL) {
-	channel = xmlGenericError;
-	data = xmlGenericErrorContext;
+	    channel(data, "%s", to->message);
     }
-    if (channel == NULL)
-        return(0);
-
-    if ((channel == xmlParserError) ||
-        (channel == xmlParserWarning) ||
-	(channel == xmlParserValidityError) ||
-	(channel == xmlParserValidityWarning))
-	xmlReportError(to, ctxt, str, NULL, NULL);
-    else if (((void(*)(void)) channel == (void(*)(void)) fprintf) ||
-             (channel == xmlGenericErrorDefaultFunc))
-	xmlReportError(to, ctxt, str, channel, data);
-    else
-	channel(data, "%s", str);
 
     return(0);
-
-err_memory:
-    xmlResetError(to);
-    to->domain = domain;
-    to->code = XML_ERR_NO_MEMORY;
-    to->level = XML_ERR_FATAL;
-
-    if (to != lastError) {
-        xmlResetError(lastError);
-        lastError->domain = domain;
-        lastError->code = XML_ERR_NO_MEMORY;
-        lastError->level = XML_ERR_FATAL;
-    }
-
-    return(-1);
 }
 
 /**
@@ -750,7 +768,7 @@
 int
 __xmlRaiseError(xmlStructuredErrorFunc schannel,
                 xmlGenericErrorFunc channel, void *data, void *ctx,
-                void *nod, int domain, int code, xmlErrorLevel level,
+                xmlNode *node, int domain, int code, xmlErrorLevel level,
                 const char *file, int line, const char *str1,
                 const char *str2, const char *str3, int int1, int col,
                 const char *msg, ...)
@@ -759,7 +777,7 @@
     int res;
 
     va_start(ap, msg);
-    res = xmlVRaiseError(schannel, channel, data, ctx, nod, domain, code,
+    res = xmlVRaiseError(schannel, channel, data, ctx, node, domain, code,
                          level, file, line, str1, str2, str3, int1, col, msg,
                          ap);
     va_end(ap);
@@ -768,36 +786,6 @@
 }
 
 /**
- * __xmlSimpleError:
- * @domain: where the error comes from
- * @code: the error code
- * @node: the context node
- * @extra:  extra information
- *
- * Handle an out of memory condition
- */
-void
-__xmlSimpleError(int domain, int code, xmlNodePtr node,
-                 const char *msg, const char *extra)
-{
-
-    if (code == XML_ERR_NO_MEMORY) {
-	if (extra)
-	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
-			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
-			    NULL, NULL, 0, 0,
-			    "Memory allocation failed : %s\n", extra);
-	else
-	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
-			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
-			    NULL, NULL, 0, 0, "Memory allocation failed\n");
-    } else {
-	__xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
-			code, XML_ERR_ERROR, NULL, 0, extra,
-			NULL, NULL, 0, 0, msg, extra);
-    }
-}
-/**
  * xmlParserError:
  * @ctx:  an XML parser context
  * @msg:  the message to display/transmit
@@ -807,37 +795,11 @@
  * extra parameters.
  */
 void
-xmlParserError(void *ctx, const char *msg, ...)
+xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
 {
-    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
-    xmlParserInputPtr input = NULL;
-    xmlParserInputPtr cur = NULL;
-    char * str;
+    xmlParserCtxtPtr ctxt = ctx;
 
-    if (ctxt != NULL) {
-	input = ctxt->input;
-	if ((input != NULL) && (input->filename == NULL) &&
-	    (ctxt->inputNr > 1)) {
-	    cur = input;
-	    input = ctxt->inputTab[ctxt->inputNr - 2];
-	}
-	xmlParserPrintFileInfo(input);
-    }
-
-    xmlGenericError(xmlGenericErrorContext, "error: ");
-    XML_GET_VAR_STR(msg, str);
-    xmlGenericError(xmlGenericErrorContext, "%s", str);
-    if (str != NULL)
-	xmlFree(str);
-
-    if (ctxt != NULL) {
-	xmlParserPrintFileContext(input);
-	if (cur != NULL) {
-	    xmlParserPrintFileInfo(cur);
-	    xmlGenericError(xmlGenericErrorContext, "\n");
-	    xmlParserPrintFileContext(cur);
-	}
-    }
+    xmlFormatError(&ctxt->lastError, xmlGenericError, xmlGenericErrorContext);
 }
 
 /**
@@ -850,45 +812,13 @@
  * extra parameters.
  */
 void
-xmlParserWarning(void *ctx, const char *msg, ...)
+xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
 {
-    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
-    xmlParserInputPtr input = NULL;
-    xmlParserInputPtr cur = NULL;
-    char * str;
+    xmlParserCtxtPtr ctxt = ctx;
 
-    if (ctxt != NULL) {
-	input = ctxt->input;
-	if ((input != NULL) && (input->filename == NULL) &&
-	    (ctxt->inputNr > 1)) {
-	    cur = input;
-	    input = ctxt->inputTab[ctxt->inputNr - 2];
-	}
-	xmlParserPrintFileInfo(input);
-    }
-
-    xmlGenericError(xmlGenericErrorContext, "warning: ");
-    XML_GET_VAR_STR(msg, str);
-    xmlGenericError(xmlGenericErrorContext, "%s", str);
-    if (str != NULL)
-	xmlFree(str);
-
-    if (ctxt != NULL) {
-	xmlParserPrintFileContext(input);
-	if (cur != NULL) {
-	    xmlParserPrintFileInfo(cur);
-	    xmlGenericError(xmlGenericErrorContext, "\n");
-	    xmlParserPrintFileContext(cur);
-	}
-    }
+    xmlFormatError(&ctxt->lastError, xmlGenericError, xmlGenericErrorContext);
 }
 
-/************************************************************************
- *									*
- *			Handling of validation errors			*
- *									*
- ************************************************************************/
-
 /**
  * xmlParserValidityError:
  * @ctx:  an XML parser context
@@ -899,38 +829,11 @@
  * line, position and extra parameters.
  */
 void
-xmlParserValidityError(void *ctx, const char *msg, ...)
+xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
 {
-    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
-    xmlParserInputPtr input = NULL;
-    char * str;
-    int len = xmlStrlen((const xmlChar *) msg);
-    static int had_info = 0;
+    xmlParserCtxtPtr ctxt = ctx;
 
-    if ((len > 1) && (msg[len - 2] != ':')) {
-	if (ctxt != NULL) {
-	    input = ctxt->input;
-	    if ((input->filename == NULL) && (ctxt->inputNr > 1))
-		input = ctxt->inputTab[ctxt->inputNr - 2];
-
-	    if (had_info == 0) {
-		xmlParserPrintFileInfo(input);
-	    }
-	}
-	xmlGenericError(xmlGenericErrorContext, "validity error: ");
-	had_info = 0;
-    } else {
-	had_info = 1;
-    }
-
-    XML_GET_VAR_STR(msg, str);
-    xmlGenericError(xmlGenericErrorContext, "%s", str);
-    if (str != NULL)
-	xmlFree(str);
-
-    if ((ctxt != NULL) && (input != NULL)) {
-	xmlParserPrintFileContext(input);
-    }
+    xmlFormatError(&ctxt->lastError, xmlGenericError, xmlGenericErrorContext);
 }
 
 /**
@@ -943,30 +846,11 @@
  * position and extra parameters.
  */
 void
-xmlParserValidityWarning(void *ctx, const char *msg, ...)
+xmlParserValidityWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
 {
-    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
-    xmlParserInputPtr input = NULL;
-    char * str;
-    int len = xmlStrlen((const xmlChar *) msg);
+    xmlParserCtxtPtr ctxt = ctx;
 
-    if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
-	input = ctxt->input;
-	if ((input->filename == NULL) && (ctxt->inputNr > 1))
-	    input = ctxt->inputTab[ctxt->inputNr - 2];
-
-	xmlParserPrintFileInfo(input);
-    }
-
-    xmlGenericError(xmlGenericErrorContext, "validity warning: ");
-    XML_GET_VAR_STR(msg, str);
-    xmlGenericError(xmlGenericErrorContext, "%s", str);
-    if (str != NULL)
-	xmlFree(str);
-
-    if (ctxt != NULL) {
-	xmlParserPrintFileContext(input);
-    }
+    xmlFormatError(&ctxt->lastError, xmlGenericError, xmlGenericErrorContext);
 }
 
 
@@ -1084,75 +968,349 @@
  */
 int
 xmlCopyError(const xmlError *from, xmlErrorPtr to) {
-    char *message = NULL;
-    char *file = NULL;
-    char *str1 = NULL;
-    char *str2 = NULL;
-    char *str3 = NULL;
+    const char *fmt = NULL;
 
     if ((from == NULL) || (to == NULL))
         return(-1);
 
-    if (from->message != NULL) {
-        message = (char *) xmlStrdup((xmlChar *) from->message);
-        if (message == NULL)
-            goto err_memory;
-    }
-    if (from->file != NULL) {
-        file = (char *) xmlStrdup ((xmlChar *) from->file);
-        if (file == NULL)
-            goto err_memory;
-    }
-    if (from->str1 != NULL) {
-        str1 = (char *) xmlStrdup ((xmlChar *) from->str1);
-        if (str1 == NULL)
-            goto err_memory;
-    }
-    if (from->str2 != NULL) {
-        str2 = (char *) xmlStrdup ((xmlChar *) from->str2);
-        if (str2 == NULL)
-            goto err_memory;
-    }
-    if (from->str3 != NULL) {
-        str3 = (char *) xmlStrdup ((xmlChar *) from->str3);
-        if (str3 == NULL)
-            goto err_memory;
-    }
+    if (from->message != NULL)
+        fmt = "%s";
 
-    if (to->message != NULL)
-        xmlFree(to->message);
-    if (to->file != NULL)
-        xmlFree(to->file);
-    if (to->str1 != NULL)
-        xmlFree(to->str1);
-    if (to->str2 != NULL)
-        xmlFree(to->str2);
-    if (to->str3 != NULL)
-        xmlFree(to->str3);
-    to->domain = from->domain;
-    to->code = from->code;
-    to->level = from->level;
-    to->line = from->line;
-    to->node = from->node;
-    to->int1 = from->int1;
-    to->int2 = from->int2;
-    to->node = from->node;
-    to->ctxt = from->ctxt;
-    to->message = message;
-    to->file = file;
-    to->str1 = str1;
-    to->str2 = str2;
-    to->str3 = str3;
-
-    return 0;
-
-err_memory:
-    xmlFree(message);
-    xmlFree(file);
-    xmlFree(str1);
-    xmlFree(str2);
-    xmlFree(str3);
-
-    return -1;
+    return(xmlSetError(to, from->ctxt, from->node,
+                       from->domain, from->code, from->level,
+                       from->file, from->line,
+                       from->str1, from->str2, from->str3,
+                       from->int1, from->int2,
+                       fmt, from->message));
 }
 
+/**
+ * xmlErrString:
+ * @code:  an xmlParserErrors code
+ *
+ * Returns an error message for a code.
+ */
+const char *
+xmlErrString(xmlParserErrors code) {
+    const char *errmsg;
+
+    switch (code) {
+        case XML_ERR_INVALID_HEX_CHARREF:
+            errmsg = "CharRef: invalid hexadecimal value";
+            break;
+        case XML_ERR_INVALID_DEC_CHARREF:
+            errmsg = "CharRef: invalid decimal value";
+            break;
+        case XML_ERR_INVALID_CHARREF:
+            errmsg = "CharRef: invalid value";
+            break;
+        case XML_ERR_INTERNAL_ERROR:
+            errmsg = "internal error";
+            break;
+        case XML_ERR_PEREF_AT_EOF:
+            errmsg = "PEReference at end of document";
+            break;
+        case XML_ERR_PEREF_IN_PROLOG:
+            errmsg = "PEReference in prolog";
+            break;
+        case XML_ERR_PEREF_IN_EPILOG:
+            errmsg = "PEReference in epilog";
+            break;
+        case XML_ERR_PEREF_NO_NAME:
+            errmsg = "PEReference: no name";
+            break;
+        case XML_ERR_PEREF_SEMICOL_MISSING:
+            errmsg = "PEReference: expecting ';'";
+            break;
+        case XML_ERR_ENTITY_LOOP:
+            errmsg = "Detected an entity reference loop";
+            break;
+        case XML_ERR_ENTITY_NOT_STARTED:
+            errmsg = "EntityValue: \" or ' expected";
+            break;
+        case XML_ERR_ENTITY_PE_INTERNAL:
+            errmsg = "PEReferences forbidden in internal subset";
+            break;
+        case XML_ERR_ENTITY_NOT_FINISHED:
+            errmsg = "EntityValue: \" or ' expected";
+            break;
+        case XML_ERR_ATTRIBUTE_NOT_STARTED:
+            errmsg = "AttValue: \" or ' expected";
+            break;
+        case XML_ERR_LT_IN_ATTRIBUTE:
+            errmsg = "Unescaped '<' not allowed in attributes values";
+            break;
+        case XML_ERR_LITERAL_NOT_STARTED:
+            errmsg = "SystemLiteral \" or ' expected";
+            break;
+        case XML_ERR_LITERAL_NOT_FINISHED:
+            errmsg = "Unfinished System or Public ID \" or ' expected";
+            break;
+        case XML_ERR_MISPLACED_CDATA_END:
+            errmsg = "Sequence ']]>' not allowed in content";
+            break;
+        case XML_ERR_URI_REQUIRED:
+            errmsg = "SYSTEM or PUBLIC, the URI is missing";
+            break;
+        case XML_ERR_PUBID_REQUIRED:
+            errmsg = "PUBLIC, the Public Identifier is missing";
+            break;
+        case XML_ERR_HYPHEN_IN_COMMENT:
+            errmsg = "Comment must not contain '--' (double-hyphen)";
+            break;
+        case XML_ERR_PI_NOT_STARTED:
+            errmsg = "xmlParsePI : no target name";
+            break;
+        case XML_ERR_RESERVED_XML_NAME:
+            errmsg = "Invalid PI name";
+            break;
+        case XML_ERR_NOTATION_NOT_STARTED:
+            errmsg = "NOTATION: Name expected here";
+            break;
+        case XML_ERR_NOTATION_NOT_FINISHED:
+            errmsg = "'>' required to close NOTATION declaration";
+            break;
+        case XML_ERR_VALUE_REQUIRED:
+            errmsg = "Entity value required";
+            break;
+        case XML_ERR_URI_FRAGMENT:
+            errmsg = "Fragment not allowed";
+            break;
+        case XML_ERR_ATTLIST_NOT_STARTED:
+            errmsg = "'(' required to start ATTLIST enumeration";
+            break;
+        case XML_ERR_NMTOKEN_REQUIRED:
+            errmsg = "NmToken expected in ATTLIST enumeration";
+            break;
+        case XML_ERR_ATTLIST_NOT_FINISHED:
+            errmsg = "')' required to finish ATTLIST enumeration";
+            break;
+        case XML_ERR_MIXED_NOT_STARTED:
+            errmsg = "MixedContentDecl : '|' or ')*' expected";
+            break;
+        case XML_ERR_PCDATA_REQUIRED:
+            errmsg = "MixedContentDecl : '#PCDATA' expected";
+            break;
+        case XML_ERR_ELEMCONTENT_NOT_STARTED:
+            errmsg = "ContentDecl : Name or '(' expected";
+            break;
+        case XML_ERR_ELEMCONTENT_NOT_FINISHED:
+            errmsg = "ContentDecl : ',' '|' or ')' expected";
+            break;
+        case XML_ERR_PEREF_IN_INT_SUBSET:
+            errmsg =
+                "PEReference: forbidden within markup decl in internal subset";
+            break;
+        case XML_ERR_GT_REQUIRED:
+            errmsg = "expected '>'";
+            break;
+        case XML_ERR_CONDSEC_INVALID:
+            errmsg = "XML conditional section '[' expected";
+            break;
+        case XML_ERR_INT_SUBSET_NOT_FINISHED:
+            errmsg = "Content error in the internal subset";
+            break;
+        case XML_ERR_EXT_SUBSET_NOT_FINISHED:
+            errmsg = "Content error in the external subset";
+            break;
+        case XML_ERR_CONDSEC_INVALID_KEYWORD:
+            errmsg =
+                "conditional section INCLUDE or IGNORE keyword expected";
+            break;
+        case XML_ERR_CONDSEC_NOT_FINISHED:
+            errmsg = "XML conditional section not closed";
+            break;
+        case XML_ERR_XMLDECL_NOT_STARTED:
+            errmsg = "Text declaration '<?xml' required";
+            break;
+        case XML_ERR_XMLDECL_NOT_FINISHED:
+            errmsg = "parsing XML declaration: '?>' expected";
+            break;
+        case XML_ERR_EXT_ENTITY_STANDALONE:
+            errmsg = "external parsed entities cannot be standalone";
+            break;
+        case XML_ERR_ENTITYREF_SEMICOL_MISSING:
+            errmsg = "EntityRef: expecting ';'";
+            break;
+        case XML_ERR_DOCTYPE_NOT_FINISHED:
+            errmsg = "DOCTYPE improperly terminated";
+            break;
+        case XML_ERR_LTSLASH_REQUIRED:
+            errmsg = "EndTag: '</' not found";
+            break;
+        case XML_ERR_EQUAL_REQUIRED:
+            errmsg = "expected '='";
+            break;
+        case XML_ERR_STRING_NOT_CLOSED:
+            errmsg = "String not closed expecting \" or '";
+            break;
+        case XML_ERR_STRING_NOT_STARTED:
+            errmsg = "String not started expecting ' or \"";
+            break;
+        case XML_ERR_ENCODING_NAME:
+            errmsg = "Invalid XML encoding name";
+            break;
+        case XML_ERR_STANDALONE_VALUE:
+            errmsg = "standalone accepts only 'yes' or 'no'";
+            break;
+        case XML_ERR_DOCUMENT_EMPTY:
+            errmsg = "Document is empty";
+            break;
+        case XML_ERR_DOCUMENT_END:
+            errmsg = "Extra content at the end of the document";
+            break;
+        case XML_ERR_NOT_WELL_BALANCED:
+            errmsg = "chunk is not well balanced";
+            break;
+        case XML_ERR_EXTRA_CONTENT:
+            errmsg = "extra content at the end of well balanced chunk";
+            break;
+        case XML_ERR_VERSION_MISSING:
+            errmsg = "Malformed declaration expecting version";
+            break;
+        case XML_ERR_NAME_TOO_LONG:
+            errmsg = "Name too long";
+            break;
+        case XML_ERR_INVALID_ENCODING:
+            errmsg = "Invalid bytes in character encoding";
+            break;
+        case XML_ERR_RESOURCE_LIMIT:
+            errmsg = "Resource limit exceeded";
+            break;
+        case XML_ERR_ARGUMENT:
+            errmsg = "Invalid argument";
+            break;
+        case XML_ERR_SYSTEM:
+            errmsg = "Out of system resources";
+            break;
+        case XML_ERR_REDECL_PREDEF_ENTITY:
+            errmsg = "Invalid redeclaration of predefined entity";
+            break;
+        case XML_ERR_UNSUPPORTED_ENCODING:
+            errmsg = "Unsupported encoding";
+            break;
+        case XML_ERR_INVALID_CHAR:
+            errmsg = "Invalid character";
+            break;
+
+        case XML_IO_UNKNOWN:
+            errmsg = "Unknown IO error"; break;
+        case XML_IO_EACCES:
+            errmsg = "Permission denied"; break;
+        case XML_IO_EAGAIN:
+            errmsg = "Resource temporarily unavailable"; break;
+        case XML_IO_EBADF:
+            errmsg = "Bad file descriptor"; break;
+        case XML_IO_EBADMSG:
+            errmsg = "Bad message"; break;
+        case XML_IO_EBUSY:
+            errmsg = "Resource busy"; break;
+        case XML_IO_ECANCELED:
+            errmsg = "Operation canceled"; break;
+        case XML_IO_ECHILD:
+            errmsg = "No child processes"; break;
+        case XML_IO_EDEADLK:
+            errmsg = "Resource deadlock avoided"; break;
+        case XML_IO_EDOM:
+            errmsg = "Domain error"; break;
+        case XML_IO_EEXIST:
+            errmsg = "File exists"; break;
+        case XML_IO_EFAULT:
+            errmsg = "Bad address"; break;
+        case XML_IO_EFBIG:
+            errmsg = "File too large"; break;
+        case XML_IO_EINPROGRESS:
+            errmsg = "Operation in progress"; break;
+        case XML_IO_EINTR:
+            errmsg = "Interrupted function call"; break;
+        case XML_IO_EINVAL:
+            errmsg = "Invalid argument"; break;
+        case XML_IO_EIO:
+            errmsg = "Input/output error"; break;
+        case XML_IO_EISDIR:
+            errmsg = "Is a directory"; break;
+        case XML_IO_EMFILE:
+            errmsg = "Too many open files"; break;
+        case XML_IO_EMLINK:
+            errmsg = "Too many links"; break;
+        case XML_IO_EMSGSIZE:
+            errmsg = "Inappropriate message buffer length"; break;
+        case XML_IO_ENAMETOOLONG:
+            errmsg = "Filename too long"; break;
+        case XML_IO_ENFILE:
+            errmsg = "Too many open files in system"; break;
+        case XML_IO_ENODEV:
+            errmsg = "No such device"; break;
+        case XML_IO_ENOENT:
+            errmsg = "No such file or directory"; break;
+        case XML_IO_ENOEXEC:
+            errmsg = "Exec format error"; break;
+        case XML_IO_ENOLCK:
+            errmsg = "No locks available"; break;
+        case XML_IO_ENOMEM:
+            errmsg = "Not enough space"; break;
+        case XML_IO_ENOSPC:
+            errmsg = "No space left on device"; break;
+        case XML_IO_ENOSYS:
+            errmsg = "Function not implemented"; break;
+        case XML_IO_ENOTDIR:
+            errmsg = "Not a directory"; break;
+        case XML_IO_ENOTEMPTY:
+            errmsg = "Directory not empty"; break;
+        case XML_IO_ENOTSUP:
+            errmsg = "Not supported"; break;
+        case XML_IO_ENOTTY:
+            errmsg = "Inappropriate I/O control operation"; break;
+        case XML_IO_ENXIO:
+            errmsg = "No such device or address"; break;
+        case XML_IO_EPERM:
+            errmsg = "Operation not permitted"; break;
+        case XML_IO_EPIPE:
+            errmsg = "Broken pipe"; break;
+        case XML_IO_ERANGE:
+            errmsg = "Result too large"; break;
+        case XML_IO_EROFS:
+            errmsg = "Read-only file system"; break;
+        case XML_IO_ESPIPE:
+            errmsg = "Invalid seek"; break;
+        case XML_IO_ESRCH:
+            errmsg = "No such process"; break;
+        case XML_IO_ETIMEDOUT:
+            errmsg = "Operation timed out"; break;
+        case XML_IO_EXDEV:
+            errmsg = "Improper link"; break;
+        case XML_IO_NETWORK_ATTEMPT:
+            errmsg = "Attempt to load network entity"; break;
+        case XML_IO_ENCODER:
+            errmsg = "encoder error"; break;
+        case XML_IO_FLUSH:
+            errmsg = "flush error"; break;
+        case XML_IO_WRITE:
+            errmsg = "write error"; break;
+        case XML_IO_NO_INPUT:
+            errmsg = "no input"; break;
+        case XML_IO_BUFFER_FULL:
+            errmsg = "buffer full"; break;
+        case XML_IO_LOAD_ERROR:
+            errmsg = "loading error"; break;
+        case XML_IO_ENOTSOCK:
+            errmsg = "not a socket"; break;
+        case XML_IO_EISCONN:
+            errmsg = "already connected"; break;
+        case XML_IO_ECONNREFUSED:
+            errmsg = "connection refused"; break;
+        case XML_IO_ENETUNREACH:
+            errmsg = "unreachable network"; break;
+        case XML_IO_EADDRINUSE:
+            errmsg = "address in use"; break;
+        case XML_IO_EALREADY:
+            errmsg = "already in use"; break;
+        case XML_IO_EAFNOSUPPORT:
+            errmsg = "unknown address family"; break;
+
+        default:
+            errmsg = "Unregistered error message";
+    }
+
+    return(errmsg);
+}
diff --git a/src/globals.c b/src/globals.c
index 04e7964..affbf6a 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -26,6 +26,7 @@
 #include <libxml/SAX.h>
 #include <libxml/SAX2.h>
 
+#include "private/dict.h"
 #include "private/error.h"
 #include "private/globals.h"
 #include "private/threads.h"
@@ -75,6 +76,10 @@
     void *waitHandle;
 #endif
 
+#ifdef LIBXML_THREAD_ENABLED
+    unsigned localRngState[2];
+#endif
+
 #define XML_OP XML_DECLARE_MEMBER
 XML_GLOBALS_ALLOC
 XML_GLOBALS_ERROR
@@ -162,6 +167,10 @@
  *									*
  ************************************************************************/
 
+#ifdef LIBXML_THREAD_ENABLED
+static unsigned xmlMainThreadRngState[2];
+#endif
+
 /*
  * Memory allocation routines
  */
@@ -272,8 +281,7 @@
  * while handling entities.
  * Disabled by default
  */
-int xmlParserDebugEntities = 0;
-static int xmlParserDebugEntitiesThrDef = 0;
+const int xmlParserDebugEntities = 0;
 /**
  * xmlDoValidityCheckingDefaultValue:
  *
@@ -287,7 +295,7 @@
 /**
  * xmlGetWarningsDefaultValue:
  *
- * DEPRECATED: Don't use
+ * DEPRECATED: Use the modern options API with XML_PARSE_NOWARNING.
  *
  * Global setting, indicate that the DTD validation should provide warnings.
  * Activated by default.
@@ -594,6 +602,11 @@
 #endif
     mainthread = GetCurrentThreadId();
 #endif
+
+#ifdef LIBXML_THREAD_ENABLED
+    xmlMainThreadRngState[0] = xmlGlobalRandom();
+    xmlMainThreadRngState[1] = xmlGlobalRandom();
+#endif
 }
 
 /**
@@ -754,6 +767,11 @@
 xmlInitGlobalState(xmlGlobalStatePtr gs) {
     xmlMutexLock(&xmlThrDefMutex);
 
+#ifdef LIBXML_THREAD_ENABLED
+    gs->localRngState[0] = xmlGlobalRandom();
+    gs->localRngState[1] = xmlGlobalRandom();
+#endif
+
     gs->gs_xmlBufferAllocScheme = xmlBufferAllocSchemeThrDef;
     gs->gs_xmlDefaultBufferSize = xmlDefaultBufferSizeThrDef;
     gs->gs_xmlDoValidityCheckingDefaultValue =
@@ -782,7 +800,6 @@
     gs->gs_xmlKeepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef;
     gs->gs_xmlLineNumbersDefaultValue = xmlLineNumbersDefaultValueThrDef;
     gs->gs_xmlLoadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef;
-    gs->gs_xmlParserDebugEntities = xmlParserDebugEntitiesThrDef;
     gs->gs_xmlPedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef;
     gs->gs_xmlSubstituteEntitiesDefaultValue =
         xmlSubstituteEntitiesDefaultValueThrDef;
@@ -895,6 +912,16 @@
 XML_GLOBALS_TREE
 #undef XML_OP
 
+#ifdef LIBXML_THREAD_ENABLED
+unsigned *
+xmlGetLocalRngState(void) {
+    if (IS_MAIN_THREAD)
+        return(xmlMainThreadRngState);
+    else
+        return(xmlGetThreadLocalStorage(0)->localRngState);
+}
+#endif
+
 /* For backward compatibility */
 
 const char *const *
@@ -907,6 +934,11 @@
     return &oldXMLWDcompatibility;
 }
 
+const int *
+__xmlParserDebugEntities(void) {
+    return &xmlParserDebugEntities;
+}
+
 const xmlSAXLocator *
 __xmlDefaultSAXLocator(void) {
     return &xmlDefaultSAXLocator;
@@ -1124,13 +1156,8 @@
     return ret;
 }
 
-int xmlThrDefParserDebugEntities(int v) {
-    int ret;
-    xmlMutexLock(&xmlThrDefMutex);
-    ret = xmlParserDebugEntitiesThrDef;
-    xmlParserDebugEntitiesThrDef = v;
-    xmlMutexUnlock(&xmlThrDefMutex);
-    return ret;
+int xmlThrDefParserDebugEntities(int v ATTRIBUTE_UNUSED) {
+    return(xmlParserDebugEntities);
 }
 
 int xmlThrDefPedanticParserDefaultValue(int v) {
diff --git a/src/include/libxml/HTMLparser.h b/src/include/libxml/HTMLparser.h
index 0e97425..952a363 100644
--- a/src/include/libxml/HTMLparser.h
+++ b/src/include/libxml/HTMLparser.h
@@ -247,6 +247,9 @@
 					 const char *encoding,
 					 int options);
 XMLPUBFUN htmlDocPtr
+		htmlCtxtParseDocument	(htmlParserCtxtPtr ctxt,
+					 xmlParserInputPtr input);
+XMLPUBFUN htmlDocPtr
 		htmlCtxtReadDoc		(xmlParserCtxtPtr ctxt,
 					 const xmlChar *cur,
 					 const char *URL,
diff --git a/src/include/libxml/c14n.h b/src/include/libxml/c14n.h
index f9bdf9b..8ccd1ce 100644
--- a/src/include/libxml/c14n.h
+++ b/src/include/libxml/c14n.h
@@ -39,18 +39,7 @@
  *  a) default attributes (if any) are added to all nodes
  *  b) all character and parsed entity references are resolved
  * In order to achieve this in libxml2 the document MUST be loaded with
- * following global settings:
- *
- *    xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
- *    xmlSubstituteEntitiesDefault(1);
- *
- * or corresponding parser context setting:
- *    xmlParserCtxtPtr ctxt;
- *
- *    ...
- *    ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
- *    ctxt->replaceEntities = 1;
- *    ...
+ * following options: XML_PARSE_DTDATTR | XML_PARSE_NOENT
  */
 
 /*
diff --git a/src/include/libxml/encoding.h b/src/include/libxml/encoding.h
index 4aa4f79..74b83d5 100644
--- a/src/include/libxml/encoding.h
+++ b/src/include/libxml/encoding.h
@@ -167,6 +167,7 @@
 					 xmlCharEncodingHandlerPtr *out);
 XMLPUBFUN int
 	xmlOpenCharEncodingHandler	(const char *name,
+					 int output,
 					 xmlCharEncodingHandlerPtr *out);
 XMLPUBFUN xmlCharEncodingHandlerPtr
 	xmlGetCharEncodingHandler	(xmlCharEncoding enc);
diff --git a/src/include/libxml/entities.h b/src/include/libxml/entities.h
index dd9c05a..96029ba 100644
--- a/src/include/libxml/entities.h
+++ b/src/include/libxml/entities.h
@@ -55,7 +55,7 @@
 
     struct _xmlEntity     *nexte;	/* unused */
     const xmlChar           *URI;	/* the full URI as computed */
-    int                    owner;	/* does the entity own the childrens */
+    int                    owner;	/* unused */
     int                    flags;       /* various flags */
     unsigned long   expandedSize;       /* expanded size */
 };
diff --git a/src/include/libxml/parser.h b/src/include/libxml/parser.h
index 8a029df..b2552c0 100644
--- a/src/include/libxml/parser.h
+++ b/src/include/libxml/parser.h
@@ -60,11 +60,11 @@
     xmlParserInputBufferPtr buf;      /* UTF-8 encoded buffer */
 
     const char *filename;             /* The file analyzed, if any */
-    const char *directory;            /* the directory/base of the file */
+    const char *directory;            /* unused */
     const xmlChar *base;              /* Base of the array to parse */
     const xmlChar *cur;               /* Current char being parsed */
     const xmlChar *end;               /* end of the array to parse */
-    int length;                       /* length if known */
+    int length;                       /* unused */
     int line;                         /* Current line */
     int col;                          /* Current column */
     unsigned long consumed;           /* How many xmlChars already consumed */
@@ -73,7 +73,7 @@
     const xmlChar *version;           /* the version string for entity */
     int flags;                        /* Flags */
     int id;                           /* an unique identifier for the entity */
-    unsigned long parentConsumed;     /* consumed bytes from parents */
+    unsigned long parentConsumed;     /* unused */
     xmlEntityPtr entity;              /* entity, if any */
 };
 
@@ -132,30 +132,14 @@
     XML_PARSER_XML_DECL         /* before XML decl (but after BOM) */
 } xmlParserInputState;
 
-/**
- * XML_DETECT_IDS:
- *
- * Bit in the loadsubset context field to tell to do ID/REFs lookups.
- * Use it to initialize xmlLoadExtDtdDefaultValue.
+/** DOC_DISABLE */
+/*
+ * Internal bits in the 'loadsubset' context member
  */
 #define XML_DETECT_IDS		2
-
-/**
- * XML_COMPLETE_ATTRS:
- *
- * Bit in the loadsubset context field to tell to do complete the
- * elements attributes lists with the ones defaulted from the DTDs.
- * Use it to initialize xmlLoadExtDtdDefaultValue.
- */
 #define XML_COMPLETE_ATTRS	4
-
-/**
- * XML_SKIP_IDS:
- *
- * Bit in the loadsubset context field to tell to not do ID/REFs registration.
- * Used to initialize xmlLoadExtDtdDefaultValue in some special cases.
- */
 #define XML_SKIP_IDS		8
+/** DOC_ENABLE */
 
 /**
  * xmlParserMode:
@@ -220,16 +204,16 @@
 
     int     hasExternalSubset;        /* reference and external subset */
     int             hasPErefs;        /* the internal subset has PE refs */
-    int              external;        /* are we parsing an external entity */
+    int              external;        /* unused */
 
     int                 valid;        /* is the document valid */
     int              validate;        /* shall we try to validate ? */
     xmlValidCtxt        vctxt;        /* The validity context */
 
-    xmlParserInputState instate;      /* current type of input */
-    int                 token;        /* next char look-ahead */
+    xmlParserInputState instate;      /* push parser state */
+    int                 token;        /* unused */
 
-    char           *directory;        /* the data directory */
+    char           *directory;        /* unused */
 
     /* Node name stack */
     const xmlChar     *name;          /* Current parsed Node */
@@ -253,7 +237,7 @@
     int *              spaceTab;      /* array of space infos */
 
     int                depth;         /* to prevent entity substitution loops */
-    xmlParserInputPtr  entity;        /* used to check entities boundaries */
+    xmlParserInputPtr  entity;        /* unused */
     int                charset;       /* unused */
     int                nodelen;       /* Those two fields are there to */
     int                nodemem;       /* Speed up large node parsing */
@@ -264,11 +248,11 @@
     int                linenumbers;   /* set line number in element content */
     void              *catalogs;      /* document's own catalog */
     int                recovery;      /* run in recovery mode */
-    int                progressive;   /* is this a progressive parsing */
+    int                progressive;   /* unused */
     xmlDictPtr         dict;          /* dictionary for the parser */
     const xmlChar *   *atts;          /* array for the attributes callbacks */
     int                maxatts;       /* the size of the array */
-    int                docdict;       /* use strings from dict to build tree */
+    int                docdict;       /* unused */
 
     /*
      * pre-interned strings
@@ -306,7 +290,7 @@
     xmlError          lastError;
     xmlParserMode     parseMode;    /* the parser mode */
     unsigned long    nbentities;    /* unused */
-    unsigned long  sizeentities;    /* size of parsed entities */
+    unsigned long  sizeentities;    /* size of external entities */
 
     /* for use by HTML non-recursive parser */
     xmlParserNodeInfo *nodeInfo;      /* Current NodeInfo */
@@ -325,6 +309,9 @@
     xmlParserNsData       *nsdb;    /* namespace database */
     unsigned        attrHashMax;    /* allocated size */
     xmlAttrHashBucket *attrHash;    /* atttribute hash table */
+
+    xmlStructuredErrorFunc errorHandler;
+    void *errorCtxt;
 };
 
 /**
@@ -844,6 +831,8 @@
 XML_DEPRECATED
 XMLPUBVAR const int oldXMLWDcompatibility;
 XML_DEPRECATED
+XMLPUBVAR const int xmlParserDebugEntities;
+XML_DEPRECATED
 XMLPUBVAR const xmlSAXLocator xmlDefaultSAXLocator;
 #ifdef LIBXML_SAX1_ENABLED
 XML_DEPRECATED
@@ -856,6 +845,8 @@
 XML_DEPRECATED
 XMLPUBFUN const int *__oldXMLWDcompatibility(void);
 XML_DEPRECATED
+XMLPUBFUN const int *__xmlParserDebugEntities(void);
+XML_DEPRECATED
 XMLPUBFUN const xmlSAXLocator *__xmlDefaultSAXLocator(void);
 #ifdef LIBXML_SAX1_ENABLED
 XML_DEPRECATED
@@ -864,18 +855,27 @@
 #endif
 
 /** DOC_DISABLE */
-#define XML_GLOBALS_PARSER \
+#define XML_GLOBALS_PARSER_CORE \
   XML_OP(xmlDoValidityCheckingDefaultValue, int, XML_DEPRECATED) \
   XML_OP(xmlGetWarningsDefaultValue, int, XML_DEPRECATED) \
   XML_OP(xmlKeepBlanksDefaultValue, int, XML_DEPRECATED) \
   XML_OP(xmlLineNumbersDefaultValue, int, XML_DEPRECATED) \
   XML_OP(xmlLoadExtDtdDefaultValue, int, XML_DEPRECATED) \
-  XML_OP(xmlParserDebugEntities, int, XML_DEPRECATED) \
   XML_OP(xmlPedanticParserDefaultValue, int, XML_DEPRECATED) \
-  XML_OP(xmlSubstituteEntitiesDefaultValue, int, XML_DEPRECATED) \
-  XML_OP(xmlIndentTreeOutput, int, XML_NO_ATTR) \
-  XML_OP(xmlTreeIndentString, const char *, XML_NO_ATTR) \
-  XML_OP(xmlSaveNoEmptyTags, int, XML_NO_ATTR)
+  XML_OP(xmlSubstituteEntitiesDefaultValue, int, XML_DEPRECATED)
+
+#ifdef LIBXML_OUTPUT_ENABLED
+  #define XML_GLOBALS_PARSER_OUTPUT \
+    XML_OP(xmlIndentTreeOutput, int, XML_NO_ATTR) \
+    XML_OP(xmlTreeIndentString, const char *, XML_NO_ATTR) \
+    XML_OP(xmlSaveNoEmptyTags, int, XML_NO_ATTR)
+#else
+  #define XML_GLOBALS_PARSER_OUTPUT
+#endif
+
+#define XML_GLOBALS_PARSER \
+  XML_GLOBALS_PARSER_CORE \
+  XML_GLOBALS_PARSER_OUTPUT
 
 #define XML_OP XML_DECLARE_GLOBAL
 XML_GLOBALS_PARSER
@@ -893,14 +893,15 @@
   #define xmlLineNumbersDefaultValue \
     XML_GLOBAL_MACRO(xmlLineNumbersDefaultValue)
   #define xmlLoadExtDtdDefaultValue XML_GLOBAL_MACRO(xmlLoadExtDtdDefaultValue)
-  #define xmlParserDebugEntities XML_GLOBAL_MACRO(xmlParserDebugEntities)
   #define xmlPedanticParserDefaultValue \
     XML_GLOBAL_MACRO(xmlPedanticParserDefaultValue)
   #define xmlSubstituteEntitiesDefaultValue \
     XML_GLOBAL_MACRO(xmlSubstituteEntitiesDefaultValue)
-  #define xmlIndentTreeOutput XML_GLOBAL_MACRO(xmlIndentTreeOutput)
-  #define xmlTreeIndentString XML_GLOBAL_MACRO(xmlTreeIndentString)
-  #define xmlSaveNoEmptyTags XML_GLOBAL_MACRO(xmlSaveNoEmptyTags)
+  #ifdef LIBXML_OUTPUT_ENABLED
+    #define xmlIndentTreeOutput XML_GLOBAL_MACRO(xmlIndentTreeOutput)
+    #define xmlTreeIndentString XML_GLOBAL_MACRO(xmlTreeIndentString)
+    #define xmlSaveNoEmptyTags XML_GLOBAL_MACRO(xmlSaveNoEmptyTags)
+  #endif
 #endif
 /** DOC_ENABLE */
 
@@ -1246,7 +1247,8 @@
     XML_PARSE_HUGE      = 1<<19,/* relax any hardcoded limit from the parser */
     XML_PARSE_OLDSAX    = 1<<20,/* parse using SAX2 interface before 2.7.0 */
     XML_PARSE_IGNORE_ENC= 1<<21,/* ignore internal document encoding hint */
-    XML_PARSE_BIG_LINES = 1<<22 /* Store big lines numbers in text PSVI field */
+    XML_PARSE_BIG_LINES = 1<<22,/* Store big lines numbers in text PSVI field */
+    XML_PARSE_NO_XXE    = 1<<23 /* disable loading of external content */
 } xmlParserOption;
 
 XMLPUBFUN void
@@ -1258,9 +1260,16 @@
 					 const char *filename,
 					 const char *encoding);
 XMLPUBFUN int
+		xmlCtxtSetOptions	(xmlParserCtxtPtr ctxt,
+					 int options);
+XMLPUBFUN int
 		xmlCtxtUseOptions	(xmlParserCtxtPtr ctxt,
 					 int options);
 XMLPUBFUN void
+		xmlCtxtSetErrorHandler	(xmlParserCtxtPtr ctxt,
+					 xmlStructuredErrorFunc handler,
+					 void *data);
+XMLPUBFUN void
 		xmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt,
 					 unsigned maxAmpl);
 XMLPUBFUN xmlDocPtr
@@ -1291,6 +1300,9 @@
 					 const char *encoding,
 					 int options);
 XMLPUBFUN xmlDocPtr
+		xmlCtxtParseDocument	(xmlParserCtxtPtr ctxt,
+					 xmlParserInputPtr input);
+XMLPUBFUN xmlDocPtr
 		xmlCtxtReadDoc		(xmlParserCtxtPtr ctxt,
 					 const xmlChar *cur,
 					 const char *URL,
@@ -1363,7 +1375,7 @@
     XML_WITH_MODULES = 27,
     XML_WITH_DEBUG = 28,
     XML_WITH_DEBUG_MEM = 29,
-    XML_WITH_DEBUG_RUN = 30,
+    XML_WITH_DEBUG_RUN = 30, /* unused */
     XML_WITH_ZLIB = 31,
     XML_WITH_ICU = 32,
     XML_WITH_LZMA = 33,
diff --git a/src/include/libxml/parserInternals.h b/src/include/libxml/parserInternals.h
index 6b59529..a5ca057 100644
--- a/src/include/libxml/parserInternals.h
+++ b/src/include/libxml/parserInternals.h
@@ -25,11 +25,14 @@
 /**
  * xmlParserMaxDepth:
  *
+ * DEPRECATED: has no effect
+ *
  * arbitrary depth limit for the XML documents that we allow to
  * process. This is not a limitation of the parser but a safety
  * boundary feature, use XML_PARSE_HUGE option to override it.
  */
-XMLPUBVAR unsigned int xmlParserMaxDepth;
+XML_DEPRECATED
+XMLPUBVAR const unsigned int xmlParserMaxDepth;
 
 /**
  * XML_MAX_TEXT_LENGTH:
@@ -313,12 +316,18 @@
 			xmlCreateEntityParserCtxt(const xmlChar *URL,
 						 const xmlChar *ID,
 						 const xmlChar *base);
-XMLPUBFUN void xmlErrMemory(xmlParserCtxtPtr ctxt, const char* extra);
+XMLPUBFUN void
+			xmlCtxtErrMemory	(xmlParserCtxtPtr ctxt);
+XMLPUBFUN void
+			xmlCtxtErrIO		(xmlParserCtxtPtr ctxt,
+						 int code,
+						 const char *uri);
 XMLPUBFUN int
 			xmlSwitchEncoding	(xmlParserCtxtPtr ctxt,
 						 xmlCharEncoding enc);
-XMLPUBFUN int xmlSwitchEncodingName(xmlParserCtxtPtr ctxt,
-                                    const char* encoding);
+XMLPUBFUN int
+			xmlSwitchEncodingName	(xmlParserCtxtPtr ctxt,
+						 const char *encoding);
 XMLPUBFUN int
 			xmlSwitchToEncoding	(xmlParserCtxtPtr ctxt,
 					 xmlCharEncodingHandlerPtr handler);
diff --git a/src/include/libxml/valid.h b/src/include/libxml/valid.h
index 0ea5cfa..10d6d19 100644
--- a/src/include/libxml/valid.h
+++ b/src/include/libxml/valid.h
@@ -148,9 +148,11 @@
 XMLPUBFUN void
 		xmlFreeNotationTable	(xmlNotationTablePtr table);
 #ifdef LIBXML_OUTPUT_ENABLED
+XML_DEPRECATED
 XMLPUBFUN void
 		xmlDumpNotationDecl	(xmlBufferPtr buf,
 					 xmlNotationPtr nota);
+/* XML_DEPRECATED, still used in lxml */
 XMLPUBFUN void
 		xmlDumpNotationTable	(xmlBufferPtr buf,
 					 xmlNotationTablePtr table);
@@ -182,13 +184,12 @@
 	                                 xmlElementContentPtr content,
 					 int englob);
 #ifdef LIBXML_OUTPUT_ENABLED
-/* DEPRECATED */
+XML_DEPRECATED
 XMLPUBFUN void
 		xmlSprintfElementContent(char *buf,
 	                                 xmlElementContentPtr content,
 					 int englob);
 #endif /* LIBXML_OUTPUT_ENABLED */
-/* DEPRECATED */
 
 /* Element */
 XMLPUBFUN xmlElementPtr
@@ -204,9 +205,11 @@
 XMLPUBFUN void
 		xmlFreeElementTable	(xmlElementTablePtr table);
 #ifdef LIBXML_OUTPUT_ENABLED
+XML_DEPRECATED
 XMLPUBFUN void
 		xmlDumpElementTable	(xmlBufferPtr buf,
 					 xmlElementTablePtr table);
+XML_DEPRECATED
 XMLPUBFUN void
 		xmlDumpElementDecl	(xmlBufferPtr buf,
 					 xmlElementPtr elem);
@@ -240,9 +243,11 @@
 XMLPUBFUN void
 		xmlFreeAttributeTable  (xmlAttributeTablePtr table);
 #ifdef LIBXML_OUTPUT_ENABLED
+XML_DEPRECATED
 XMLPUBFUN void
 		xmlDumpAttributeTable  (xmlBufferPtr buf,
 					xmlAttributeTablePtr table);
+XML_DEPRECATED
 XMLPUBFUN void
 		xmlDumpAttributeDecl   (xmlBufferPtr buf,
 					xmlAttributePtr attr);
diff --git a/src/include/libxml/xinclude.h b/src/include/libxml/xinclude.h
index e1d135b..6a67953 100644
--- a/src/include/libxml/xinclude.h
+++ b/src/include/libxml/xinclude.h
@@ -116,6 +116,12 @@
 		xmlXIncludeSetFlags	(xmlXIncludeCtxtPtr ctxt,
 					 int flags);
 XMLPUBFUN void
+		xmlXIncludeSetErrorHandler(xmlXIncludeCtxtPtr ctxt,
+					 xmlStructuredErrorFunc handler,
+					 void *data);
+XMLPUBFUN int
+		xmlXIncludeGetLastError	(xmlXIncludeCtxtPtr ctxt);
+XMLPUBFUN void
 		xmlXIncludeFreeContext	(xmlXIncludeCtxtPtr ctxt);
 XMLPUBFUN int
 		xmlXIncludeProcessNode	(xmlXIncludeCtxtPtr ctxt,
diff --git a/src/include/libxml/xmlIO.h b/src/include/libxml/xmlIO.h
index 7e88da5..4165bb3 100644
--- a/src/include/libxml/xmlIO.h
+++ b/src/include/libxml/xmlIO.h
@@ -216,7 +216,6 @@
 XMLPUBFUN xmlParserInputBufferPtr
 	xmlParserInputBufferCreateMem		(const char *mem, int size,
 	                                         xmlCharEncoding enc);
-XML_DEPRECATED
 XMLPUBFUN xmlParserInputBufferPtr
 	xmlParserInputBufferCreateStatic	(const char *mem, int size,
 	                                         xmlCharEncoding enc);
@@ -322,12 +321,14 @@
 
 #ifdef LIBXML_HTTP_ENABLED
 /*  This function only exists if HTTP support built into the library  */
+XML_DEPRECATED
 XMLPUBFUN void
 	xmlRegisterHTTPPostCallbacks	(void );
 #endif /* LIBXML_HTTP_ENABLED */
 
 #endif /* LIBXML_OUTPUT_ENABLED */
 
+XML_DEPRECATED
 XMLPUBFUN xmlParserInputPtr
 	xmlCheckHTTPInput		(xmlParserCtxtPtr ctxt,
 					 xmlParserInputPtr ret);
@@ -340,26 +341,28 @@
 					 const char *ID,
 					 xmlParserCtxtPtr ctxt);
 
-/*
- * xmlNormalizeWindowsPath is obsolete, don't use it.
- * Check xmlCanonicPath in uri.h for a better alternative.
- */
+XML_DEPRECATED
 XMLPUBFUN xmlChar *
 	xmlNormalizeWindowsPath		(const xmlChar *path);
 
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlCheckFilename		(const char *path);
 /**
  * Default 'file://' protocol callbacks
  */
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlFileMatch			(const char *filename);
+XML_DEPRECATED
 XMLPUBFUN void *
 	xmlFileOpen			(const char *filename);
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlFileRead			(void * context,
 					 char * buffer,
 					 int len);
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlFileClose			(void * context);
 
@@ -367,19 +370,24 @@
  * Default 'http://' protocol callbacks
  */
 #ifdef LIBXML_HTTP_ENABLED
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlIOHTTPMatch			(const char *filename);
+XML_DEPRECATED
 XMLPUBFUN void *
 	xmlIOHTTPOpen			(const char *filename);
 #ifdef LIBXML_OUTPUT_ENABLED
+XML_DEPRECATED
 XMLPUBFUN void *
 	xmlIOHTTPOpenW			(const char * post_uri,
 					 int   compression );
 #endif /* LIBXML_OUTPUT_ENABLED */
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlIOHTTPRead			(void * context,
 					 char * buffer,
 					 int len);
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlIOHTTPClose			(void * context);
 #endif /* LIBXML_HTTP_ENABLED */
@@ -388,14 +396,18 @@
  * Default 'ftp://' protocol callbacks
  */
 #if defined(LIBXML_FTP_ENABLED)
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlIOFTPMatch			(const char *filename);
+XML_DEPRECATED
 XMLPUBFUN void *
 	xmlIOFTPOpen			(const char *filename);
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlIOFTPRead			(void * context,
 					 char * buffer,
 					 int len);
+XML_DEPRECATED
 XMLPUBFUN int
 	xmlIOFTPClose			(void * context);
 #endif /* defined(LIBXML_FTP_ENABLED) */
diff --git a/src/include/libxml/xmlerror.h b/src/include/libxml/xmlerror.h
index 0be0b88..373e5f6 100644
--- a/src/include/libxml/xmlerror.h
+++ b/src/include/libxml/xmlerror.h
@@ -215,6 +215,7 @@
     XML_ERR_ARGUMENT, /* 115 */
     XML_ERR_SYSTEM, /* 116 */
     XML_ERR_REDECL_PREDEF_ENTITY, /* 117 */
+    XML_ERR_INT_SUBSET_NOT_FINISHED, /* 118 */
     XML_NS_ERR_XML_NAMESPACE = 200,
     XML_NS_ERR_UNDEFINED_NAMESPACE, /* 201 */
     XML_NS_ERR_QNAME, /* 202 */
@@ -928,6 +929,10 @@
     xmlParserPrintFileInfo	(struct _xmlParserInput *input);
 XMLPUBFUN void
     xmlParserPrintFileContext	(struct _xmlParserInput *input);
+XMLPUBFUN void
+xmlFormatError			(const xmlError *err,
+				 xmlGenericErrorFunc channel,
+				 void *data);
 
 /*
  * Extended error information routines
diff --git a/src/include/libxml/xmlexports.h b/src/include/libxml/xmlexports.h
index 3b063e7..3d90a7e 100644
--- a/src/include/libxml/xmlexports.h
+++ b/src/include/libxml/xmlexports.h
@@ -9,6 +9,11 @@
 #define __XML_EXPORTS_H__
 
 /** DOC_DISABLE */
+
+/*
+ * Symbol visibility
+ */
+
 #if defined(_WIN32) || defined(__CYGWIN__)
   #ifdef LIBXML_STATIC
     #define XMLPUBLIC
@@ -20,30 +25,110 @@
 #else /* not Windows */
   #define XMLPUBLIC
 #endif /* platform switch */
-/** DOC_ENABLE */
 
-/*
- * XMLPUBFUN:
- *
- * Macro which declares an exportable function
- */
 #define XMLPUBFUN XMLPUBLIC
 
-/**
- * XMLPUBVAR:
- *
- * Macro which declares an exportable variable
- */
 #define XMLPUBVAR XMLPUBLIC extern
 
-/** DOC_DISABLE */
 /* Compatibility */
 #define XMLCALL
 #define XMLCDECL
-#if !defined(LIBXML_DLL_IMPORT)
-#define LIBXML_DLL_IMPORT XMLPUBVAR
+#ifndef LIBXML_DLL_IMPORT
+  #define LIBXML_DLL_IMPORT XMLPUBVAR
 #endif
-/** DOC_ENABLE */
+
+/*
+ * Attributes
+ */
+
+#if __GNUC__ * 100 + __GNUC_MINOR__ >= 207
+  #define ATTRIBUTE_UNUSED __attribute__((unused))
+#else
+  #define ATTRIBUTE_UNUSED
+#endif
+
+#if !defined(__clang__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)
+  #define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
+#else
+  #define LIBXML_ATTR_ALLOC_SIZE(x)
+#endif
+
+#if __GNUC__ * 100 + __GNUC_MINOR__ >= 303
+  #define LIBXML_ATTR_FORMAT(fmt,args) \
+    __attribute__((__format__(__printf__,fmt,args)))
+#else
+  #define LIBXML_ATTR_FORMAT(fmt,args)
+#endif
+
+#ifndef XML_DEPRECATED
+  #if defined(IN_LIBXML)
+    #define XML_DEPRECATED
+  #elif __GNUC__ * 100 + __GNUC_MINOR__ >= 301
+    #define XML_DEPRECATED __attribute__((deprecated))
+  #elif _MSC_VER >= 1400
+    /* Available since Visual Studio 2005 */
+    #define XML_DEPRECATED __declspec(deprecated)
+  #else
+    #define XML_DEPRECATED
+  #endif
+#endif
+
+/*
+ * Warnings pragmas, should be moved from public headers
+ */
+
+#if defined(__LCC__)
+
+  #define XML_IGNORE_FPTR_CAST_WARNINGS
+  #define XML_POP_WARNINGS \
+    _Pragma("diag_default 1215")
+
+#elif defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)
+
+  #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800)
+    #define XML_IGNORE_FPTR_CAST_WARNINGS \
+      _Pragma("GCC diagnostic push") \
+      _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
+      _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"")
+  #else
+    #define XML_IGNORE_FPTR_CAST_WARNINGS \
+      _Pragma("GCC diagnostic push") \
+      _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
+  #endif
+  #define XML_POP_WARNINGS \
+    _Pragma("GCC diagnostic pop")
+
+#elif _MSC_VER >= 1400
+
+  #define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push))
+  #define XML_POP_WARNINGS __pragma(warning(pop))
+
+#else
+
+  #define XML_IGNORE_FPTR_CAST_WARNINGS
+  #define XML_POP_WARNINGS
+
+#endif
+
+/*
+ * Accessors for globals
+ */
+
+#define XML_NO_ATTR
+
+#ifdef LIBXML_THREAD_ENABLED
+  #define XML_DECLARE_GLOBAL(name, type, attrs) \
+    attrs XMLPUBFUN type *__##name(void);
+  #define XML_GLOBAL_MACRO(name) (*__##name())
+#else
+  #define XML_DECLARE_GLOBAL(name, type, attrs) \
+    attrs XMLPUBVAR type name;
+#endif
+
+/*
+ * Originally declared in xmlversion.h which is generated
+ */
+XMLPUBFUN void xmlCheckVersion(int version);
 
 #endif /* __XML_EXPORTS_H__ */
 
diff --git a/src/include/libxml/xmlreader.h b/src/include/libxml/xmlreader.h
index b9f6989..5d4fc5d 100644
--- a/src/include/libxml/xmlreader.h
+++ b/src/include/libxml/xmlreader.h
@@ -127,6 +127,8 @@
 XMLPUBFUN void
             xmlTextReaderSetMaxAmplification(xmlTextReaderPtr reader,
                    unsigned maxAmpl);
+XMLPUBFUN const xmlError *
+            xmlTextReaderGetLastError(xmlTextReaderPtr reader);
 
 /*
  * Iterators
diff --git a/src/include/libxml/xmlversion.h.in b/src/include/libxml/xmlversion.h.in
index 0927d39..df516fe 100644
--- a/src/include/libxml/xmlversion.h.in
+++ b/src/include/libxml/xmlversion.h.in
@@ -10,20 +10,6 @@
 #ifndef __XML_VERSION_H__
 #define __XML_VERSION_H__
 
-#include <libxml/xmlexports.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * use those to be sure nothing nasty will happen if
- * your library and includes mismatch
- */
-#ifndef LIBXML2_COMPILING_MSCCDEF
-XMLPUBFUN void xmlCheckVersion(int version);
-#endif /* LIBXML2_COMPILING_MSCCDEF */
-
 /**
  * LIBXML_DOTTED_VERSION:
  *
@@ -286,15 +272,6 @@
 #endif
 
 /**
- * LIBXML_DEBUG_RUNTIME:
- *
- * Removed
- */
-#if 0
-#define LIBXML_DEBUG_RUNTIME
-#endif
-
-/**
  * LIBXML_UNICODE_ENABLED:
  *
  * Whether the Unicode related interfaces are compiled in
@@ -322,17 +299,6 @@
 #endif
 
 /**
- * LIBXML_EXPR_ENABLED:
- *
- * Whether the formal expressions interfaces are compiled in
- *
- * This code is unused and disabled unconditionally for now.
- */
-#if 0
-#define LIBXML_EXPR_ENABLED
-#endif
-
-/**
  * LIBXML_SCHEMAS_ENABLED:
  *
  * Whether the Schemas validation interfaces are compiled in
@@ -383,108 +349,8 @@
 #define LIBXML_LZMA_ENABLED
 #endif
 
-#ifdef __GNUC__
-/** DOC_DISABLE */
+#include <libxml/xmlexports.h>
 
-#ifndef ATTRIBUTE_UNUSED
-# if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7)))
-#  define ATTRIBUTE_UNUSED __attribute__((unused))
-# else
-#  define ATTRIBUTE_UNUSED
-# endif
-#endif
-
-#ifndef LIBXML_ATTR_ALLOC_SIZE
-# if (!defined(__clang__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))))
-#  define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
-# else
-#  define LIBXML_ATTR_ALLOC_SIZE(x)
-# endif
-#else
-# define LIBXML_ATTR_ALLOC_SIZE(x)
-#endif
-
-#ifndef LIBXML_ATTR_FORMAT
-# if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))
-#  define LIBXML_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args)))
-# else
-#  define LIBXML_ATTR_FORMAT(fmt,args)
-# endif
-#else
-# define LIBXML_ATTR_FORMAT(fmt,args)
-#endif
-
-#ifndef XML_DEPRECATED
-#  if defined (IN_LIBXML) || (__GNUC__ * 100 + __GNUC_MINOR__ < 301)
-#    define XML_DEPRECATED
-/* Available since at least GCC 3.1 */
-#  else
-#    define XML_DEPRECATED __attribute__((deprecated))
-#  endif
-#endif
-
-#if defined(__LCC__)
-  #define XML_IGNORE_FPTR_CAST_WARNINGS
-  #define XML_POP_WARNINGS \
-    _Pragma("diag_default 1215")
-#elif defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)
-  #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800)
-    #define XML_IGNORE_FPTR_CAST_WARNINGS \
-      _Pragma("GCC diagnostic push") \
-      _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
-      _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"")
-  #else
-    #define XML_IGNORE_FPTR_CAST_WARNINGS \
-      _Pragma("GCC diagnostic push") \
-      _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
-  #endif
-  #define XML_POP_WARNINGS \
-    _Pragma("GCC diagnostic pop")
-#else
-  #define XML_IGNORE_FPTR_CAST_WARNINGS
-  #define XML_POP_WARNINGS
-#endif
-
-#else /* ! __GNUC__ */
-#define ATTRIBUTE_UNUSED
-#define LIBXML_ATTR_ALLOC_SIZE(x)
-#define LIBXML_ATTR_FORMAT(fmt,args)
-#ifndef XML_DEPRECATED
-#  if defined (IN_LIBXML) || !defined (_MSC_VER)
-#    define XML_DEPRECATED
-/* Available since Visual Studio 2005 */
-#  elif defined (_MSC_VER) && (_MSC_VER >= 1400)
-#    define XML_DEPRECATED __declspec(deprecated)
-#  endif
-#endif
-#if defined (_MSC_VER) && (_MSC_VER >= 1400)
-#  define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push))
-#else
-#  define XML_IGNORE_FPTR_CAST_WARNINGS
-#endif
-#ifndef XML_POP_WARNINGS
-#  if defined (_MSC_VER) && (_MSC_VER >= 1400)
-#    define XML_POP_WARNINGS __pragma(warning(pop))
-#  else
-#    define XML_POP_WARNINGS
-#  endif
-#endif
-#endif /* __GNUC__ */
-
-#define XML_NO_ATTR
-
-#ifdef LIBXML_THREAD_ENABLED
-  #define XML_DECLARE_GLOBAL(name, type, attrs) \
-    attrs XMLPUBFUN type *__##name(void);
-  #define XML_GLOBAL_MACRO(name) (*__##name())
-#else
-  #define XML_DECLARE_GLOBAL(name, type, attrs) \
-    attrs XMLPUBVAR type name;
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
 #endif
 
 
diff --git a/src/include/libxml/xmlwriter.h b/src/include/libxml/xmlwriter.h
index 339f251..55f88bc 100644
--- a/src/include/libxml/xmlwriter.h
+++ b/src/include/libxml/xmlwriter.h
@@ -478,6 +478,7 @@
  * misc
  */
     XMLPUBFUN int xmlTextWriterFlush(xmlTextWriterPtr writer);
+    XMLPUBFUN int xmlTextWriterClose(xmlTextWriterPtr writer);
 
 #ifdef __cplusplus
 }
diff --git a/src/include/libxml/xpath.h b/src/include/libxml/xpath.h
index 6dae078..b89e105 100644
--- a/src/include/libxml/xpath.h
+++ b/src/include/libxml/xpath.h
@@ -515,6 +515,10 @@
 		    xmlXPathNewContext		(xmlDocPtr doc);
 XMLPUBFUN void
 		    xmlXPathFreeContext		(xmlXPathContextPtr ctxt);
+XMLPUBFUN void
+		    xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
+					    xmlStructuredErrorFunc handler,
+					    void *context);
 XMLPUBFUN int
 		    xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
 				            int active,
diff --git a/src/include/private/buf.h b/src/include/private/buf.h
index 6fef4ce..678294f 100644
--- a/src/include/private/buf.h
+++ b/src/include/private/buf.h
@@ -56,8 +56,6 @@
 xmlBufFromBuffer(xmlBufferPtr buffer);
 XML_HIDDEN xmlBufferPtr
 xmlBufBackToBuffer(xmlBufPtr buf);
-XML_HIDDEN int
-xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer);
 
 XML_HIDDEN int
 xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input);
diff --git a/src/include/private/dict.h b/src/include/private/dict.h
index 9b0be62..826ac54 100644
--- a/src/include/private/dict.h
+++ b/src/include/private/dict.h
@@ -67,6 +67,8 @@
 XML_HIDDEN void
 xmlCleanupRandom(void);
 XML_HIDDEN unsigned
+xmlGlobalRandom(void);
+XML_HIDDEN unsigned
 xmlRandom(void);
 
 #endif /* XML_DICT_H_PRIVATE__ */
diff --git a/src/include/private/entities.h b/src/include/private/entities.h
index c3f15e6..d262ef4 100644
--- a/src/include/private/entities.h
+++ b/src/include/private/entities.h
@@ -9,13 +9,17 @@
  *
  * XML_ENT_PARSED: The entity was parsed and `children` points to the
  * content.
- * XML_ENT_CHECKED: The entity was checked for loops.
+ *
+ * XML_ENT_CHECKED: The entity was checked for loops and amplification.
+ * expandedSize was set.
+ *
+ * XML_ENT_VALIDATED: The entity contains a valid attribute value.
+ * Only used when entities aren't substituted.
  */
-#define XML_ENT_PARSED      (1<<0)
-#define XML_ENT_CHECKED     (1<<1)
-#define XML_ENT_EXPANDING   (1<<2)
-#define XML_ENT_CHECKED_LT  (1<<3)
-#define XML_ENT_CONTAINS_LT (1<<4)
+#define XML_ENT_PARSED      (1u << 0)
+#define XML_ENT_CHECKED     (1u << 1)
+#define XML_ENT_VALIDATED   (1u << 2)
+#define XML_ENT_EXPANDING   (1u << 3)
 
 XML_HIDDEN xmlChar *
 xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input);
diff --git a/src/include/private/error.h b/src/include/private/error.h
index d3d2665..506405a 100644
--- a/src/include/private/error.h
+++ b/src/include/private/error.h
@@ -4,27 +4,31 @@
 #include <libxml/xmlerror.h>
 #include <libxml/xmlversion.h>
 
+#define MAX_ERR_MSG_SIZE 64000
+
 struct _xmlNode;
 
+XML_HIDDEN void
+xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel,
+                    void *data, int domain, xmlError *error);
 XML_HIDDEN int
-xmlVRaiseError(xmlStructuredErrorFunc schannel,
-               xmlGenericErrorFunc channel, void *data, void *ctx,
-               void *nod, int domain, int code, xmlErrorLevel level,
+xmlVRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel,
+               void *data, void *ctx, struct _xmlNode *node,
+               int domain, int code, xmlErrorLevel level,
                const char *file, int line, const char *str1,
                const char *str2, const char *str3, int int1, int col,
                const char *msg, va_list ap);
 XML_HIDDEN int
-__xmlRaiseError(xmlStructuredErrorFunc schannel,
-                xmlGenericErrorFunc channel, void *data, void *ctx,
-                void *nod, int domain, int code, xmlErrorLevel level,
+__xmlRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel,
+                void *data, void *ctx, struct _xmlNode *node,
+                int domain, int code, xmlErrorLevel level,
                 const char *file, int line, const char *str1,
                 const char *str2, const char *str3, int int1, int col,
 	        const char *msg, ...) LIBXML_ATTR_FORMAT(16,17);
 XML_HIDDEN void
-__xmlSimpleError(int domain, int code, struct _xmlNode *node,
-                 const char *msg, const char *extra) LIBXML_ATTR_FORMAT(4,0);
-XML_HIDDEN void
 xmlGenericErrorDefaultFunc(void *ctx, const char *msg,
                            ...) LIBXML_ATTR_FORMAT(2,3);
+XML_HIDDEN const char *
+xmlErrString(xmlParserErrors code);
 
 #endif /* XML_ERROR_H_PRIVATE__ */
diff --git a/src/include/private/globals.h b/src/include/private/globals.h
index 5f3f112..828b6d5 100644
--- a/src/include/private/globals.h
+++ b/src/include/private/globals.h
@@ -6,4 +6,9 @@
 XML_HIDDEN void
 xmlCleanupGlobalsInternal(void);
 
+#ifdef LIBXML_THREAD_ENABLED
+XML_HIDDEN unsigned *
+xmlGetLocalRngState(void);
+#endif
+
 #endif /* XML_GLOBALS_H_PRIVATE__ */
diff --git a/src/include/private/io.h b/src/include/private/io.h
index ed931ac..01c2ced 100644
--- a/src/include/private/io.h
+++ b/src/include/private/io.h
@@ -6,13 +6,23 @@
 #include <libxml/xmlversion.h>
 
 XML_HIDDEN void
-__xmlIOErr(int domain, int code, const char *extra);
-XML_HIDDEN void xmlLoaderErr(xmlParserCtxtPtr ctxt,
-                             const char* msg,
-                             const char* filename) LIBXML_ATTR_FORMAT(2, 0);
+xmlInitIOCallbacks(void);
 
-xmlParserInputBufferPtr
-xmlParserInputBufferCreateString(const xmlChar *str);
+XML_HIDDEN int
+__xmlIOErr(int domain, int code, const char *extra);
+
+XML_HIDDEN int
+xmlNoNetExists(const char *filename);
+
+XML_HIDDEN int
+xmlParserInputBufferCreateFilenameSafe(const char *URI, xmlCharEncoding enc,
+                                       xmlParserInputBufferPtr *out);
+
+XML_HIDDEN xmlParserInputBufferPtr
+xmlNewInputBufferString(const char *str, int flags);
+XML_HIDDEN xmlParserInputBufferPtr
+xmlNewInputBufferMemory(const void *mem, size_t size, int flags,
+                        xmlCharEncoding enc);
 
 #ifdef LIBXML_OUTPUT_ENABLED
 XML_HIDDEN xmlOutputBufferPtr
diff --git a/src/include/private/parser.h b/src/include/private/parser.h
index 96be5e4..c5df068 100644
--- a/src/include/private/parser.h
+++ b/src/include/private/parser.h
@@ -25,41 +25,39 @@
 #define XML_INPUT_AUTO_OTHER        (4u << 1)
 #define XML_INPUT_USES_ENC_DECL     (1u << 4)
 #define XML_INPUT_ENCODING_ERROR    (1u << 5)
+#define XML_INPUT_PROGRESSIVE       (1u << 6)
 
 #define PARSER_STOPPED(ctxt) ((ctxt)->disableSAX > 1)
 
-XML_HIDDEN void xmlVErrParser(xmlParserCtxtPtr ctxt,
-                              xmlNodePtr node,
-                              int domain,
-                              int code,
-                              xmlErrorLevel level,
-                              const xmlChar* str1,
-                              const xmlChar* str2,
-                              const xmlChar* str3,
-                              int int1,
-                              const char* msg,
-                              va_list ap);
-XML_HIDDEN void xmlErrParser(xmlParserCtxtPtr ctxt,
-                             xmlNodePtr node,
-                             int domain,
-                             int code,
-                             xmlErrorLevel level,
-                             const xmlChar* str1,
-                             const xmlChar* str2,
-                             const xmlChar* str3,
-                             int int1,
-                             const char* msg,
-                             ...);
+#define PARSER_PROGRESSIVE(ctxt) \
+    ((ctxt)->input->flags & XML_INPUT_PROGRESSIVE)
+
+#define PARSER_IN_PE(ctxt) \
+    (((ctxt)->input->entity != NULL) && \
+     (((ctxt)->input->entity->etype == XML_INTERNAL_PARAMETER_ENTITY) || \
+      ((ctxt)->input->entity->etype == XML_EXTERNAL_PARAMETER_ENTITY)))
+
+#define PARSER_EXTERNAL(ctxt) \
+    (((ctxt)->inSubset == 2) || \
+     (((ctxt)->input->entity != NULL) && \
+      ((ctxt)->input->entity->etype == XML_EXTERNAL_PARAMETER_ENTITY)))
+
+XML_HIDDEN void
+xmlCtxtVErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain,
+            xmlParserErrors code, xmlErrorLevel level,
+            const xmlChar *str1, const xmlChar *str2, const xmlChar *str3,
+            int int1, const char *msg, va_list ap);
+XML_HIDDEN void
+xmlCtxtErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain,
+           xmlParserErrors code, xmlErrorLevel level,
+           const xmlChar *str1, const xmlChar *str2, const xmlChar *str3,
+           int int1, const char *msg, ...);
 XML_HIDDEN void
 xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info);
 XML_HIDDEN void LIBXML_ATTR_FORMAT(3,0)
 xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
               const char *msg, const xmlChar *str1, const xmlChar *str2);
 XML_HIDDEN void
-__xmlErrEncoding(xmlParserCtxtPtr ctxt, xmlParserErrors xmlerr,
-                 const char *msg, const xmlChar *str1,
-                 const xmlChar *str2) LIBXML_ATTR_FORMAT(3,0);
-XML_HIDDEN void
 xmlHaltParser(xmlParserCtxtPtr ctxt);
 XML_HIDDEN int
 xmlParserGrow(xmlParserCtxtPtr ctxt);
@@ -85,4 +83,34 @@
 XML_HIDDEN void *
 xmlParserNsLookupSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix);
 
+#define XML_INPUT_BUF_STATIC		(1u << 1)
+#define XML_INPUT_BUF_ZERO_TERMINATED	(1u << 2)
+
+XML_HIDDEN xmlParserInputPtr
+xmlNewInputURL(xmlParserCtxtPtr ctxt, const char *url, const char *publicId,
+               const char *encoding, int flags);
+XML_HIDDEN xmlParserInputPtr
+xmlNewInputMemory(xmlParserCtxtPtr ctxt, const char *url,
+                  const void *mem, size_t size,
+                  const char *encoding, int flags);
+XML_HIDDEN xmlParserInputPtr
+xmlNewInputString(xmlParserCtxtPtr ctxt, const char *url, const char *str,
+                  const char *encoding, int flags);
+XML_HIDDEN xmlParserInputPtr
+xmlNewInputFd(xmlParserCtxtPtr ctxt, const char *filename, int fd,
+              const char *encoding, int flags);
+XML_HIDDEN xmlParserInputPtr
+xmlNewInputIO(xmlParserCtxtPtr ctxt, const char *url,
+              xmlInputReadCallback ioRead,
+              xmlInputCloseCallback ioClose,
+              void *ioCtxt,
+              const char *encoding, int flags);
+XML_HIDDEN xmlParserInputPtr
+xmlNewInputPush(xmlParserCtxtPtr ctxt, const char *url,
+                const char *chunk, int size, const char *encoding);
+
+XML_HIDDEN xmlChar *
+xmlExpandEntitiesInAttValue(xmlParserCtxtPtr ctxt, const xmlChar *str,
+                            int normalize);
+
 #endif /* XML_PARSER_H_PRIVATE__ */
diff --git a/src/include/private/save.h b/src/include/private/save.h
index 873aad7..6e16a2f 100644
--- a/src/include/private/save.h
+++ b/src/include/private/save.h
@@ -2,10 +2,16 @@
 #define XML_SAVE_H_PRIVATE__
 
 #include <libxml/tree.h>
+#include <libxml/xmlsave.h>
 #include <libxml/xmlversion.h>
 
 #ifdef LIBXML_OUTPUT_ENABLED
 
+XML_HIDDEN int
+xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur);
+XML_HIDDEN int
+xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur);
+
 XML_HIDDEN void
 xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
                               xmlAttrPtr attr, const xmlChar * string);
diff --git a/src/include/private/string.h b/src/include/private/string.h
index 9665fc4..34f4c96 100644
--- a/src/include/private/string.h
+++ b/src/include/private/string.h
@@ -3,6 +3,10 @@
 
 #include <libxml/xmlstring.h>
 
+XML_HIDDEN int
+xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap);
+XML_HIDDEN int
+xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...);
 XML_HIDDEN xmlChar *
 xmlEscapeFormatString(xmlChar **msg);
 
diff --git a/src/include/private/xpath.h b/src/include/private/xpath.h
index 3128a11..72a6972 100644
--- a/src/include/private/xpath.h
+++ b/src/include/private/xpath.h
@@ -8,9 +8,9 @@
 
 #ifdef LIBXML_XPATH_ENABLED
 XML_HIDDEN void
-xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra);
+xmlXPathErrMemory(xmlXPathContextPtr ctxt);
 XML_HIDDEN void
-xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra);
+xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt);
 #endif
 
 #endif /* XML_XPATH_H_PRIVATE__ */
diff --git a/src/include/private/xzlib.h b/src/include/private/xzlib.h
index b332698..8505ef3 100644
--- a/src/include/private/xzlib.h
+++ b/src/include/private/xzlib.h
@@ -19,7 +19,7 @@
 XML_HIDDEN xzFile
 __libxml2_xzopen(const char *path, const char *mode);
 XML_HIDDEN xzFile
-__libxml2_xzdopen(int fd, const char *mode);
+__libxml2_xzdopen(const char *path, int fd, const char *mode);
 XML_HIDDEN int
 __libxml2_xzread(xzFile file, void *buf, unsigned len);
 XML_HIDDEN int
diff --git a/src/libxml.h b/src/libxml.h
index 00404d2..d94677b 100644
--- a/src/libxml.h
+++ b/src/libxml.h
@@ -55,9 +55,14 @@
 #endif
 
 #ifdef __clang__
-  #define ATTRIBUTE_NO_SANITIZE_INTEGER \
-    ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") \
-    ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
+  #if __clang_major__ >= 12
+    #define ATTRIBUTE_NO_SANITIZE_INTEGER \
+      ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow") \
+      ATTRIBUTE_NO_SANITIZE("unsigned-shift-base")
+  #else
+    #define ATTRIBUTE_NO_SANITIZE_INTEGER \
+      ATTRIBUTE_NO_SANITIZE("unsigned-integer-overflow")
+  #endif
 #else
   #define ATTRIBUTE_NO_SANITIZE_INTEGER
 #endif
diff --git a/src/libxml2-config.cmake.in b/src/libxml2-config.cmake.in
index 0447936..6799fd2 100644
--- a/src/libxml2-config.cmake.in
+++ b/src/libxml2-config.cmake.in
@@ -6,6 +6,7 @@
 #
 # ::
 #
+#   LIBXML2_FOUND              - True if libxml2 headers and libraries were found
 #   LIBXML2_INCLUDE_DIR        - Directory where LibXml2 headers are located.
 #   LIBXML2_INCLUDE_DIRS       - list of the include directories needed to use LibXml2.
 #   LIBXML2_LIBRARY            - path to the LibXml2 library.
@@ -121,6 +122,10 @@
 
 mark_as_advanced(LIBXML2_LIBRARY LIBXML2_XMLCATALOG_EXECUTABLE LIBXML2_XMLLINT_EXECUTABLE)
 
+if(DEFINED LIBXML2_LIBRARY AND DEFINED LIBXML2_INCLUDE_DIRS)
+  set(LIBXML2_FOUND TRUE)
+endif()
+
 if(NOT TARGET LibXml2::LibXml2 AND DEFINED LIBXML2_LIBRARY AND DEFINED LIBXML2_INCLUDE_DIRS)
   add_library(LibXml2::LibXml2 UNKNOWN IMPORTED)
   set_target_properties(LibXml2::LibXml2 PROPERTIES IMPORTED_LOCATION "${LIBXML2_LIBRARY}")
diff --git a/src/list.c b/src/list.c
index 3eaf67f..20df26c 100644
--- a/src/list.c
+++ b/src/list.c
@@ -188,18 +188,13 @@
 xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare)
 {
     xmlListPtr l;
-    if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) {
-        xmlGenericError(xmlGenericErrorContext,
-		        "Cannot initialize memory for list");
+    if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList))))
         return (NULL);
-    }
     /* Initialize the list to NULL */
     memset(l, 0, sizeof(xmlList));
 
     /* Add the sentinel */
     if (NULL ==(l->sentinel = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
-        xmlGenericError(xmlGenericErrorContext,
-		        "Cannot initialize memory for sentinel");
 	xmlFree(l);
         return (NULL);
     }
@@ -279,11 +274,8 @@
     lkPlace = xmlListLowerSearch(l, data);
     /* Add the new link */
     lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
-    if (lkNew == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-		        "Cannot initialize memory for new link");
+    if (lkNew == NULL)
         return (1);
-    }
     lkNew->data = data;
     lkPlace = lkPlace->prev;
     lkNew->next = lkPlace->next;
@@ -311,11 +303,8 @@
     lkPlace = xmlListHigherSearch(l, data);
     /* Add the new link */
     lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
-    if (lkNew == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-		        "Cannot initialize memory for new link");
+    if (lkNew == NULL)
         return (1);
-    }
     lkNew->data = data;
     lkNew->next = lkPlace->next;
     (lkPlace->next)->prev = lkNew;
@@ -548,11 +537,8 @@
     lkPlace = l->sentinel;
     /* Add the new link */
     lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
-    if (lkNew == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-		        "Cannot initialize memory for new link");
+    if (lkNew == NULL)
         return (0);
-    }
     lkNew->data = data;
     lkNew->next = lkPlace->next;
     (lkPlace->next)->prev = lkNew;
@@ -579,11 +565,8 @@
         return(0);
     lkPlace = l->sentinel->prev;
     /* Add the new link */
-    if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
-        xmlGenericError(xmlGenericErrorContext,
-		        "Cannot initialize memory for new link");
+    if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink))))
         return (0);
-    }
     lkNew->data = data;
     lkNew->next = lkPlace->next;
     (lkPlace->next)->prev = lkNew;
diff --git a/src/nanoftp.c b/src/nanoftp.c
index 8fbe7aa..fc8f8d7 100644
--- a/src/nanoftp.c
+++ b/src/nanoftp.c
@@ -137,9 +137,9 @@
  * Handle an out of memory condition
  */
 static void
-xmlFTPErrMemory(const char *extra)
+xmlFTPErrMemory(const char *extra ATTRIBUTE_UNUSED)
 {
-    __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
+    xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_FTP, NULL);
 }
 
 /**
@@ -1923,7 +1923,7 @@
 void ftpList(void *userData, const char *filename, const char* attrib,
 	     const char *owner, const char *group, unsigned long size, int links,
 	     int year, const char *month, int day, int hour, int minute) {
-    xmlGenericError(xmlGenericErrorContext,
+    fprintf(stderr,
 	    "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
 }
 static
@@ -1945,7 +1945,7 @@
     if (argc > 1) {
 	ctxt = xmlNanoFTPNewCtxt(argv[1]);
 	if (xmlNanoFTPConnect(ctxt) < 0) {
-	    xmlGenericError(xmlGenericErrorContext,
+	    fprintf(stderr,
 		    "Couldn't connect to %s\n", argv[1]);
 	    exit(1);
 	}
@@ -1954,7 +1954,7 @@
     } else
 	ctxt = xmlNanoFTPConnectTo("localhost", 0);
     if (ctxt == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
+        fprintf(stderr,
 		"Couldn't connect to localhost\n");
         exit(1);
     }
@@ -1962,7 +1962,7 @@
     output = fopen("/tmp/tstdata", "w");
     if (output != NULL) {
 	if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
-	    xmlGenericError(xmlGenericErrorContext,
+	    fprintf(stderr,
 		    "Failed to get file\n");
 
     }
@@ -1974,7 +1974,7 @@
 #ifdef STANDALONE
 #include <stdio.h>
 int main(int argc, char **argv) {
-    xmlGenericError(xmlGenericErrorContext,
+    fprintf(stderr,
 	    "%s : FTP support not compiled in\n", argv[0]);
     return(0);
 }
diff --git a/src/nanohttp.c b/src/nanohttp.c
index 0d7af48..81da585 100644
--- a/src/nanohttp.c
+++ b/src/nanohttp.c
@@ -147,9 +147,9 @@
  * Handle an out of memory condition
  */
 static void
-xmlHTTPErrMemory(const char *extra)
+xmlHTTPErrMemory(void)
 {
-    __xmlSimpleError(XML_FROM_HTTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
+    xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_HTTP, NULL);
 }
 
 /**
@@ -358,7 +358,7 @@
 
     ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
     if (ret == NULL) {
-        xmlHTTPErrMemory("allocating context");
+        xmlHTTPErrMemory();
         return(NULL);
     }
 
@@ -504,7 +504,7 @@
         if (ctxt->in == NULL) {
             ctxt->in = (char *) xmlMallocAtomic(65000);
             if (ctxt->in == NULL) {
-                xmlHTTPErrMemory("allocating input");
+                xmlHTTPErrMemory();
                 ctxt->last = -1;
                 return (-1);
             }
@@ -529,7 +529,7 @@
             ctxt->inlen *= 2;
             ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen);
             if (ctxt->in == NULL) {
-                xmlHTTPErrMemory("allocating input buffer");
+                xmlHTTPErrMemory();
                 xmlFree(tmp_ptr);
                 ctxt->last = -1;
                 return (-1);
@@ -1444,7 +1444,7 @@
     bp = (char*)xmlMallocAtomic(blen);
     if ( bp == NULL ) {
         xmlNanoHTTPFreeCtxt( ctxt );
-	xmlHTTPErrMemory("allocating header buffer");
+	xmlHTTPErrMemory();
 	return ( NULL );
     }
 
@@ -1831,9 +1831,9 @@
 	    xmlNanoHTTPFetch(argv[1], "-", &contentType);
 	if (contentType != NULL) xmlFree(contentType);
     } else {
-        xmlGenericError(xmlGenericErrorContext,
+        fprintf(stderr,
 		"%s: minimal HTTP GET implementation\n", argv[0]);
-        xmlGenericError(xmlGenericErrorContext,
+        fprintf(stderr,
 		"\tusage %s [ URL [ filename ] ]\n", argv[0]);
     }
     xmlNanoHTTPCleanup();
@@ -1844,7 +1844,7 @@
 #ifdef STANDALONE
 #include <stdio.h>
 int main(int argc, char **argv) {
-    xmlGenericError(xmlGenericErrorContext,
+    fprintf(stderr,
 	    "%s : HTTP support not compiled in\n", argv[0]);
     return(0);
 }
diff --git a/src/parser.c b/src/parser.c
index 43ef214..8859e3c 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -108,23 +108,25 @@
 
     unsigned elementId;
     int defaultNsIndex;
+    int minNsIndex;
 };
 
 struct _xmlAttrHashBucket {
     int index;
 };
 
-static xmlParserCtxtPtr
-xmlCreateEntityParserCtxtInternal(xmlSAXHandlerPtr sax, void *userData,
-        const xmlChar *URL, const xmlChar *ID, const xmlChar *base,
-        xmlParserCtxtPtr pctx);
-
 static int
 xmlParseElementStart(xmlParserCtxtPtr ctxt);
 
 static void
 xmlParseElementEnd(xmlParserCtxtPtr ctxt);
 
+static xmlEntityPtr
+xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr);
+
+static const xmlChar *
+xmlParseEntityRefInternal(xmlParserCtxtPtr ctxt);
+
 /************************************************************************
  *									*
  *	Arbitrary limits set in the parser. See XML_PARSE_HUGE		*
@@ -159,7 +161,7 @@
  * boundary feature. It can be disabled with the XML_PARSE_HUGE
  * parser option.
  */
-unsigned int xmlParserMaxDepth = 256;
+const unsigned int xmlParserMaxDepth = 256;
 
 
 
@@ -201,24 +203,8 @@
 static xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt,
                                               const xmlChar **str);
 
-static xmlParserErrors
-xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
-	              xmlSAXHandlerPtr sax,
-		      void *user_data, int depth, const xmlChar *URL,
-		      const xmlChar *ID, xmlNodePtr *list);
-
-static int
-xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options,
-                          const char *encoding);
-#ifdef LIBXML_LEGACY_ENABLED
 static void
-xmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode,
-                      xmlNodePtr lastNode);
-#endif /* LIBXML_LEGACY_ENABLED */
-
-static xmlParserErrors
-xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt,
-		      const xmlChar *string, void *user_data, xmlNodePtr *lst);
+xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent);
 
 static int
 xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity);
@@ -229,6 +215,11 @@
  *									*
  ************************************************************************/
 
+static void
+xmlErrMemory(xmlParserCtxtPtr ctxt) {
+    xmlCtxtErrMemory(ctxt);
+}
+
 /**
  * xmlErrAttributeDup:
  * @ctxt:  an XML parser context
@@ -242,13 +233,13 @@
                    const xmlChar * localname)
 {
     if (prefix == NULL)
-        xmlErrParser(ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED,
-                     XML_ERR_FATAL, localname, NULL, NULL, 0,
-                     "Attribute %s redefined\n", localname);
+        xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED,
+                   XML_ERR_FATAL, localname, NULL, NULL, 0,
+                   "Attribute %s redefined\n", localname);
     else
-        xmlErrParser(ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED,
-                     XML_ERR_FATAL, prefix, localname, NULL, 0,
-                     "Attribute %s:%s redefined\n", prefix, localname);
+        xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED,
+                   XML_ERR_FATAL, prefix, localname, NULL, 0,
+                   "Attribute %s:%s redefined\n", prefix, localname);
 }
 
 /**
@@ -263,8 +254,8 @@
 xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                const char *msg)
 {
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
-                 NULL, NULL, NULL, 0, "%s", msg);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
+               NULL, NULL, NULL, 0, "%s", msg);
 }
 
 /**
@@ -281,8 +272,8 @@
 xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error,
               const char *msg, const xmlChar *str1, const xmlChar *str2)
 {
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING,
-                 str1, str2, NULL, 0, msg, str1, str2);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING,
+               str1, str2, NULL, 0, msg, str1, str2);
 }
 
 /**
@@ -300,8 +291,8 @@
 {
     ctxt->valid = 0;
 
-    xmlErrParser(ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR,
-                 str1, str2, NULL, 0, msg, str1, str2);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR,
+               str1, str2, NULL, 0, msg, str1, str2);
 }
 
 /**
@@ -317,8 +308,8 @@
 xmlFatalErrMsgInt(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                   const char *msg, int val)
 {
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
-                 NULL, NULL, NULL, val, msg, val);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
+               NULL, NULL, NULL, val, msg, val);
 }
 
 /**
@@ -337,8 +328,8 @@
                   const char *msg, const xmlChar *str1, int val,
 		  const xmlChar *str2)
 {
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
-                 str1, str2, NULL, val, msg, str1, val, str2);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
+               str1, str2, NULL, val, msg, str1, val, str2);
 }
 
 /**
@@ -354,8 +345,8 @@
 xmlFatalErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                   const char *msg, const xmlChar * val)
 {
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
-                 val, NULL, NULL, 0, msg, val);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
+               val, NULL, NULL, 0, msg, val);
 }
 
 /**
@@ -371,8 +362,8 @@
 xmlErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                   const char *msg, const xmlChar * val)
 {
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_ERROR,
-                 val, NULL, NULL, 0, msg, val);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_ERROR,
+               val, NULL, NULL, 0, msg, val);
 }
 
 /**
@@ -393,8 +384,8 @@
 {
     ctxt->nsWellFormed = 0;
 
-    xmlErrParser(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_ERROR,
-                 info1, info2, info3, 0, msg, info1, info2, info3);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_ERROR,
+               info1, info2, info3, 0, msg, info1, info2, info3);
 }
 
 /**
@@ -413,8 +404,8 @@
          const xmlChar * info1, const xmlChar * info2,
          const xmlChar * info3)
 {
-    xmlErrParser(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_WARNING,
-                 info1, info2, info3, 0, msg, info1, info2, info3);
+    xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_WARNING,
+               info1, info2, info3, 0, msg, info1, info2, info3);
 }
 
 static void
@@ -440,7 +431,7 @@
  *
  * Check for non-linear entity expansion behaviour.
  *
- * In some cases like xmlStringDecodeEntities, this function is called
+ * In some cases like xmlExpandEntityInAttValue, this function is called
  * for each, possibly nested entity and its unexpanded content length.
  *
  * In other cases like xmlParseReference, it's only called for each
@@ -461,37 +452,41 @@
 xmlParserEntityCheck(xmlParserCtxtPtr ctxt, unsigned long extra)
 {
     unsigned long consumed;
+    unsigned long *expandedSize;
     xmlParserInputPtr input = ctxt->input;
     xmlEntityPtr entity = input->entity;
 
+    if ((entity) && (entity->flags & XML_ENT_CHECKED))
+        return(0);
+
     /*
      * Compute total consumed bytes so far, including input streams of
      * external entities.
      */
-    consumed = input->parentConsumed;
-    if ((entity == NULL) ||
-        ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
-         ((entity->flags & XML_ENT_PARSED) == 0))) {
-        xmlSaturatedAdd(&consumed, input->consumed);
-        xmlSaturatedAddSizeT(&consumed, input->cur - input->base);
-    }
+    consumed = input->consumed;
+    xmlSaturatedAddSizeT(&consumed, input->cur - input->base);
     xmlSaturatedAdd(&consumed, ctxt->sizeentities);
 
+    if (entity)
+        expandedSize = &entity->expandedSize;
+    else
+        expandedSize = &ctxt->sizeentcopy;
+
     /*
      * Add extra cost and some fixed cost.
      */
-    xmlSaturatedAdd(&ctxt->sizeentcopy, extra);
-    xmlSaturatedAdd(&ctxt->sizeentcopy, XML_ENT_FIXED_COST);
+    xmlSaturatedAdd(expandedSize, extra);
+    xmlSaturatedAdd(expandedSize, XML_ENT_FIXED_COST);
 
     /*
      * It's important to always use saturation arithmetic when tracking
      * entity sizes to make the size checks reliable. If "sizeentcopy"
      * overflows, we have to abort.
      */
-    if ((ctxt->sizeentcopy > XML_PARSER_ALLOWED_EXPANSION) &&
-        ((ctxt->sizeentcopy >= ULONG_MAX) ||
-         (ctxt->sizeentcopy / ctxt->maxAmpl > consumed))) {
-        xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_LOOP,
+    if ((*expandedSize > XML_PARSER_ALLOWED_EXPANSION) &&
+        ((*expandedSize >= ULONG_MAX) ||
+         (*expandedSize / ctxt->maxAmpl > consumed))) {
+        xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT,
                        "Maximum entity amplification factor exceeded, see "
                        "xmlCtxtSetMaxAmplification.\n");
         xmlHaltParser(ctxt);
@@ -695,8 +690,6 @@
 #else
             return(0);
 #endif
-        case XML_WITH_DEBUG_RUN:
-            return(0);
         case XML_WITH_ZLIB:
 #ifdef LIBXML_ZLIB_ENABLED
             return(1);
@@ -723,23 +716,241 @@
 
 /************************************************************************
  *									*
+ *			Simple string buffer				*
+ *									*
+ ************************************************************************/
+
+typedef struct {
+    xmlChar *mem;
+    unsigned size;
+    unsigned cap; /* size < cap */
+    unsigned max; /* size <= max */
+    xmlParserErrors code;
+} xmlSBuf;
+
+static void
+xmlSBufInit(xmlSBuf *buf, unsigned max) {
+    buf->mem = NULL;
+    buf->size = 0;
+    buf->cap = 0;
+    buf->max = max;
+    buf->code = XML_ERR_OK;
+}
+
+static int
+xmlSBufGrow(xmlSBuf *buf, unsigned len) {
+    xmlChar *mem;
+    unsigned cap;
+
+    if (len >= UINT_MAX / 2 - buf->size) {
+        buf->code = XML_ERR_RESOURCE_LIMIT;
+        return(-1);
+    }
+
+    cap = (buf->size + len) * 2;
+    if (cap < 240)
+        cap = 240;
+
+    mem = xmlRealloc(buf->mem, cap);
+    if (mem == NULL) {
+        buf->code = XML_ERR_NO_MEMORY;
+        return(-1);
+    }
+
+    buf->mem = mem;
+    buf->cap = cap;
+
+    return(0);
+}
+
+static void
+xmlSBufAddString(xmlSBuf *buf, const xmlChar *str, unsigned len) {
+    if (buf->max - buf->size < len) {
+        buf->code = XML_ERR_RESOURCE_LIMIT;
+        return;
+    }
+
+    if (buf->cap - buf->size <= len) {
+        if (xmlSBufGrow(buf, len) < 0)
+            return;
+    }
+
+    if (len > 0)
+        memcpy(buf->mem + buf->size, str, len);
+    buf->size += len;
+}
+
+static void
+xmlSBufAddCString(xmlSBuf *buf, const char *str, unsigned len) {
+    xmlSBufAddString(buf, (const xmlChar *) str, len);
+}
+
+static void
+xmlSBufAddChar(xmlSBuf *buf, int c) {
+    xmlChar *end;
+
+    if (buf->max - buf->size < 4) {
+        buf->code = XML_ERR_RESOURCE_LIMIT;
+        return;
+    }
+
+    if (buf->cap - buf->size <= 4) {
+        if (xmlSBufGrow(buf, 4) < 0)
+            return;
+    }
+
+    end = buf->mem + buf->size;
+
+    if (c < 0x80) {
+        *end = (xmlChar) c;
+        buf->size += 1;
+    } else {
+        buf->size += xmlCopyCharMultiByte(end, c);
+    }
+}
+
+static void
+xmlSBufAddReplChar(xmlSBuf *buf) {
+    xmlSBufAddCString(buf, "\xEF\xBF\xBD", 3);
+}
+
+static void
+xmlSBufReportError(xmlSBuf *buf, xmlParserCtxtPtr ctxt, const char *errMsg) {
+    if (buf->code == XML_ERR_NO_MEMORY)
+        xmlCtxtErrMemory(ctxt);
+    else
+        xmlFatalErr(ctxt, buf->code, errMsg);
+}
+
+static xmlChar *
+xmlSBufFinish(xmlSBuf *buf, int *sizeOut, xmlParserCtxtPtr ctxt,
+              const char *errMsg) {
+    if (buf->mem == NULL) {
+        buf->mem = xmlMalloc(1);
+        if (buf->mem == NULL) {
+            buf->code = XML_ERR_NO_MEMORY;
+        } else {
+            buf->mem[0] = 0;
+        }
+    } else {
+        buf->mem[buf->size] = 0;
+    }
+
+    if (buf->code == XML_ERR_OK) {
+        if (sizeOut != NULL)
+            *sizeOut = buf->size;
+        return(buf->mem);
+    }
+
+    xmlSBufReportError(buf, ctxt, errMsg);
+
+    xmlFree(buf->mem);
+
+    if (sizeOut != NULL)
+        *sizeOut = 0;
+    return(NULL);
+}
+
+static void
+xmlSBufCleanup(xmlSBuf *buf, xmlParserCtxtPtr ctxt, const char *errMsg) {
+    if (buf->code != XML_ERR_OK)
+        xmlSBufReportError(buf, ctxt, errMsg);
+
+    xmlFree(buf->mem);
+}
+
+static int
+xmlUTF8MultibyteLen(xmlParserCtxtPtr ctxt, const xmlChar *str,
+                    const char *errMsg) {
+    int c = str[0];
+    int c1 = str[1];
+
+    if ((c1 & 0xC0) != 0x80)
+        goto encoding_error;
+
+    if (c < 0xE0) {
+        /* 2-byte sequence */
+        if (c < 0xC2)
+            goto encoding_error;
+
+        return(2);
+    } else {
+        int c2 = str[2];
+
+        if ((c2 & 0xC0) != 0x80)
+            goto encoding_error;
+
+        if (c < 0xF0) {
+            /* 3-byte sequence */
+            if (c == 0xE0) {
+                /* overlong */
+                if (c1 < 0xA0)
+                    goto encoding_error;
+            } else if (c == 0xED) {
+                /* surrogate */
+                if (c1 >= 0xA0)
+                    goto encoding_error;
+            } else if (c == 0xEF) {
+                /* U+FFFE and U+FFFF are invalid Chars */
+                if ((c1 == 0xBF) && (c2 >= 0xBE))
+                    xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, errMsg);
+            }
+
+            return(3);
+        } else {
+            /* 4-byte sequence */
+            if ((str[3] & 0xC0) != 0x80)
+                goto encoding_error;
+            if (c == 0xF0) {
+                /* overlong */
+                if (c1 < 0x90)
+                    goto encoding_error;
+            } else if (c >= 0xF4) {
+                /* greater than 0x10FFFF */
+                if ((c > 0xF4) || (c1 >= 0x90))
+                    goto encoding_error;
+            }
+
+            return(4);
+        }
+    }
+
+encoding_error:
+    /* Only report the first error */
+    if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) {
+        xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL);
+        ctxt->input->flags |= XML_INPUT_ENCODING_ERROR;
+    }
+
+    return(0);
+}
+
+/************************************************************************
+ *									*
  *		SAX2 defaulted attributes handling			*
  *									*
  ************************************************************************/
 
 /**
- * xmlDetectSAX2:
+ * xmlCtxtInitializeLate:
  * @ctxt:  an XML parser context
  *
- * Do the SAX2 detection and specific initialization
+ * Final initialization of the parser context before starting to parse.
+ *
+ * This accounts for users modifying struct members of parser context
+ * directly.
  */
 static void
-xmlDetectSAX2(xmlParserCtxtPtr ctxt) {
+xmlCtxtInitializeLate(xmlParserCtxtPtr ctxt) {
     xmlSAXHandlerPtr sax;
 
     /* Avoid unused variable warning if features are disabled. */
     (void) sax;
 
+    /*
+     * Changing the SAX struct directly is still widespread practice
+     * in internal and external code.
+     */
     if (ctxt == NULL) return;
     sax = ctxt->sax;
 #ifdef LIBXML_SAX1_ENABLED
@@ -747,7 +958,9 @@
      * Only enable SAX2 if there SAX2 element handlers, except when there
      * are no element handlers at all.
      */
-    if ((sax) && (sax->initialized == XML_SAX2_MAGIC) &&
+    if (((ctxt->options & XML_PARSE_SAX1) == 0) &&
+        (sax) &&
+        (sax->initialized == XML_SAX2_MAGIC) &&
         ((sax->startElementNs != NULL) ||
          (sax->endElementNs != NULL) ||
          ((sax->startElement == NULL) && (sax->endElement == NULL))))
@@ -756,12 +969,16 @@
     ctxt->sax2 = 1;
 #endif /* LIBXML_SAX1_ENABLED */
 
+    /*
+     * Some users replace the dictionary directly in the context struct.
+     * We really need an API function to do that cleanly.
+     */
     ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3);
     ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5);
     ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36);
     if ((ctxt->str_xml==NULL) || (ctxt->str_xmlns==NULL) ||
 		(ctxt->str_xml_ns == NULL)) {
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
     }
 }
 
@@ -827,65 +1044,6 @@
 }
 
 /**
- * xmlAttrNormalizeSpace2:
- * @src: the source string
- *
- * Normalize the space in non CDATA attribute values, a slightly more complex
- * front end to avoid allocation problems when running on attribute values
- * coming from the input.
- *
- * Returns a pointer to the normalized value (dst) or NULL if no conversion
- *         is needed.
- */
-static const xmlChar *
-xmlAttrNormalizeSpace2(xmlParserCtxtPtr ctxt, xmlChar *src, int *len)
-{
-    int i;
-    int remove_head = 0;
-    int need_realloc = 0;
-    const xmlChar *cur;
-
-    if ((ctxt == NULL) || (src == NULL) || (len == NULL))
-        return(NULL);
-    i = *len;
-    if (i <= 0)
-        return(NULL);
-
-    cur = src;
-    while (*cur == 0x20) {
-        cur++;
-	remove_head++;
-    }
-    while (*cur != 0) {
-	if (*cur == 0x20) {
-	    cur++;
-	    if ((*cur == 0x20) || (*cur == 0)) {
-	        need_realloc = 1;
-		break;
-	    }
-	} else
-	    cur++;
-    }
-    if (need_realloc) {
-        xmlChar *ret;
-
-	ret = xmlStrndup(src + remove_head, i - remove_head + 1);
-	if (ret == NULL) {
-	    xmlErrMemory(ctxt, NULL);
-	    return(NULL);
-	}
-	xmlAttrNormalizeSpace(ret, ret);
-	*len = strlen((const char *)ret);
-        return(ret);
-    } else if (remove_head) {
-        *len -= remove_head;
-        memmove(src, src + remove_head, 1 + *len);
-	return(src);
-    }
-    return(NULL);
-}
-
-/**
  * xmlAddDefAttrs:
  * @ctxt:  an XML parser context
  * @fullname:  the element fullname
@@ -996,13 +1154,13 @@
     attr->prefix = prefix;
     attr->value = hvalue;
     attr->valueEnd = hvalue.name + len;
-    attr->external = ctxt->external;
+    attr->external = PARSER_EXTERNAL(ctxt);
     attr->expandedSize = expandedSize;
 
     return;
 
 mem_error:
-    xmlErrMemory(ctxt, NULL);
+    xmlErrMemory(ctxt);
     return;
 }
 
@@ -1033,7 +1191,7 @@
     return;
 
 mem_error:
-    xmlErrMemory(ctxt, NULL);
+    xmlErrMemory(ctxt);
     return;
 }
 
@@ -1278,8 +1436,8 @@
  *									*
  ************************************************************************/
 
-static xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt,
-                                            const xmlChar ** str);
+static xmlChar *
+xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar **str);
 
 /**
  * xmlParserNsCreate:
@@ -1421,8 +1579,12 @@
     if (prefix->name == ctxt->str_xml)
         return(ctxt->str_xml_ns);
 
+    /*
+     * minNsIndex is used when building an entity tree. We must
+     * ignore namespaces declared outside the entity.
+     */
     nsIndex = xmlParserNsLookup(ctxt, prefix, NULL);
-    if (nsIndex == INT_MAX)
+    if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex))
         return(NULL);
 
     ret = ctxt->nsTab[nsIndex * 2 + 1];
@@ -1455,7 +1617,7 @@
     else
         hprefix.hashValue = 0;
     nsIndex = xmlParserNsLookup(ctxt, &hprefix, NULL);
-    if (nsIndex == INT_MAX)
+    if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex))
         return(NULL);
 
     return(ctxt->nsdb->extra[nsIndex].saxData);
@@ -1488,7 +1650,7 @@
     else
         hprefix.hashValue = 0;
     nsIndex = xmlParserNsLookup(ctxt, &hprefix, NULL);
-    if (nsIndex == INT_MAX)
+    if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex))
         return(-1);
 
     ctxt->nsdb->extra[nsIndex].saxData = saxData;
@@ -1527,7 +1689,7 @@
     return(0);
 
 error:
-    xmlErrMemory(ctxt, NULL);
+    xmlErrMemory(ctxt);
     return(-1);
 }
 
@@ -1556,7 +1718,7 @@
         return(0);
 
     if ((ctxt->nsNr >= ctxt->nsMax) && (xmlParserNsGrow(ctxt) < 0)) {
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
         return(-1);
     }
 
@@ -1622,13 +1784,13 @@
         unsigned newSize, i, index;
 
         if (ctxt->nsdb->hashSize > UINT_MAX / 2) {
-            xmlErrMemory(ctxt, NULL);
+            xmlErrMemory(ctxt);
             return(-1);
         }
         newSize = ctxt->nsdb->hashSize ? ctxt->nsdb->hashSize * 2 : 16;
         newHash = xmlMalloc(newSize * sizeof(newHash[0]));
         if (newHash == NULL) {
-            xmlErrMemory(ctxt, NULL);
+            xmlErrMemory(ctxt);
             return(-1);
         }
         memset(newHash, 0, newSize * sizeof(newHash[0]));
@@ -1756,7 +1918,7 @@
     }
     return(ctxt->maxatts);
 mem_error:
-    xmlErrMemory(ctxt, NULL);
+    xmlErrMemory(ctxt);
     return(-1);
 }
 
@@ -1781,7 +1943,7 @@
         tmp = (xmlParserInputPtr *) xmlRealloc(ctxt->inputTab,
                                                newSize * sizeof(*tmp));
         if (tmp == NULL) {
-            xmlErrMemory(ctxt, NULL);
+            xmlErrMemory(ctxt);
             return (-1);
         }
         ctxt->inputTab = tmp;
@@ -1831,7 +1993,19 @@
 int
 nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value)
 {
-    if (ctxt == NULL) return(0);
+    int maxDepth;
+
+    if (ctxt == NULL)
+        return(0);
+
+    maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256;
+    if (ctxt->nodeNr > maxDepth) {
+        xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT,
+                "Excessive depth in document: %d use XML_PARSE_HUGE option\n",
+                ctxt->nodeNr);
+        xmlHaltParser(ctxt);
+        return(-1);
+    }
     if (ctxt->nodeNr >= ctxt->nodeMax) {
         xmlNodePtr *tmp;
 
@@ -1839,20 +2013,12 @@
                                       ctxt->nodeMax * 2 *
                                       sizeof(ctxt->nodeTab[0]));
         if (tmp == NULL) {
-            xmlErrMemory(ctxt, NULL);
+            xmlErrMemory(ctxt);
             return (-1);
         }
         ctxt->nodeTab = tmp;
 	ctxt->nodeMax *= 2;
     }
-    if ((((unsigned int) ctxt->nodeNr) > xmlParserMaxDepth) &&
-        ((ctxt->options & XML_PARSE_HUGE) == 0)) {
-	xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR,
-		 "Excessive depth in document: %d use XML_PARSE_HUGE option\n",
-			  xmlParserMaxDepth);
-	xmlHaltParser(ctxt);
-	return(-1);
-    }
     ctxt->nodeTab[ctxt->nodeNr] = value;
     ctxt->node = value;
     return (ctxt->nodeNr++);
@@ -1940,7 +2106,7 @@
     tag->nsNr = nsNr;
     return (ctxt->nameNr++);
 mem_error:
-    xmlErrMemory(ctxt, NULL);
+    xmlErrMemory(ctxt);
     return (-1);
 }
 #ifdef LIBXML_PUSH_ENABLED
@@ -2001,7 +2167,7 @@
     ctxt->name = value;
     return (ctxt->nameNr++);
 mem_error:
-    xmlErrMemory(ctxt, NULL);
+    xmlErrMemory(ctxt);
     return (-1);
 }
 
@@ -2040,7 +2206,7 @@
         tmp = (int *) xmlRealloc(ctxt->spaceTab,
 	                         ctxt->spaceMax * sizeof(ctxt->spaceTab[0]));
         if (tmp == NULL) {
-	    xmlErrMemory(ctxt, NULL);
+	    xmlErrMemory(ctxt);
 	    ctxt->spaceMax /=2;
 	    return(-1);
 	}
@@ -2141,18 +2307,21 @@
         xmlParserGrow(ctxt);						\
   } while (0)
 
-/* Don't shrink push parser buffer. */
 #define SHRINK \
-    if (((ctxt->progressive == 0) || (ctxt->inputNr > 1)) && \
+    if ((!PARSER_PROGRESSIVE(ctxt)) && \
         (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \
 	(ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \
 	xmlParserShrink(ctxt);
 
-#define GROW if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)	\
+#define GROW \
+    if ((!PARSER_PROGRESSIVE(ctxt)) && \
+        (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \
 	xmlParserGrow(ctxt);
 
 #define SKIP_BLANKS xmlSkipBlankChars(ctxt)
 
+#define SKIP_BLANKS_PE xmlSkipBlankCharsPE(ctxt)
+
 #define NEXT xmlNextChar(ctxt)
 
 #define NEXT1 {								\
@@ -2182,97 +2351,146 @@
  *
  * DEPRECATED: Internal function, do not use.
  *
- * skip all blanks character found at that point in the input streams.
- * It pops up finished entities in the process if allowable at that point.
+ * Skip whitespace in the input stream.
  *
  * Returns the number of space chars skipped
  */
-
 int
 xmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
+    const xmlChar *cur;
     int res = 0;
 
     /*
      * 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)) ||
-        (ctxt->instate == XML_PARSER_START)) {
-	const xmlChar *cur;
-	/*
-	 * if we are in the document content, go really fast
-	 */
-	cur = ctxt->input->cur;
-	while (IS_BLANK_CH(*cur)) {
-	    if (*cur == '\n') {
-		ctxt->input->line++; ctxt->input->col = 1;
-	    } else {
-		ctxt->input->col++;
-	    }
-	    cur++;
-	    if (res < INT_MAX)
-		res++;
-	    if (*cur == 0) {
-		ctxt->input->cur = cur;
-		xmlParserGrow(ctxt);
-		cur = ctxt->input->cur;
-	    }
-	}
-	ctxt->input->cur = cur;
-    } else {
-        int expandPE = ((ctxt->external != 0) || (ctxt->inputNr != 1));
-
-	while (PARSER_STOPPED(ctxt) == 0) {
-            if (IS_BLANK_CH(CUR)) { /* CHECKED tstblanks.xml */
-		NEXT;
-	    } else if (CUR == '%') {
-                /*
-                 * Need to handle support of entities branching here
-                 */
-	        if ((expandPE == 0) || (IS_BLANK_CH(NXT(1))) || (NXT(1) == 0))
-                    break;
-	        xmlParsePEReference(ctxt);
-            } else if (CUR == 0) {
-                unsigned long consumed;
-                xmlEntityPtr ent;
-
-                if (ctxt->inputNr <= 1)
-                    break;
-
-                consumed = ctxt->input->consumed;
-                xmlSaturatedAddSizeT(&consumed,
-                                     ctxt->input->cur - ctxt->input->base);
-
-                /*
-                 * Add to sizeentities when parsing an external entity
-                 * for the first time.
-                 */
-                ent = ctxt->input->entity;
-                if ((ent->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
-                    ((ent->flags & XML_ENT_PARSED) == 0)) {
-                    ent->flags |= XML_ENT_PARSED;
-
-                    xmlSaturatedAdd(&ctxt->sizeentities, consumed);
-                }
-
-                xmlParserEntityCheck(ctxt, consumed);
-
-                xmlPopInput(ctxt);
-            } else {
-                break;
-            }
-
-            /*
-             * Also increase the counter when entering or exiting a PERef.
-             * The spec says: "When a parameter-entity reference is recognized
-             * in the DTD and included, its replacement text MUST be enlarged
-             * by the attachment of one leading and one following space (#x20)
-             * character."
-             */
-	    if (res < INT_MAX)
-		res++;
+    cur = ctxt->input->cur;
+    while (IS_BLANK_CH(*cur)) {
+        if (*cur == '\n') {
+            ctxt->input->line++; ctxt->input->col = 1;
+        } else {
+            ctxt->input->col++;
+        }
+        cur++;
+        if (res < INT_MAX)
+            res++;
+        if (*cur == 0) {
+            ctxt->input->cur = cur;
+            xmlParserGrow(ctxt);
+            cur = ctxt->input->cur;
         }
     }
+    ctxt->input->cur = cur;
+
+    return(res);
+}
+
+static void
+xmlPopPE(xmlParserCtxtPtr ctxt) {
+    unsigned long consumed;
+    xmlEntityPtr ent;
+
+    ent = ctxt->input->entity;
+
+    ent->flags &= ~XML_ENT_EXPANDING;
+
+    if ((ent->flags & XML_ENT_CHECKED) == 0) {
+        int result;
+
+        /*
+         * Read the rest of the stream in case of errors. We want
+         * to account for the whole entity size.
+         */
+        do {
+            ctxt->input->cur = ctxt->input->end;
+            xmlParserShrink(ctxt);
+            result = xmlParserGrow(ctxt);
+        } while (result > 0);
+
+        consumed = ctxt->input->consumed;
+        xmlSaturatedAddSizeT(&consumed,
+                             ctxt->input->end - ctxt->input->base);
+
+        xmlSaturatedAdd(&ent->expandedSize, consumed);
+
+        /*
+         * Add to sizeentities when parsing an external entity
+         * for the first time.
+         */
+        if (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY) {
+            xmlSaturatedAdd(&ctxt->sizeentities, consumed);
+        }
+
+        ent->flags |= XML_ENT_CHECKED;
+    }
+
+    xmlPopInput(ctxt);
+
+    xmlParserEntityCheck(ctxt, ent->expandedSize);
+}
+
+/**
+ * xmlSkipBlankCharsPE:
+ * @ctxt:  the XML parser context
+ *
+ * Skip whitespace in the input stream, also handling parameter
+ * entities.
+ *
+ * Returns the number of space chars skipped
+ */
+static int
+xmlSkipBlankCharsPE(xmlParserCtxtPtr ctxt) {
+    int res = 0;
+    int inParam;
+    int expandParam;
+
+    inParam = PARSER_IN_PE(ctxt);
+    expandParam = PARSER_EXTERNAL(ctxt);
+
+    if (!inParam && !expandParam)
+        return(xmlSkipBlankChars(ctxt));
+
+    while (PARSER_STOPPED(ctxt) == 0) {
+        if (IS_BLANK_CH(CUR)) { /* CHECKED tstblanks.xml */
+            NEXT;
+        } else if (CUR == '%') {
+            if ((expandParam == 0) ||
+                (IS_BLANK_CH(NXT(1))) || (NXT(1) == 0))
+                break;
+
+            /*
+             * Expand parameter entity. We continue to consume
+             * whitespace at the start of the entity and possible
+             * even consume the whole entity and pop it. We might
+             * even pop multiple PEs in this loop.
+             */
+            xmlParsePEReference(ctxt);
+
+            inParam = PARSER_IN_PE(ctxt);
+            expandParam = PARSER_EXTERNAL(ctxt);
+        } else if (CUR == 0) {
+            if (inParam == 0)
+                break;
+
+            xmlPopPE(ctxt);
+
+            inParam = PARSER_IN_PE(ctxt);
+            expandParam = PARSER_EXTERNAL(ctxt);
+        } else {
+            break;
+        }
+
+        /*
+         * Also increase the counter when entering or exiting a PERef.
+         * The spec says: "When a parameter-entity reference is recognized
+         * in the DTD and included, its replacement text MUST be enlarged
+         * by the attachment of one leading and one following space (#x20)
+         * character."
+         */
+        if (res < INT_MAX)
+            res++;
+    }
+
     return(res);
 }
 
@@ -2296,12 +2514,7 @@
     xmlParserInputPtr input;
 
     if ((ctxt == NULL) || (ctxt->inputNr <= 1)) return(0);
-    if (xmlParserDebugEntities)
-	xmlGenericError(xmlGenericErrorContext,
-		"Popping input %d\n", ctxt->inputNr);
     input = inputPop(ctxt);
-    if (input->entity != NULL)
-        input->entity->flags &= ~XML_ENT_EXPANDING;
     xmlFreeInputStream(input);
     if (*ctxt->input->cur == 0)
         xmlParserGrow(ctxt);
@@ -2313,28 +2526,26 @@
  * @ctxt:  an XML parser context
  * @input:  an XML parser input fragment (entity, XML fragment ...).
  *
- * xmlPushInput: switch to a new input stream which is stacked on top
- *               of the previous one(s).
+ * Push an input stream onto the stack.
+ *
+ * This makes the parser use an input returned from advanced functions
+ * like xmlNewInputURL or xmlNewInputMemory.
+ *
  * Returns -1 in case of error or the index in the input stack
  */
 int
 xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
+    int maxDepth;
     int ret;
-    if (input == NULL) return(-1);
 
-    if (xmlParserDebugEntities) {
-	if ((ctxt->input != NULL) && (ctxt->input->filename))
-	    xmlGenericError(xmlGenericErrorContext,
-		    "%s(%d): ", ctxt->input->filename,
-		    ctxt->input->line);
-	xmlGenericError(xmlGenericErrorContext,
-		"Pushing input %d : %.30s\n", ctxt->inputNr+1, input->cur);
-    }
-    if (((ctxt->inputNr > 40) && ((ctxt->options & XML_PARSE_HUGE) == 0)) ||
-        (ctxt->inputNr > 100)) {
-        xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
-        while (ctxt->inputNr > 1)
-            xmlFreeInputStream(inputPop(ctxt));
+    if ((ctxt == NULL) || (input == NULL))
+        return(-1);
+
+    maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20;
+    if (ctxt->inputNr > maxDepth) {
+        xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT,
+                       "Maximum entity nesting depth exceeded");
+        xmlHaltParser(ctxt);
 	return(-1);
     }
     ret = inputPush(ctxt, input);
@@ -2579,288 +2790,9 @@
  */
 void
 xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) {
-    switch(ctxt->instate) {
-	case XML_PARSER_CDATA_SECTION:
-	    return;
-        case XML_PARSER_COMMENT:
-	    return;
-	case XML_PARSER_START_TAG:
-	    return;
-	case XML_PARSER_END_TAG:
-	    return;
-        case XML_PARSER_EOF:
-	    xmlFatalErr(ctxt, XML_ERR_PEREF_AT_EOF, NULL);
-	    return;
-        case XML_PARSER_PROLOG:
-	case XML_PARSER_START:
-	case XML_PARSER_XML_DECL:
-	case XML_PARSER_MISC:
-	    xmlFatalErr(ctxt, XML_ERR_PEREF_IN_PROLOG, NULL);
-	    return;
-	case XML_PARSER_ENTITY_DECL:
-        case XML_PARSER_CONTENT:
-        case XML_PARSER_ATTRIBUTE_VALUE:
-        case XML_PARSER_PI:
-	case XML_PARSER_SYSTEM_LITERAL:
-	case XML_PARSER_PUBLIC_LITERAL:
-	    /* we just ignore it there */
-	    return;
-        case XML_PARSER_EPILOG:
-	    xmlFatalErr(ctxt, XML_ERR_PEREF_IN_EPILOG, NULL);
-	    return;
-	case XML_PARSER_ENTITY_VALUE:
-	    /*
-	     * NOTE: in the case of entity values, we don't do the
-	     *       substitution here since we need the literal
-	     *       entity value to be able to save the internal
-	     *       subset of the document.
-	     *       This will be handled by xmlStringDecodeEntities
-	     */
-	    return;
-        case XML_PARSER_DTD:
-	    /*
-	     * [WFC: Well-Formedness Constraint: PEs in Internal Subset]
-	     * In the internal DTD subset, parameter-entity references
-	     * can occur only where markup declarations can occur, not
-	     * within markup declarations.
-	     * In that case this is handled in xmlParseMarkupDecl
-	     */
-	    if ((ctxt->external == 0) && (ctxt->inputNr == 1))
-		return;
-	    if (IS_BLANK_CH(NXT(1)) || NXT(1) == 0)
-		return;
-            break;
-        case XML_PARSER_IGNORE:
-            return;
-    }
-
     xmlParsePEReference(ctxt);
 }
 
-/*
- * Macro used to grow the current buffer.
- * buffer##_size is expected to be a size_t
- * mem_error: is expected to handle memory allocation failures
- */
-#define growBuffer(buffer, n) {						\
-    xmlChar *tmp;							\
-    size_t new_size = buffer##_size * 2 + n;                            \
-    if (new_size < buffer##_size) goto mem_error;                       \
-    tmp = (xmlChar *) xmlRealloc(buffer, new_size);                     \
-    if (tmp == NULL) goto mem_error;					\
-    buffer = tmp;							\
-    buffer##_size = new_size;                                           \
-}
-
-/**
- * xmlStringDecodeEntitiesInt:
- * @ctxt:  the parser context
- * @str:  the input string
- * @len: the string length
- * @what:  combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF
- * @end:  an end marker xmlChar, 0 if none
- * @end2:  an end marker xmlChar, 0 if none
- * @end3:  an end marker xmlChar, 0 if none
- * @check:  whether to perform entity checks
- */
-static xmlChar *
-xmlStringDecodeEntitiesInt(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
-		           int what, xmlChar end, xmlChar  end2, xmlChar end3,
-                           int check) {
-    xmlChar *buffer = NULL;
-    size_t buffer_size = 0;
-    size_t nbchars = 0;
-
-    xmlChar *current = NULL;
-    xmlChar *rep = NULL;
-    const xmlChar *last;
-    xmlEntityPtr ent;
-    int c,l;
-
-    if (str == NULL)
-        return(NULL);
-    last = str + len;
-
-    if (((ctxt->depth > 40) &&
-         ((ctxt->options & XML_PARSE_HUGE) == 0)) ||
-	(ctxt->depth > 100)) {
-	xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_LOOP,
-                       "Maximum entity nesting depth exceeded");
-	return(NULL);
-    }
-
-    /*
-     * allocate a translation buffer.
-     */
-    buffer_size = XML_PARSER_BIG_BUFFER_SIZE;
-    buffer = (xmlChar *) xmlMallocAtomic(buffer_size);
-    if (buffer == NULL) goto mem_error;
-
-    /*
-     * OK loop until we reach one of the ending char or a size limit.
-     * we are operating on already parsed values.
-     */
-    if (str < last)
-	c = CUR_SCHAR(str, l);
-    else
-        c = 0;
-    while ((c != 0) && (c != end) && /* non input consuming loop */
-           (c != end2) && (c != end3) &&
-           (PARSER_STOPPED(ctxt) == 0)) {
-
-	if (c == 0) break;
-        if ((c == '&') && (str[1] == '#')) {
-	    int val = xmlParseStringCharRef(ctxt, &str);
-	    if (val == 0)
-                goto int_error;
-	    COPY_BUF(buffer, nbchars, val);
-	    if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) {
-	        growBuffer(buffer, XML_PARSER_BUFFER_SIZE);
-	    }
-	} else if ((c == '&') && (what & XML_SUBSTITUTE_REF)) {
-	    if (xmlParserDebugEntities)
-		xmlGenericError(xmlGenericErrorContext,
-			"String decoding Entity Reference: %.30s\n",
-			str);
-	    ent = xmlParseStringEntityRef(ctxt, &str);
-	    if ((ent != NULL) &&
-		(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
-		if (ent->content != NULL) {
-		    COPY_BUF(buffer, nbchars, ent->content[0]);
-		    if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) {
-			growBuffer(buffer, XML_PARSER_BUFFER_SIZE);
-		    }
-		} else {
-		    xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
-			    "predefined entity has no content\n");
-                    goto int_error;
-		}
-	    } else if ((ent != NULL) && (ent->content != NULL)) {
-	        if ((check) && (xmlParserEntityCheck(ctxt, ent->length)))
-                    goto int_error;
-
-                if (ent->flags & XML_ENT_EXPANDING) {
-	            xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
-                    xmlHaltParser(ctxt);
-                    ent->content[0] = 0;
-                    goto int_error;
-                }
-
-                ent->flags |= XML_ENT_EXPANDING;
-		ctxt->depth++;
-		rep = xmlStringDecodeEntitiesInt(ctxt, ent->content,
-                        ent->length, what, 0, 0, 0, check);
-		ctxt->depth--;
-                ent->flags &= ~XML_ENT_EXPANDING;
-
-		if (rep == NULL) {
-                    ent->content[0] = 0;
-                    goto int_error;
-                }
-
-                current = rep;
-                while (*current != 0) { /* non input consuming loop */
-                    buffer[nbchars++] = *current++;
-                    if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) {
-                        growBuffer(buffer, XML_PARSER_BUFFER_SIZE);
-                    }
-                }
-                xmlFree(rep);
-                rep = NULL;
-	    } else if (ent != NULL) {
-		int i = xmlStrlen(ent->name);
-		const xmlChar *cur = ent->name;
-
-		buffer[nbchars++] = '&';
-		if (nbchars + i + XML_PARSER_BUFFER_SIZE > buffer_size) {
-		    growBuffer(buffer, i + XML_PARSER_BUFFER_SIZE);
-		}
-		for (;i > 0;i--)
-		    buffer[nbchars++] = *cur++;
-		buffer[nbchars++] = ';';
-	    }
-	} else if (c == '%' && (what & XML_SUBSTITUTE_PEREF)) {
-	    if (xmlParserDebugEntities)
-		xmlGenericError(xmlGenericErrorContext,
-			"String decoding PE Reference: %.30s\n", str);
-	    ent = xmlParseStringPEReference(ctxt, &str);
-	    if (ent != NULL) {
-                if (ent->content == NULL) {
-		    /*
-		     * Note: external parsed entities will not be loaded,
-		     * it is not required for a non-validating parser to
-		     * complete external PEReferences coming from the
-		     * internal subset
-		     */
-		    if (((ctxt->options & XML_PARSE_NOENT) != 0) ||
-			((ctxt->options & XML_PARSE_DTDVALID) != 0) ||
-			(ctxt->validate != 0)) {
-			xmlLoadEntityContent(ctxt, ent);
-		    } else {
-			xmlWarningMsg(ctxt, XML_ERR_ENTITY_PROCESSING,
-		  "not validating will not read content for PE entity %s\n",
-		                      ent->name, NULL);
-		    }
-		}
-
-	        if ((check) && (xmlParserEntityCheck(ctxt, ent->length)))
-                    goto int_error;
-
-                if (ent->flags & XML_ENT_EXPANDING) {
-	            xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
-                    xmlHaltParser(ctxt);
-                    if (ent->content != NULL)
-                        ent->content[0] = 0;
-                    goto int_error;
-                }
-
-                ent->flags |= XML_ENT_EXPANDING;
-		ctxt->depth++;
-		rep = xmlStringDecodeEntitiesInt(ctxt, ent->content,
-                        ent->length, what, 0, 0, 0, check);
-		ctxt->depth--;
-                ent->flags &= ~XML_ENT_EXPANDING;
-
-		if (rep == NULL) {
-                    if (ent->content != NULL)
-                        ent->content[0] = 0;
-                    goto int_error;
-                }
-                current = rep;
-                while (*current != 0) { /* non input consuming loop */
-                    buffer[nbchars++] = *current++;
-                    if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) {
-                        growBuffer(buffer, XML_PARSER_BUFFER_SIZE);
-                    }
-                }
-                xmlFree(rep);
-                rep = NULL;
-	    }
-	} else {
-	    COPY_BUF(buffer, nbchars, c);
-	    str += l;
-	    if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) {
-	        growBuffer(buffer, XML_PARSER_BUFFER_SIZE);
-	    }
-	}
-	if (str < last)
-	    c = CUR_SCHAR(str, l);
-	else
-	    c = 0;
-    }
-    buffer[nbchars] = 0;
-    return(buffer);
-
-mem_error:
-    xmlErrMemory(ctxt, NULL);
-int_error:
-    if (rep != NULL)
-        xmlFree(rep);
-    if (buffer != NULL)
-        xmlFree(buffer);
-    return(NULL);
-}
-
 /**
  * xmlStringLenDecodeEntities:
  * @ctxt:  the parser context
@@ -2873,23 +2805,21 @@
  *
  * DEPRECATED: Internal function, don't use.
  *
- * Takes a entity string content and process to do the adequate substitutions.
- *
- * [67] Reference ::= EntityRef | CharRef
- *
- * [69] PEReference ::= '%' Name ';'
- *
  * Returns A newly allocated string with the substitution done. The caller
  *      must deallocate it !
  */
 xmlChar *
 xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
-                           int what, xmlChar end, xmlChar  end2,
-                           xmlChar end3) {
+                           int what ATTRIBUTE_UNUSED,
+                           xmlChar end, xmlChar end2, xmlChar end3) {
     if ((ctxt == NULL) || (str == NULL) || (len < 0))
         return(NULL);
-    return(xmlStringDecodeEntitiesInt(ctxt, str, len, what,
-                                      end, end2, end3, 0));
+
+    if ((str[len] != 0) ||
+        (end != 0) || (end2 != 0) || (end3 != 0))
+        return(NULL);
+
+    return(xmlExpandEntitiesInAttValue(ctxt, str, 0));
 }
 
 /**
@@ -2903,21 +2833,20 @@
  *
  * DEPRECATED: Internal function, don't use.
  *
- * Takes a entity string content and process to do the adequate substitutions.
- *
- * [67] Reference ::= EntityRef | CharRef
- *
- * [69] PEReference ::= '%' Name ';'
- *
  * Returns A newly allocated string with the substitution done. The caller
  *      must deallocate it !
  */
 xmlChar *
-xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what,
+xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str,
+                        int what ATTRIBUTE_UNUSED,
 		        xmlChar end, xmlChar  end2, xmlChar end3) {
-    if ((ctxt == NULL) || (str == NULL)) return(NULL);
-    return(xmlStringDecodeEntitiesInt(ctxt, str, xmlStrlen(str), what,
-                                      end, end2, end3, 0));
+    if ((ctxt == NULL) || (str == NULL))
+        return(NULL);
+
+    if ((end != 0) || (end2 != 0) || (end3 != 0))
+        return(NULL);
+
+    return(xmlExpandEntitiesInAttValue(ctxt, str, 0));
 }
 
 /************************************************************************
@@ -3076,7 +3005,7 @@
 
 	buffer = (xmlChar *) xmlMallocAtomic(max);
 	if (buffer == NULL) {
-	    xmlErrMemory(ctxt, NULL);
+	    xmlErrMemory(ctxt);
 	    return(NULL);
 	}
 	memcpy(buffer, buf, len);
@@ -3088,7 +3017,7 @@
 		tmp = (xmlChar *) xmlRealloc(buffer, max);
 		if (tmp == NULL) {
 		    xmlFree(buffer);
-		    xmlErrMemory(ctxt, NULL);
+		    xmlErrMemory(ctxt);
 		    return(NULL);
 		}
 		buffer = tmp;
@@ -3108,7 +3037,7 @@
     if (buffer == NULL) {
 	ret = xmlStrndup(buf, len);
         if (ret == NULL) {
-	    xmlErrMemory(ctxt, NULL);
+	    xmlErrMemory(ctxt);
 	    return(NULL);
         }
     } else {
@@ -3163,7 +3092,7 @@
 
 	    buffer = (xmlChar *) xmlMallocAtomic(max);
 	    if (buffer == NULL) {
-	        xmlErrMemory(ctxt, NULL);
+	        xmlErrMemory(ctxt);
                 xmlFree(prefix);
 		return(NULL);
 	    }
@@ -3175,7 +3104,7 @@
 		    max *= 2;
 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
 		    if (tmp == NULL) {
-			xmlErrMemory(ctxt, NULL);
+			xmlErrMemory(ctxt);
                         xmlFree(prefix);
 			xmlFree(buffer);
 			return(NULL);
@@ -3297,9 +3226,6 @@
     return(0);
 }
 
-static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt,
-                                          int *len, int *alloc, int normalize);
-
 static const xmlChar *
 xmlParseNameComplex(xmlParserCtxtPtr ctxt) {
     const xmlChar *ret;
@@ -3406,7 +3332,7 @@
     else
         ret = xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len);
     if (ret == NULL)
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
     return(ret);
 }
 
@@ -3463,7 +3389,7 @@
 	    ctxt->input->cur = in;
 	    ctxt->input->col += count;
 	    if (ret == NULL)
-	        xmlErrMemory(ctxt, NULL);
+	        xmlErrMemory(ctxt);
 	    return(ret);
 	}
     }
@@ -3507,7 +3433,7 @@
     }
     ret = xmlDictLookupHashed(ctxt->dict, (BASE_PTR + startPosition), len);
     if (ret.name == NULL)
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
     return(ret);
 }
 
@@ -3564,7 +3490,7 @@
 	    ctxt->input->cur = in;
 	    ctxt->input->col += count;
 	    if (ret.name == NULL) {
-	        xmlErrMemory(ctxt, NULL);
+	        xmlErrMemory(ctxt);
 	    }
 	    return(ret);
 	}
@@ -3663,7 +3589,7 @@
 
 	    buffer = (xmlChar *) xmlMallocAtomic(max);
 	    if (buffer == NULL) {
-	        xmlErrMemory(ctxt, NULL);
+	        xmlErrMemory(ctxt);
 		return(NULL);
 	    }
 	    memcpy(buffer, buf, len);
@@ -3674,7 +3600,7 @@
 		    max *= 2;
 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
 		    if (tmp == NULL) {
-			xmlErrMemory(ctxt, NULL);
+			xmlErrMemory(ctxt);
 			xmlFree(buffer);
 			return(NULL);
 		    }
@@ -3701,7 +3627,7 @@
     *str = cur;
     ret = xmlStrndup(buf, len);
     if (ret == NULL)
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
     return(ret);
 }
 
@@ -3746,7 +3672,7 @@
 
 	    buffer = (xmlChar *) xmlMallocAtomic(max);
 	    if (buffer == NULL) {
-	        xmlErrMemory(ctxt, NULL);
+	        xmlErrMemory(ctxt);
 		return(NULL);
 	    }
 	    memcpy(buffer, buf, len);
@@ -3757,7 +3683,7 @@
 		    max *= 2;
 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
 		    if (tmp == NULL) {
-			xmlErrMemory(ctxt, NULL);
+			xmlErrMemory(ctxt);
 			xmlFree(buffer);
 			return(NULL);
 		    }
@@ -3784,11 +3710,162 @@
     }
     ret = xmlStrndup(buf, len);
     if (ret == NULL)
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
     return(ret);
 }
 
 /**
+ * xmlExpandPEsInEntityValue:
+ * @ctxt:  parser context
+ * @buf:  string buffer
+ * @str:  entity value
+ * @length:  size of entity value
+ * @depth:  nesting depth
+ *
+ * Validate an entity value and expand parameter entities.
+ */
+static void
+xmlExpandPEsInEntityValue(xmlParserCtxtPtr ctxt, xmlSBuf *buf,
+                          const xmlChar *str, int length, int depth) {
+    int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20;
+    const xmlChar *end, *chunk;
+    int c, l;
+
+    if (str == NULL)
+        return;
+
+    depth += 1;
+    if (depth > maxDepth) {
+	xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT,
+                       "Maximum entity nesting depth exceeded");
+	return;
+    }
+
+    end = str + length;
+    chunk = str;
+
+    while ((str < end) && (!PARSER_STOPPED(ctxt))) {
+        c = *str;
+
+        if (c >= 0x80) {
+            l = xmlUTF8MultibyteLen(ctxt, str,
+                    "invalid character in entity value\n");
+            if (l == 0) {
+                if (chunk < str)
+                    xmlSBufAddString(buf, chunk, str - chunk);
+                xmlSBufAddReplChar(buf);
+                str += 1;
+                chunk = str;
+            } else {
+                str += l;
+            }
+        } else if (c == '&') {
+            if (str[1] == '#') {
+                if (chunk < str)
+                    xmlSBufAddString(buf, chunk, str - chunk);
+
+                c = xmlParseStringCharRef(ctxt, &str);
+                if (c == 0)
+                    return;
+
+                xmlSBufAddChar(buf, c);
+
+                chunk = str;
+            } else {
+                xmlChar *name;
+
+                /*
+                 * General entity references are checked for
+                 * syntactic validity.
+                 */
+                str++;
+                name = xmlParseStringName(ctxt, &str);
+
+                if ((name == NULL) || (*str++ != ';')) {
+                    xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_CHAR_ERROR,
+                            "EntityValue: '&' forbidden except for entities "
+                            "references\n");
+                    xmlFree(name);
+                    return;
+                }
+
+                xmlFree(name);
+            }
+        } else if (c == '%') {
+            xmlEntityPtr ent;
+
+            if (chunk < str)
+                xmlSBufAddString(buf, chunk, str - chunk);
+
+            ent = xmlParseStringPEReference(ctxt, &str);
+            if (ent == NULL)
+                return;
+
+            if (!PARSER_EXTERNAL(ctxt)) {
+                xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL);
+                return;
+            }
+
+            if (ent->content == NULL) {
+                /*
+                 * Note: external parsed entities will not be loaded,
+                 * it is not required for a non-validating parser to
+                 * complete external PEReferences coming from the
+                 * internal subset
+                 */
+                if (((ctxt->options & XML_PARSE_NO_XXE) == 0) &&
+                    ((ctxt->replaceEntities) ||
+                     (ctxt->validate))) {
+                    xmlLoadEntityContent(ctxt, ent);
+                } else {
+                    xmlWarningMsg(ctxt, XML_ERR_ENTITY_PROCESSING,
+                                  "not validating will not read content for "
+                                  "PE entity %s\n", ent->name, NULL);
+                }
+            }
+
+            /*
+             * TODO: Skip if ent->content is still NULL.
+             */
+
+            if (xmlParserEntityCheck(ctxt, ent->length))
+                return;
+
+            if (ent->flags & XML_ENT_EXPANDING) {
+                xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
+                xmlHaltParser(ctxt);
+                return;
+            }
+
+            ent->flags |= XML_ENT_EXPANDING;
+            xmlExpandPEsInEntityValue(ctxt, buf, ent->content, ent->length,
+                                      depth);
+            ent->flags &= ~XML_ENT_EXPANDING;
+
+            chunk = str;
+        } else {
+            /* Normal ASCII char */
+            if (!IS_BYTE_CHAR(c)) {
+                xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR,
+                        "invalid character in entity value\n");
+                if (chunk < str)
+                    xmlSBufAddString(buf, chunk, str - chunk);
+                xmlSBufAddReplChar(buf);
+                str += 1;
+                chunk = str;
+            } else {
+                str += 1;
+            }
+        }
+    }
+
+    if (chunk < str)
+        xmlSBufAddString(buf, chunk, str - chunk);
+
+    return;
+}
+
+/**
  * xmlParseEntityValue:
  * @ctxt:  an XML parser context
  * @orig:  if non-NULL store a copy of the original entity value
@@ -3802,398 +3879,636 @@
  *
  * Returns the EntityValue parsed with reference substituted or NULL
  */
-
 xmlChar *
 xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) {
-    xmlChar *buf = NULL;
-    int len = 0;
-    int size = XML_PARSER_BUFFER_SIZE;
-    int c, l;
-    int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
-                    XML_MAX_HUGE_LENGTH :
-                    XML_MAX_TEXT_LENGTH;
-    xmlChar stop;
-    xmlChar *ret = NULL;
-    const xmlChar *cur = NULL;
-    xmlParserInputPtr input;
+    unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+                         XML_MAX_HUGE_LENGTH :
+                         XML_MAX_TEXT_LENGTH;
+    xmlSBuf buf;
+    const xmlChar *start;
+    int quote, length;
 
-    if (RAW == '"') stop = '"';
-    else if (RAW == '\'') stop = '\'';
-    else {
-	xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_STARTED, NULL);
-	return(NULL);
-    }
-    buf = (xmlChar *) xmlMallocAtomic(size);
-    if (buf == NULL) {
-	xmlErrMemory(ctxt, NULL);
-	return(NULL);
-    }
+    xmlSBufInit(&buf, maxLength);
 
-    /*
-     * The content of the entity definition is copied in a buffer.
-     */
-
-    ctxt->instate = XML_PARSER_ENTITY_VALUE;
-    input = ctxt->input;
     GROW;
-    NEXT;
-    c = CUR_CHAR(l);
-    /*
-     * NOTE: 4.4.5 Included in Literal
-     * When a parameter entity reference appears in a literal entity
-     * value, ... a single or double quote character in the replacement
-     * text is always treated as a normal data character and will not
-     * terminate the literal.
-     * In practice it means we stop the loop only when back at parsing
-     * the initial entity and the quote is found
-     */
-    while (((IS_CHAR(c)) && ((c != stop) || /* checked */
-	    (ctxt->input != input))) && (PARSER_STOPPED(ctxt) == 0)) {
-	if (len + 5 >= size) {
-	    xmlChar *tmp;
 
-	    size *= 2;
-	    tmp = (xmlChar *) xmlRealloc(buf, size);
-	    if (tmp == NULL) {
-		xmlErrMemory(ctxt, NULL);
-                goto error;
-	    }
-	    buf = tmp;
-	}
-	COPY_BUF(buf, len, c);
-	NEXTL(l);
-
-	GROW;
-	c = CUR_CHAR(l);
-	if (c == 0) {
-	    GROW;
-	    c = CUR_CHAR(l);
-	}
-
-        if (len > maxLength) {
-            xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_NOT_FINISHED,
-                           "entity value too long\n");
-            goto error;
-        }
-    }
-    buf[len] = 0;
-    if (c != stop) {
-        xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL);
-        goto error;
-    }
-    NEXT;
-
-    /*
-     * Raise problem w.r.t. '&' and '%' being used in non-entities
-     * reference constructs. Note Charref will be handled in
-     * xmlStringDecodeEntities()
-     */
-    cur = buf;
-    while (*cur != 0) { /* non input consuming */
-	if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) {
-	    xmlChar *name;
-	    xmlChar tmp = *cur;
-            int nameOk = 0;
-
-	    cur++;
-	    name = xmlParseStringName(ctxt, &cur);
-            if (name != NULL) {
-                nameOk = 1;
-                xmlFree(name);
-            }
-            if ((nameOk == 0) || (*cur != ';')) {
-		xmlFatalErrMsgInt(ctxt, XML_ERR_ENTITY_CHAR_ERROR,
-	    "EntityValue: '%c' forbidden except for entities references\n",
-	                          tmp);
-                goto error;
-	    }
-	    if ((tmp == '%') && (ctxt->inSubset == 1) &&
-		(ctxt->inputNr == 1)) {
-		xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL);
-                goto error;
-	    }
-	    if (*cur == 0)
-	        break;
-	}
-	cur++;
-    }
-
-    /*
-     * Then PEReference entities are substituted.
-     *
-     * NOTE: 4.4.7 Bypassed
-     * When a general entity reference appears in the EntityValue in
-     * an entity declaration, it is bypassed and left as is.
-     * so XML_SUBSTITUTE_REF is not set here.
-     */
-    ++ctxt->depth;
-    ret = xmlStringDecodeEntitiesInt(ctxt, buf, len, XML_SUBSTITUTE_PEREF,
-                                     0, 0, 0, /* check */ 1);
-    --ctxt->depth;
-
-    if (orig != NULL) {
-        *orig = buf;
-        buf = NULL;
-    }
-
-error:
-    if (buf != NULL)
-        xmlFree(buf);
-    return(ret);
-}
-
-/**
- * xmlParseAttValueComplex:
- * @ctxt:  an XML parser context
- * @len:   the resulting attribute len
- * @normalize:  whether to apply the inner normalization
- *
- * parse a value for an attribute, this is the fallback function
- * of xmlParseAttValue() when the attribute parsing requires handling
- * of non-ASCII characters, or normalization compaction.
- *
- * Returns the AttValue parsed or NULL. The value has to be freed by the caller.
- */
-static xmlChar *
-xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
-    xmlChar limit = 0;
-    xmlChar *buf = NULL;
-    xmlChar *rep = NULL;
-    size_t len = 0;
-    size_t buf_size = 0;
-    size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
-                       XML_MAX_HUGE_LENGTH :
-                       XML_MAX_TEXT_LENGTH;
-    int c, l, in_space = 0;
-    xmlChar *current = NULL;
-    xmlEntityPtr ent;
-
-    if (NXT(0) == '"') {
-	ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
-	limit = '"';
-        NEXT;
-    } else if (NXT(0) == '\'') {
-	limit = '\'';
-	ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
-        NEXT;
-    } else {
+    quote = CUR;
+    if ((quote != '"') && (quote != '\'')) {
 	xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL);
 	return(NULL);
     }
+    CUR_PTR++;
+
+    length = 0;
 
     /*
-     * allocate a translation buffer.
+     * Copy raw content of the entity into a buffer
      */
-    buf_size = XML_PARSER_BUFFER_SIZE;
-    buf = (xmlChar *) xmlMallocAtomic(buf_size);
-    if (buf == NULL) goto mem_error;
+    while (1) {
+        int c;
 
-    /*
-     * OK loop until we reach one of the ending char or a size limit.
-     */
-    c = CUR_CHAR(l);
-    while (((NXT(0) != limit) && /* checked */
-            (IS_CHAR(c)) && (c != '<')) &&
-            (PARSER_STOPPED(ctxt) == 0)) {
-	if (c == '&') {
-	    in_space = 0;
-	    if (NXT(1) == '#') {
-		int val = xmlParseCharRef(ctxt);
+        if (PARSER_STOPPED(ctxt))
+            goto error;
 
-		if (val == '&') {
-		    if (ctxt->replaceEntities) {
-			if (len + 10 > buf_size) {
-			    growBuffer(buf, 10);
-			}
-			buf[len++] = '&';
-		    } else {
-			/*
-			 * The reparsing will be done in xmlStringGetNodeList()
-			 * called by the attribute() function in SAX.c
-			 */
-			if (len + 10 > buf_size) {
-			    growBuffer(buf, 10);
-			}
-			buf[len++] = '&';
-			buf[len++] = '#';
-			buf[len++] = '3';
-			buf[len++] = '8';
-			buf[len++] = ';';
-		    }
-		} else if (val != 0) {
-		    if (len + 10 > buf_size) {
-			growBuffer(buf, 10);
-		    }
-		    len += xmlCopyChar(0, &buf[len], val);
-		}
-	    } else {
-		ent = xmlParseEntityRef(ctxt);
-		if ((ent != NULL) &&
-		    (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
-		    if (len + 10 > buf_size) {
-			growBuffer(buf, 10);
-		    }
-		    if ((ctxt->replaceEntities == 0) &&
-		        (ent->content[0] == '&')) {
-			buf[len++] = '&';
-			buf[len++] = '#';
-			buf[len++] = '3';
-			buf[len++] = '8';
-			buf[len++] = ';';
-		    } else {
-			buf[len++] = ent->content[0];
-		    }
-		} else if ((ent != NULL) &&
-		           (ctxt->replaceEntities != 0)) {
-		    if (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) {
-                        if (xmlParserEntityCheck(ctxt, ent->length))
-                            goto error;
-
-			++ctxt->depth;
-			rep = xmlStringDecodeEntitiesInt(ctxt, ent->content,
-                                ent->length, XML_SUBSTITUTE_REF, 0, 0, 0,
-                                /* check */ 1);
-			--ctxt->depth;
-			if (rep != NULL) {
-			    current = rep;
-			    while (*current != 0) { /* non input consuming */
-                                if ((*current == 0xD) || (*current == 0xA) ||
-                                    (*current == 0x9)) {
-                                    buf[len++] = 0x20;
-                                    current++;
-                                } else
-                                    buf[len++] = *current++;
-				if (len + 10 > buf_size) {
-				    growBuffer(buf, 10);
-				}
-			    }
-			    xmlFree(rep);
-			    rep = NULL;
-			}
-		    } else {
-			if (len + 10 > buf_size) {
-			    growBuffer(buf, 10);
-			}
-			if (ent->content != NULL)
-			    buf[len++] = ent->content[0];
-		    }
-		} else if (ent != NULL) {
-		    int i = xmlStrlen(ent->name);
-		    const xmlChar *cur = ent->name;
-
-		    /*
-                     * We also check for recursion and amplification
-                     * when entities are not substituted. They're
-                     * often expanded later.
-		     */
-		    if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) &&
-			(ent->content != NULL)) {
-                        if ((ent->flags & XML_ENT_CHECKED) == 0) {
-                            unsigned long oldCopy = ctxt->sizeentcopy;
-
-                            ctxt->sizeentcopy = ent->length;
-
-                            ++ctxt->depth;
-                            rep = xmlStringDecodeEntitiesInt(ctxt,
-                                    ent->content, ent->length,
-                                    XML_SUBSTITUTE_REF, 0, 0, 0,
-                                    /* check */ 1);
-                            --ctxt->depth;
-
-                            /*
-                             * If we're parsing DTD content, the entity
-                             * might reference other entities which
-                             * weren't defined yet, so the check isn't
-                             * reliable.
-                             */
-                            if (ctxt->inSubset == 0) {
-                                ent->flags |= XML_ENT_CHECKED;
-                                ent->expandedSize = ctxt->sizeentcopy;
-                            }
-
-                            if (rep != NULL) {
-                                xmlFree(rep);
-                                rep = NULL;
-                            } else {
-                                ent->content[0] = 0;
-                            }
-
-                            if (xmlParserEntityCheck(ctxt, oldCopy))
-                                goto error;
-                        } else {
-                            if (xmlParserEntityCheck(ctxt, ent->expandedSize))
-                                goto error;
-                        }
-		    }
-
-		    /*
-		     * Just output the reference
-		     */
-		    buf[len++] = '&';
-		    while (len + i + 10 > buf_size) {
-			growBuffer(buf, i + 10);
-		    }
-		    for (;i > 0;i--)
-			buf[len++] = *cur++;
-		    buf[len++] = ';';
-		}
-	    }
-	} else {
-	    if ((c == 0x20) || (c == 0xD) || (c == 0xA) || (c == 0x9)) {
-	        if ((len != 0) || (!normalize)) {
-		    if ((!normalize) || (!in_space)) {
-			COPY_BUF(buf, len, 0x20);
-			while (len + 10 > buf_size) {
-			    growBuffer(buf, 10);
-			}
-		    }
-		    in_space = 1;
-		}
-	    } else {
-	        in_space = 0;
-		COPY_BUF(buf, len, c);
-		if (len + 10 > buf_size) {
-		    growBuffer(buf, 10);
-		}
-	    }
-	    NEXTL(l);
-	}
-	GROW;
-	c = CUR_CHAR(l);
-        if (len > maxLength) {
-            xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
-                           "AttValue length too long\n");
+        if (CUR_PTR >= ctxt->input->end) {
+            xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL);
             goto error;
         }
-    }
 
-    if ((in_space) && (normalize)) {
-        while ((len > 0) && (buf[len - 1] == 0x20)) len--;
-    }
-    buf[len] = 0;
-    if (RAW == '<') {
-	xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL);
-    } else if (RAW != limit) {
-	if ((c != 0) && (!IS_CHAR(c))) {
-	    xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR,
-			   "invalid character in attribute value\n");
-	} else {
-	    xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
-			   "AttValue: ' expected\n");
+        c = CUR;
+
+        if (c == 0) {
+            xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR,
+                    "invalid character in entity value\n");
+            goto error;
         }
-    } else
-	NEXT;
+        if (c == quote)
+            break;
+        NEXTL(1);
+        length += 1;
 
-    if (attlen != NULL) *attlen = len;
-    return(buf);
+        /*
+         * TODO: Check growth threshold
+         */
+        if (ctxt->input->end - CUR_PTR < 10)
+            GROW;
+    }
 
-mem_error:
-    xmlErrMemory(ctxt, NULL);
+    start = CUR_PTR - length;
+
+    if (orig != NULL) {
+        *orig = xmlStrndup(start, length);
+        if (*orig == NULL)
+            xmlErrMemory(ctxt);
+    }
+
+    xmlExpandPEsInEntityValue(ctxt, &buf, start, length, ctxt->inputNr);
+
+    NEXTL(1);
+
+    return(xmlSBufFinish(&buf, NULL, ctxt, "entity length too long"));
+
 error:
-    if (buf != NULL)
-        xmlFree(buf);
-    if (rep != NULL)
-        xmlFree(rep);
+    xmlSBufCleanup(&buf, ctxt, "entity length too long");
+    return(NULL);
+}
+
+/**
+ * xmlCheckEntityInAttValue:
+ * @ctxt:  parser context
+ * @pent:  entity
+ * @depth:  nesting depth
+ *
+ * Check an entity reference in an attribute value for validity
+ * without expanding it.
+ */
+static void
+xmlCheckEntityInAttValue(xmlParserCtxtPtr ctxt, xmlEntityPtr pent, int depth) {
+    int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20;
+    const xmlChar *str;
+    unsigned long expandedSize = pent->length;
+    int c, flags;
+
+    depth += 1;
+    if (depth > maxDepth) {
+	xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT,
+                       "Maximum entity nesting depth exceeded");
+	return;
+    }
+
+    if (pent->flags & XML_ENT_EXPANDING) {
+        xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
+        xmlHaltParser(ctxt);
+        return;
+    }
+
+    /*
+     * If we're parsing a default attribute value in DTD content,
+     * the entity might reference other entities which weren't
+     * defined yet, so the check isn't reliable.
+     */
+    if (ctxt->inSubset == 0)
+        flags = XML_ENT_CHECKED | XML_ENT_VALIDATED;
+    else
+        flags = XML_ENT_VALIDATED;
+
+    str = pent->content;
+    if (str == NULL)
+        goto done;
+
+    /*
+     * Note that entity values are already validated. We only check
+     * for illegal less-than signs and compute the expanded size
+     * of the entity. No special handling for multi-byte characters
+     * is needed.
+     */
+    while (!PARSER_STOPPED(ctxt)) {
+        c = *str;
+
+	if (c != '&') {
+            if (c == 0)
+                break;
+
+            if (c == '<')
+                xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE,
+                        "'<' in entity '%s' is not allowed in attributes "
+                        "values\n", pent->name);
+
+            str += 1;
+        } else if (str[1] == '#') {
+            int val;
+
+	    val = xmlParseStringCharRef(ctxt, &str);
+	    if (val == 0) {
+                pent->content[0] = 0;
+                break;
+            }
+	} else {
+            xmlChar *name;
+            xmlEntityPtr ent;
+
+	    name = xmlParseStringEntityRef(ctxt, &str);
+	    if (name == NULL) {
+                pent->content[0] = 0;
+                break;
+            }
+
+            ent = xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 1);
+            xmlFree(name);
+
+            if ((ent != NULL) &&
+                (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) {
+                if ((ent->flags & flags) != flags) {
+                    pent->flags |= XML_ENT_EXPANDING;
+                    xmlCheckEntityInAttValue(ctxt, ent, depth);
+                    pent->flags &= ~XML_ENT_EXPANDING;
+                }
+
+                xmlSaturatedAdd(&expandedSize, ent->expandedSize);
+                xmlSaturatedAdd(&expandedSize, XML_ENT_FIXED_COST);
+            }
+        }
+    }
+
+done:
+    if (ctxt->inSubset == 0)
+        pent->expandedSize = expandedSize;
+
+    pent->flags |= flags;
+}
+
+/**
+ * xmlExpandEntityInAttValue:
+ * @ctxt:  parser context
+ * @buf:  string buffer
+ * @str:  entity or attribute value
+ * @pent:  entity for entity value, NULL for attribute values
+ * @normalize:  whether to collapse whitespace
+ * @inSpace:  whitespace state
+ * @depth:  nesting depth
+ * @check:  whether to check for amplification
+ *
+ * Expand general entity references in an entity or attribute value.
+ * Perform attribute value normalization.
+ */
+static void
+xmlExpandEntityInAttValue(xmlParserCtxtPtr ctxt, xmlSBuf *buf,
+                          const xmlChar *str, xmlEntityPtr pent, int normalize,
+                          int *inSpace, int depth, int check) {
+    int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20;
+    int c, chunkSize;
+
+    if (str == NULL)
+        return;
+
+    depth += 1;
+    if (depth > maxDepth) {
+	xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT,
+                       "Maximum entity nesting depth exceeded");
+	return;
+    }
+
+    if (pent != NULL) {
+        if (pent->flags & XML_ENT_EXPANDING) {
+            xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
+            xmlHaltParser(ctxt);
+            return;
+        }
+
+        if (check) {
+            if (xmlParserEntityCheck(ctxt, pent->length))
+                return;
+        }
+    }
+
+    chunkSize = 0;
+
+    /*
+     * Note that entity values are already validated. No special
+     * handling for multi-byte characters is needed.
+     */
+    while (!PARSER_STOPPED(ctxt)) {
+        c = *str;
+
+	if (c != '&') {
+            if (c == 0)
+                break;
+
+            /*
+             * If this function is called without an entity, it is used to
+             * expand entities in an attribute content where less-than was
+             * already unscaped and is allowed.
+             */
+            if ((pent != NULL) && (c == '<')) {
+                xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE,
+                        "'<' in entity '%s' is not allowed in attributes "
+                        "values\n", pent->name);
+                break;
+            }
+
+            if (c <= 0x20) {
+                if ((normalize) && (*inSpace)) {
+                    /* Skip char */
+                    if (chunkSize > 0) {
+                        xmlSBufAddString(buf, str - chunkSize, chunkSize);
+                        chunkSize = 0;
+                    }
+                } else if (c < 0x20) {
+                    if (chunkSize > 0) {
+                        xmlSBufAddString(buf, str - chunkSize, chunkSize);
+                        chunkSize = 0;
+                    }
+
+                    xmlSBufAddCString(buf, " ", 1);
+                } else {
+                    chunkSize += 1;
+                }
+
+                *inSpace = 1;
+            } else {
+                chunkSize += 1;
+                *inSpace = 0;
+            }
+
+            str += 1;
+        } else if (str[1] == '#') {
+            int val;
+
+            if (chunkSize > 0) {
+                xmlSBufAddString(buf, str - chunkSize, chunkSize);
+                chunkSize = 0;
+            }
+
+	    val = xmlParseStringCharRef(ctxt, &str);
+	    if (val == 0) {
+                if (pent != NULL)
+                    pent->content[0] = 0;
+                break;
+            }
+
+            if (val == ' ') {
+                if ((!normalize) || (!*inSpace))
+                    xmlSBufAddCString(buf, " ", 1);
+                *inSpace = 1;
+            } else {
+                xmlSBufAddChar(buf, val);
+                *inSpace = 0;
+            }
+	} else {
+            xmlChar *name;
+            xmlEntityPtr ent;
+
+            if (chunkSize > 0) {
+                xmlSBufAddString(buf, str - chunkSize, chunkSize);
+                chunkSize = 0;
+            }
+
+	    name = xmlParseStringEntityRef(ctxt, &str);
+            if (name == NULL) {
+                if (pent != NULL)
+                    pent->content[0] = 0;
+                break;
+            }
+
+            ent = xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 1);
+            xmlFree(name);
+
+	    if ((ent != NULL) &&
+		(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
+		if (ent->content == NULL) {
+		    xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
+			    "predefined entity has no content\n");
+                    break;
+                }
+
+                xmlSBufAddString(buf, ent->content, ent->length);
+
+                *inSpace = 0;
+	    } else if ((ent != NULL) && (ent->content != NULL)) {
+                if (pent != NULL)
+                    pent->flags |= XML_ENT_EXPANDING;
+		xmlExpandEntityInAttValue(ctxt, buf, ent->content, ent,
+                                          normalize, inSpace, depth, check);
+                if (pent != NULL)
+                    pent->flags &= ~XML_ENT_EXPANDING;
+	    }
+        }
+    }
+
+    if (chunkSize > 0)
+        xmlSBufAddString(buf, str - chunkSize, chunkSize);
+
+    return;
+}
+
+/**
+ * xmlExpandEntitiesInAttValue:
+ * @ctxt:  parser context
+ * @str:  entity or attribute value
+ * @normalize:  whether to collapse whitespace
+ *
+ * Expand general entity references in an entity or attribute value.
+ * Perform attribute value normalization.
+ *
+ * Returns the expanded attribtue value.
+ */
+xmlChar *
+xmlExpandEntitiesInAttValue(xmlParserCtxtPtr ctxt, const xmlChar *str,
+                            int normalize) {
+    unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+                         XML_MAX_HUGE_LENGTH :
+                         XML_MAX_TEXT_LENGTH;
+    xmlSBuf buf;
+    int inSpace = 1;
+
+    xmlSBufInit(&buf, maxLength);
+
+    xmlExpandEntityInAttValue(ctxt, &buf, str, NULL, normalize, &inSpace,
+                              ctxt->inputNr, /* check */ 0);
+
+    if ((normalize) && (inSpace) && (buf.size > 0))
+        buf.size--;
+
+    return(xmlSBufFinish(&buf, NULL, ctxt, "AttValue length too long"));
+}
+
+/**
+ * xmlParseAttValueInternal:
+ * @ctxt:  an XML parser context
+ * @len:  attribute len result
+ * @alloc:  whether the attribute was reallocated as a new string
+ * @normalize:  if 1 then further non-CDATA normalization must be done
+ *
+ * parse a value for an attribute.
+ * NOTE: if no normalization is needed, the routine will return pointers
+ *       directly from the data buffer.
+ *
+ * 3.3.3 Attribute-Value Normalization:
+ * Before the value of an attribute is passed to the application or
+ * checked for validity, the XML processor must normalize it as follows:
+ * - a character reference is processed by appending the referenced
+ *   character to the attribute value
+ * - an entity reference is processed by recursively processing the
+ *   replacement text of the entity
+ * - a whitespace character (#x20, #xD, #xA, #x9) is processed by
+ *   appending #x20 to the normalized value, except that only a single
+ *   #x20 is appended for a "#xD#xA" sequence that is part of an external
+ *   parsed entity or the literal entity value of an internal parsed entity
+ * - other characters are processed by appending them to the normalized value
+ * If the declared value is not CDATA, then the XML processor must further
+ * process the normalized attribute value by discarding any leading and
+ * trailing space (#x20) characters, and by replacing sequences of space
+ * (#x20) characters by a single space (#x20) character.
+ * All attributes for which no declaration has been read should be treated
+ * by a non-validating parser as if declared CDATA.
+ *
+ * Returns the AttValue parsed or NULL. The value has to be freed by the
+ *     caller if it was copied, this can be detected by val[*len] == 0.
+ */
+static xmlChar *
+xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *attlen, int *alloc,
+                         int normalize) {
+    unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+                         XML_MAX_HUGE_LENGTH :
+                         XML_MAX_TEXT_LENGTH;
+    xmlSBuf buf;
+    xmlChar *ret;
+    int c, l, quote, flags, chunkSize;
+    int inSpace = 1;
+
+    xmlSBufInit(&buf, maxLength);
+
+    GROW;
+
+    quote = CUR;
+    if ((quote != '"') && (quote != '\'')) {
+	xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL);
+	return(NULL);
+    }
+    NEXTL(1);
+
+    if (ctxt->inSubset == 0)
+        flags = XML_ENT_CHECKED | XML_ENT_VALIDATED;
+    else
+        flags = XML_ENT_VALIDATED;
+
+    inSpace = 1;
+    chunkSize = 0;
+
+    while (1) {
+        if (PARSER_STOPPED(ctxt))
+            goto error;
+
+        if (CUR_PTR >= ctxt->input->end) {
+            xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
+                           "AttValue: ' expected\n");
+            goto error;
+        }
+
+        /*
+         * TODO: Check growth threshold
+         */
+        if (ctxt->input->end - CUR_PTR < 10)
+            GROW;
+
+        c = CUR;
+
+        if (c >= 0x80) {
+            l = xmlUTF8MultibyteLen(ctxt, CUR_PTR,
+                    "invalid character in attribute value\n");
+            if (l == 0) {
+                if (chunkSize > 0) {
+                    xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize);
+                    chunkSize = 0;
+                }
+                xmlSBufAddReplChar(&buf);
+                NEXTL(1);
+            } else {
+                chunkSize += l;
+                NEXTL(l);
+            }
+
+            inSpace = 0;
+        } else if (c != '&') {
+            if (c > 0x20) {
+                if (c == quote)
+                    break;
+
+                if (c == '<')
+                    xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL);
+
+                chunkSize += 1;
+                inSpace = 0;
+            } else if (!IS_BYTE_CHAR(c)) {
+                xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR,
+                        "invalid character in attribute value\n");
+                if (chunkSize > 0) {
+                    xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize);
+                    chunkSize = 0;
+                }
+                xmlSBufAddReplChar(&buf);
+                inSpace = 0;
+            } else {
+                /* Whitespace */
+                if ((normalize) && (inSpace)) {
+                    /* Skip char */
+                    if (chunkSize > 0) {
+                        xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize);
+                        chunkSize = 0;
+                    }
+                } else if (c < 0x20) {
+                    /* Convert to space */
+                    if (chunkSize > 0) {
+                        xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize);
+                        chunkSize = 0;
+                    }
+
+                    xmlSBufAddCString(&buf, " ", 1);
+                } else {
+                    chunkSize += 1;
+                }
+
+                inSpace = 1;
+
+                if ((c == 0xD) && (NXT(1) == 0xA))
+                    CUR_PTR++;
+            }
+
+            NEXTL(1);
+        } else if (NXT(1) == '#') {
+            int val;
+
+            if (chunkSize > 0) {
+                xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize);
+                chunkSize = 0;
+            }
+
+            val = xmlParseCharRef(ctxt);
+            if (val == 0)
+                goto error;
+
+            if ((val == '&') && (!ctxt->replaceEntities)) {
+                /*
+                 * The reparsing will be done in xmlStringGetNodeList()
+                 * called by the attribute() function in SAX.c
+                 */
+                xmlSBufAddCString(&buf, "&#38;", 5);
+                inSpace = 0;
+            } else if (val == ' ') {
+                if ((!normalize) || (!inSpace))
+                    xmlSBufAddCString(&buf, " ", 1);
+                inSpace = 1;
+            } else {
+                xmlSBufAddChar(&buf, val);
+                inSpace = 0;
+            }
+        } else {
+            const xmlChar *name;
+            xmlEntityPtr ent;
+
+            if (chunkSize > 0) {
+                xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize);
+                chunkSize = 0;
+            }
+
+            name = xmlParseEntityRefInternal(ctxt);
+            if (name == NULL) {
+                /*
+                 * Probably a literal '&' which wasn't escaped.
+                 * TODO: Handle gracefully in recovery mode.
+                 */
+                continue;
+            }
+
+            ent = xmlLookupGeneralEntity(ctxt, name, /* isAttr */ 1);
+            if (ent == NULL)
+                continue;
+
+            if (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY) {
+                if ((ent->content[0] == '&') && (!ctxt->replaceEntities))
+                    xmlSBufAddCString(&buf, "&#38;", 5);
+                else
+                    xmlSBufAddString(&buf, ent->content, ent->length);
+                inSpace = 0;
+            } else if (ctxt->replaceEntities) {
+                xmlExpandEntityInAttValue(ctxt, &buf, ent->content, ent,
+                                          normalize, &inSpace, ctxt->inputNr,
+                                          /* check */ 1);
+            } else {
+                if ((ent->flags & flags) != flags)
+                    xmlCheckEntityInAttValue(ctxt, ent, ctxt->inputNr);
+
+                if (xmlParserEntityCheck(ctxt, ent->expandedSize)) {
+                    ent->content[0] = 0;
+                    goto error;
+                }
+
+                /*
+                 * Just output the reference
+                 */
+                xmlSBufAddCString(&buf, "&", 1);
+                xmlSBufAddString(&buf, ent->name, xmlStrlen(ent->name));
+                xmlSBufAddCString(&buf, ";", 1);
+
+                inSpace = 0;
+            }
+	}
+    }
+
+    if ((buf.mem == NULL) && (alloc != NULL)) {
+        ret = (xmlChar *) CUR_PTR - chunkSize;
+
+        if (attlen != NULL)
+            *attlen = chunkSize;
+        if ((normalize) && (inSpace) && (chunkSize > 0))
+            *attlen -= 1;
+        *alloc = 0;
+
+        /* Report potential error */
+        xmlSBufCleanup(&buf, ctxt, "AttValue length too long");
+    } else {
+        if (chunkSize > 0)
+            xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize);
+
+        if ((normalize) && (inSpace) && (buf.size > 0))
+            buf.size--;
+
+        ret = xmlSBufFinish(&buf, attlen, ctxt, "AttValue length too long");
+
+        if (ret != NULL) {
+            if (attlen != NULL)
+                *attlen = buf.size;
+            if (alloc != NULL)
+                *alloc = 1;
+        }
+    }
+
+    NEXTL(1);
+
+    return(ret);
+
+error:
+    xmlSBufCleanup(&buf, ctxt, "AttValue length too long");
     return(NULL);
 }
 
@@ -4262,7 +4577,6 @@
                     XML_MAX_TEXT_LENGTH :
                     XML_MAX_NAME_LENGTH;
     xmlChar stop;
-    int state = ctxt->instate;
 
     if (RAW == '"') {
         NEXT;
@@ -4277,10 +4591,9 @@
 
     buf = (xmlChar *) xmlMallocAtomic(size);
     if (buf == NULL) {
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
 	return(NULL);
     }
-    ctxt->instate = XML_PARSER_SYSTEM_LITERAL;
     cur = CUR_CHAR(l);
     while ((IS_CHAR(cur)) && (cur != stop)) { /* checked */
 	if (len + 5 >= size) {
@@ -4290,7 +4603,7 @@
 	    tmp = (xmlChar *) xmlRealloc(buf, size);
 	    if (tmp == NULL) {
 	        xmlFree(buf);
-		xmlErrMemory(ctxt, NULL);
+		xmlErrMemory(ctxt);
 		return(NULL);
 	    }
 	    buf = tmp;
@@ -4299,14 +4612,12 @@
         if (len > maxLength) {
             xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral");
             xmlFree(buf);
-            ctxt->instate = (xmlParserInputState) state;
             return(NULL);
         }
 	NEXTL(l);
 	cur = CUR_CHAR(l);
     }
     buf[len] = 0;
-    ctxt->instate = (xmlParserInputState) state;
     if (!IS_CHAR(cur)) {
 	xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL);
     } else {
@@ -4338,7 +4649,6 @@
                     XML_MAX_NAME_LENGTH;
     xmlChar cur;
     xmlChar stop;
-    xmlParserInputState oldstate = ctxt->instate;
 
     if (RAW == '"') {
         NEXT;
@@ -4352,10 +4662,9 @@
     }
     buf = (xmlChar *) xmlMallocAtomic(size);
     if (buf == NULL) {
-	xmlErrMemory(ctxt, NULL);
+	xmlErrMemory(ctxt);
 	return(NULL);
     }
-    ctxt->instate = XML_PARSER_PUBLIC_LITERAL;
     cur = CUR;
     while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop) &&
            (PARSER_STOPPED(ctxt) == 0)) { /* checked */
@@ -4365,7 +4674,7 @@
 	    size *= 2;
 	    tmp = (xmlChar *) xmlRealloc(buf, size);
 	    if (tmp == NULL) {
-		xmlErrMemory(ctxt, NULL);
+		xmlErrMemory(ctxt);
 		xmlFree(buf);
 		return(NULL);
 	    }
@@ -4386,7 +4695,6 @@
     } else {
 	NEXTL(1);
     }
-    ctxt->instate = oldstate;
     return(buf);
 }
 
@@ -4631,9 +4939,6 @@
 		}
 	    }
 	    nbchar = 0;
-            /* something really bad happened in the SAX callback */
-            if (ctxt->instate != XML_PARSER_CONTENT)
-                return;
             SHRINK;
 	}
 	cur = CUR_CHAR(l);
@@ -4789,16 +5094,13 @@
     size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
                        XML_MAX_HUGE_LENGTH :
                        XML_MAX_TEXT_LENGTH;
-    int inputid;
-
-    inputid = ctxt->input->id;
 
     if (buf == NULL) {
         len = 0;
 	size = XML_PARSER_BUFFER_SIZE;
 	buf = (xmlChar *) xmlMallocAtomic(size);
 	if (buf == NULL) {
-	    xmlErrMemory(ctxt, NULL);
+	    xmlErrMemory(ctxt);
 	    return;
 	}
     }
@@ -4841,7 +5143,7 @@
 	    new_buf = (xmlChar *) xmlRealloc(buf, new_size);
 	    if (new_buf == NULL) {
 		xmlFree (buf);
-		xmlErrMemory(ctxt, NULL);
+		xmlErrMemory(ctxt);
 		return;
 	    }
 	    buf = new_buf;
@@ -4873,11 +5175,6 @@
                           "xmlParseComment: invalid xmlChar value %d\n",
 	                  cur);
     } else {
-	if (inputid != ctxt->input->id) {
-	    xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-		           "Comment doesn't start and stop in the same"
-                           " entity\n");
-	}
         NEXT;
 	if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
 	    (!ctxt->disableSAX))
@@ -4913,11 +5210,9 @@
     size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
                        XML_MAX_HUGE_LENGTH :
                        XML_MAX_TEXT_LENGTH;
-    xmlParserInputState state;
     const xmlChar *in;
     size_t nbchar = 0;
     int ccol;
-    int inputid;
 
     /*
      * Check that there is a comment right here.
@@ -4927,9 +5222,6 @@
     SKIP(2);
     if ((RAW != '-') || (NXT(1) != '-'))
         return;
-    state = ctxt->instate;
-    ctxt->instate = XML_PARSER_COMMENT;
-    inputid = ctxt->input->id;
     SKIP(2);
     GROW;
 
@@ -4973,7 +5265,7 @@
                     size = XML_PARSER_BUFFER_SIZE + nbchar;
                 buf = (xmlChar *) xmlMallocAtomic(size);
                 if (buf == NULL) {
-                    xmlErrMemory(ctxt, NULL);
+                    xmlErrMemory(ctxt);
                     return;
                 }
                 len = 0;
@@ -4983,7 +5275,7 @@
                 new_buf = (xmlChar *) xmlRealloc(buf, size);
                 if (new_buf == NULL) {
                     xmlFree (buf);
-                    xmlErrMemory(ctxt, NULL);
+                    xmlErrMemory(ctxt);
                     return;
                 }
                 buf = new_buf;
@@ -5019,11 +5311,6 @@
 	if (*in == '-') {
 	    if (in[1] == '-') {
 	        if (in[2] == '>') {
-		    if (ctxt->input->id != inputid) {
-			xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-			               "comment doesn't start and stop in the"
-                                       " same entity\n");
-		    }
 		    SKIP(3);
 		    if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
 		        (!ctxt->disableSAX)) {
@@ -5034,7 +5321,6 @@
 		    }
 		    if (buf != NULL)
 		        xmlFree(buf);
-		    ctxt->instate = state;
 		    return;
 		}
 		if (buf != NULL) {
@@ -5054,7 +5340,6 @@
 	}
     } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a));
     xmlParseCommentComplex(ctxt, buf, len, size);
-    ctxt->instate = state;
     return;
 }
 
@@ -5155,6 +5440,12 @@
 	goto error;
 
     if (URL != NULL) {
+        /*
+         * Unfortunately, the catalog API doesn't report OOM errors.
+         * xmlGetLastError isn't very helpful since we don't know
+         * where the last error came from. We'd have to reset it
+         * before this call and restore it afterwards.
+         */
 	ctxt->catalogs = xmlCatalogAddLocal(ctxt->catalogs, URL);
 	xmlFree(URL);
     }
@@ -5192,12 +5483,8 @@
                        XML_MAX_TEXT_LENGTH;
     int cur, l;
     const xmlChar *target;
-    xmlParserInputState state;
 
     if ((RAW == '<') && (NXT(1) == '?')) {
-	int inputid = ctxt->input->id;
-	state = ctxt->instate;
-        ctxt->instate = XML_PARSER_PI;
 	/*
 	 * this is a Processing Instruction.
 	 */
@@ -5210,11 +5497,6 @@
         target = xmlParsePITarget(ctxt);
 	if (target != NULL) {
 	    if ((RAW == '?') && (NXT(1) == '>')) {
-		if (inputid != ctxt->input->id) {
-		    xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-	                           "PI declaration doesn't start and stop in"
-                                   " the same entity\n");
-		}
 		SKIP(2);
 
 		/*
@@ -5224,12 +5506,11 @@
 		    (ctxt->sax->processingInstruction != NULL))
 		    ctxt->sax->processingInstruction(ctxt->userData,
 		                                     target, NULL);
-		ctxt->instate = state;
 		return;
 	    }
 	    buf = (xmlChar *) xmlMallocAtomic(size);
 	    if (buf == NULL) {
-		xmlErrMemory(ctxt, NULL);
+		xmlErrMemory(ctxt);
 		return;
 	    }
 	    if (SKIP_BLANKS == 0) {
@@ -5244,7 +5525,7 @@
                     size_t new_size = size * 2;
 		    tmp = (xmlChar *) xmlRealloc(buf, new_size);
 		    if (tmp == NULL) {
-			xmlErrMemory(ctxt, NULL);
+			xmlErrMemory(ctxt);
 			xmlFree(buf);
 			return;
 		    }
@@ -5256,7 +5537,6 @@
                     xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
                                       "PI %s too big found", target);
                     xmlFree(buf);
-                    ctxt->instate = state;
                     return;
                 }
 		NEXTL(l);
@@ -5267,16 +5547,10 @@
 		xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED,
 		      "ParsePI: PI %s never end ...\n", target);
 	    } else {
-		if (inputid != ctxt->input->id) {
-		    xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
-	                           "PI declaration doesn't start and stop in"
-                                   " the same entity\n");
-		}
 		SKIP(2);
 
 #ifdef LIBXML_CATALOG_ENABLED
-		if (((state == XML_PARSER_MISC) ||
-	             (state == XML_PARSER_START)) &&
+		if ((ctxt->inSubset == 0) &&
 		    (xmlStrEqual(target, XML_CATALOG_PI))) {
 		    xmlCatalogAllow allow = xmlCatalogGetDefaults();
 		    if ((allow == XML_CATA_ALLOW_DOCUMENT) ||
@@ -5298,7 +5572,6 @@
 	} else {
 	    xmlFatalErr(ctxt, XML_ERR_PI_NOT_STARTED, NULL);
 	}
-	ctxt->instate = state;
     }
 }
 
@@ -5333,7 +5606,7 @@
     if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) {
 	int inputid = ctxt->input->id;
 	SKIP(8);
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			   "Space required after '<!NOTATION'\n");
 	    return;
@@ -5349,7 +5622,7 @@
 		     "colons are forbidden from notation names '%s'\n",
 		     name, NULL, NULL);
 	}
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 		     "Space required after the NOTATION name'\n");
 	    return;
@@ -5359,7 +5632,7 @@
 	 * Parse the IDs.
 	 */
 	Systemid = xmlParseExternalID(ctxt, &Pubid, 0);
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
 
 	if (RAW == '>') {
 	    if (inputid != ctxt->input->id) {
@@ -5420,14 +5693,14 @@
     if (CMP6(CUR_PTR, 'E', 'N', 'T', 'I', 'T', 'Y')) {
 	int inputid = ctxt->input->id;
 	SKIP(6);
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			   "Space required after '<!ENTITY'\n");
 	}
 
 	if (RAW == '%') {
 	    NEXT;
-	    if (SKIP_BLANKS == 0) {
+	    if (SKIP_BLANKS_PE == 0) {
 		xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			       "Space required after '%%'\n");
 	    }
@@ -5445,12 +5718,11 @@
 		     "colons are forbidden from entities names '%s'\n",
 		     name, NULL, NULL);
 	}
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			   "Space required after the entity name\n");
 	}
 
-	ctxt->instate = XML_PARSER_ENTITY_DECL;
 	/*
 	 * handle the various case of definitions...
 	 */
@@ -5473,7 +5745,7 @@
 		    xmlURIPtr uri;
 
                     if (xmlParseURISafe((const char *) URI, &uri) < 0) {
-                        xmlErrMemory(ctxt, NULL);
+                        xmlErrMemory(ctxt);
                     } else if (uri == NULL) {
                         /*
                          * This really ought to be a well formedness error
@@ -5515,7 +5787,7 @@
 		    if (ctxt->myDoc == NULL) {
 			ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE);
 			if (ctxt->myDoc == NULL) {
-			    xmlErrMemory(ctxt, "New Doc failed");
+			    xmlErrMemory(ctxt);
 			    goto done;
 			}
 			ctxt->myDoc->properties = XML_DOC_INTERNAL;
@@ -5524,7 +5796,7 @@
 			ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc,
 					    BAD_CAST "fake", NULL, NULL);
                         if (ctxt->myDoc->intSubset == NULL) {
-                            xmlErrMemory(ctxt, NULL);
+                            xmlErrMemory(ctxt);
                             goto done;
                         }
                     }
@@ -5541,7 +5813,7 @@
 		    xmlURIPtr uri;
 
                     if (xmlParseURISafe((const char *) URI, &uri) < 0) {
-                        xmlErrMemory(ctxt, NULL);
+                        xmlErrMemory(ctxt);
                     } else if (uri == NULL) {
                         /*
                          * This really ought to be a well formedness error
@@ -5559,13 +5831,13 @@
                     }
                     xmlFreeURI(uri);
 		}
-		if ((RAW != '>') && (SKIP_BLANKS == 0)) {
+		if ((RAW != '>') && (SKIP_BLANKS_PE == 0)) {
 		    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 				   "Space required before 'NDATA'\n");
 		}
 		if (CMP5(CUR_PTR, 'N', 'D', 'A', 'T', 'A')) {
 		    SKIP(5);
-		    if (SKIP_BLANKS == 0) {
+		    if (SKIP_BLANKS_PE == 0) {
 			xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 				       "Space required after 'NDATA'\n");
 		    }
@@ -5590,7 +5862,7 @@
 			if (ctxt->myDoc == NULL) {
 			    ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE);
 			    if (ctxt->myDoc == NULL) {
-			        xmlErrMemory(ctxt, "New Doc failed");
+			        xmlErrMemory(ctxt);
 				goto done;
 			    }
 			    ctxt->myDoc->properties = XML_DOC_INTERNAL;
@@ -5600,7 +5872,7 @@
 			    ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc,
 						BAD_CAST "fake", NULL, NULL);
                             if (ctxt->myDoc->intSubset == NULL) {
-                                xmlErrMemory(ctxt, NULL);
+                                xmlErrMemory(ctxt);
                                 goto done;
                             }
                         }
@@ -5611,7 +5883,7 @@
 		}
 	    }
 	}
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
 	if (RAW != '>') {
 	    xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_NOT_FINISHED,
 	            "xmlParseEntityDecl: entity %s not terminated\n", name);
@@ -5705,13 +5977,12 @@
     if (CMP6(CUR_PTR, '#', 'F', 'I', 'X', 'E', 'D')) {
 	SKIP(6);
 	val = XML_ATTRIBUTE_FIXED;
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			   "Space required after '#FIXED'\n");
 	}
     }
     ret = xmlParseAttValue(ctxt);
-    ctxt->instate = XML_PARSER_DTD;
     if (ret == NULL) {
 	xmlFatalErrMsg(ctxt, (xmlParserErrors)ctxt->errNo,
 		       "Attribute default value declaration error\n");
@@ -5750,7 +6021,7 @@
     }
     do {
         NEXT;
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
         name = xmlParseName(ctxt);
 	if (name == NULL) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
@@ -5773,7 +6044,7 @@
 	if (tmp == NULL) {
 	    cur = xmlCreateEnumeration(name);
 	    if (cur == NULL) {
-                xmlErrMemory(ctxt, NULL);
+                xmlErrMemory(ctxt);
                 xmlFreeEnumeration(ret);
                 return(NULL);
             }
@@ -5783,7 +6054,7 @@
 		last = cur;
 	    }
 	}
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
     } while (RAW == '|');
     if (RAW != ')') {
 	xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_FINISHED, NULL);
@@ -5822,7 +6093,7 @@
     }
     do {
         NEXT;
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
         name = xmlParseNmtoken(ctxt);
 	if (name == NULL) {
 	    xmlFatalErr(ctxt, XML_ERR_NMTOKEN_REQUIRED, NULL);
@@ -5845,7 +6116,7 @@
 	    if (!xmlDictOwns(ctxt->dict, name))
 		xmlFree(name);
 	    if (cur == NULL) {
-                xmlErrMemory(ctxt, NULL);
+                xmlErrMemory(ctxt);
                 xmlFreeEnumeration(ret);
                 return(NULL);
             }
@@ -5855,7 +6126,7 @@
 		last = cur;
 	    }
 	}
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
     } while (RAW == '|');
     if (RAW != ')') {
 	xmlFatalErr(ctxt, XML_ERR_ATTLIST_NOT_FINISHED, NULL);
@@ -5886,7 +6157,7 @@
 xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
     if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) {
 	SKIP(8);
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			   "Space required after 'NOTATION'\n");
 	    return(0);
@@ -6004,7 +6275,7 @@
 	int inputid = ctxt->input->id;
 
 	SKIP(7);
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 		                 "Space required after '<!ATTLIST'\n");
 	}
@@ -6014,7 +6285,7 @@
 			   "ATTLIST: no name for Element\n");
 	    return;
 	}
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
 	GROW;
 	while ((RAW != '>') && (PARSER_STOPPED(ctxt) == 0)) {
 	    int type;
@@ -6030,7 +6301,7 @@
 		break;
 	    }
 	    GROW;
-	    if (SKIP_BLANKS == 0) {
+	    if (SKIP_BLANKS_PE == 0) {
 		xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 		        "Space required after the attribute name\n");
 		break;
@@ -6042,7 +6313,7 @@
 	    }
 
 	    GROW;
-	    if (SKIP_BLANKS == 0) {
+	    if (SKIP_BLANKS_PE == 0) {
 		xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			       "Space required after the attribute type\n");
 	        if (tree != NULL)
@@ -6063,7 +6334,7 @@
 
 	    GROW;
             if (RAW != '>') {
-		if (SKIP_BLANKS == 0) {
+		if (SKIP_BLANKS_PE == 0) {
 		    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			"Space required after the attribute default value\n");
 		    if (defaultValue != NULL)
@@ -6132,7 +6403,7 @@
     GROW;
     if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) {
 	SKIP(7);
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
 	if (RAW == ')') {
 	    if (ctxt->input->id != inputchk) {
 		xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
@@ -6173,7 +6444,7 @@
 		n->c1->parent = n;
 		cur = n;
 	    }
-	    SKIP_BLANKS;
+	    SKIP_BLANKS_PE;
 	    elem = xmlParseName(ctxt);
 	    if (elem == NULL) {
 		xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
@@ -6181,7 +6452,7 @@
 		xmlFreeDocElementContent(ctxt->myDoc, ret);
 		return(NULL);
 	    }
-	    SKIP_BLANKS;
+	    SKIP_BLANKS_PE;
 	    GROW;
 	}
 	if ((RAW == ')') && (NXT(1) == '*')) {
@@ -6212,7 +6483,7 @@
     return(ret);
 
 mem_error:
-    xmlErrMemory(ctxt, NULL);
+    xmlErrMemory(ctxt);
     xmlFreeDocElementContent(ctxt->myDoc, ret);
     return(NULL);
 }
@@ -6252,30 +6523,30 @@
 static xmlElementContentPtr
 xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk,
                                        int depth) {
+    int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256;
     xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
     const xmlChar *elem;
     xmlChar type = 0;
 
-    if (((depth > 128) && ((ctxt->options & XML_PARSE_HUGE) == 0)) ||
-        (depth >  2048)) {
-        xmlFatalErrMsgInt(ctxt, XML_ERR_ELEMCONTENT_NOT_FINISHED,
-"xmlParseElementChildrenContentDecl : depth %d too deep, use XML_PARSE_HUGE\n",
-                          depth);
+    if (depth > maxDepth) {
+        xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT,
+                "xmlParseElementChildrenContentDecl : depth %d too deep, "
+                "use XML_PARSE_HUGE\n", depth);
 	return(NULL);
     }
-    SKIP_BLANKS;
+    SKIP_BLANKS_PE;
     GROW;
     if (RAW == '(') {
 	int inputid = ctxt->input->id;
 
         /* Recurse on first child */
 	NEXT;
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
         cur = ret = xmlParseElementChildrenContentDeclPriv(ctxt, inputid,
                                                            depth + 1);
         if (cur == NULL)
             return(NULL);
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
 	GROW;
     } else {
 	elem = xmlParseName(ctxt);
@@ -6285,7 +6556,7 @@
 	}
         cur = ret = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT);
 	if (cur == NULL) {
-	    xmlErrMemory(ctxt, NULL);
+	    xmlErrMemory(ctxt);
 	    return(NULL);
 	}
 	GROW;
@@ -6303,7 +6574,7 @@
 	}
 	GROW;
     }
-    SKIP_BLANKS;
+    SKIP_BLANKS_PE;
     while ((RAW != ')') && (PARSER_STOPPED(ctxt) == 0)) {
         /*
 	 * Each loop we parse one separator and one element.
@@ -6328,7 +6599,7 @@
 
 	    op = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_SEQ);
 	    if (op == NULL) {
-                xmlErrMemory(ctxt, NULL);
+                xmlErrMemory(ctxt);
 		if ((last != NULL) && (last != ret))
 		    xmlFreeDocElementContent(ctxt->myDoc, last);
 	        xmlFreeDocElementContent(ctxt->myDoc, ret);
@@ -6369,7 +6640,7 @@
 
 	    op = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR);
 	    if (op == NULL) {
-                xmlErrMemory(ctxt, NULL);
+                xmlErrMemory(ctxt);
 		if ((last != NULL) && (last != ret))
 		    xmlFreeDocElementContent(ctxt->myDoc, last);
 		if (ret != NULL)
@@ -6400,13 +6671,13 @@
 	    return(NULL);
 	}
 	GROW;
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
 	GROW;
 	if (RAW == '(') {
 	    int inputid = ctxt->input->id;
 	    /* Recurse on second child */
 	    NEXT;
-	    SKIP_BLANKS;
+	    SKIP_BLANKS_PE;
 	    last = xmlParseElementChildrenContentDeclPriv(ctxt, inputid,
                                                           depth + 1);
             if (last == NULL) {
@@ -6414,7 +6685,7 @@
 		    xmlFreeDocElementContent(ctxt->myDoc, ret);
 		return(NULL);
             }
-	    SKIP_BLANKS;
+	    SKIP_BLANKS_PE;
 	} else {
 	    elem = xmlParseName(ctxt);
 	    if (elem == NULL) {
@@ -6425,7 +6696,7 @@
 	    }
 	    last = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT);
 	    if (last == NULL) {
-                xmlErrMemory(ctxt, NULL);
+                xmlErrMemory(ctxt);
 		if (ret != NULL)
 		    xmlFreeDocElementContent(ctxt->myDoc, ret);
 		return(NULL);
@@ -6443,7 +6714,7 @@
 		last->ocur = XML_ELEMENT_CONTENT_ONCE;
 	    }
 	}
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
 	GROW;
     }
     if ((cur != NULL) && (last != NULL)) {
@@ -6595,7 +6866,7 @@
     }
     NEXT;
     GROW;
-    SKIP_BLANKS;
+    SKIP_BLANKS_PE;
     if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) {
         tree = xmlParseElementMixedContentDecl(ctxt, inputid);
 	res = XML_ELEMENT_TYPE_MIXED;
@@ -6603,7 +6874,7 @@
         tree = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, 1);
 	res = XML_ELEMENT_TYPE_ELEMENT;
     }
-    SKIP_BLANKS;
+    SKIP_BLANKS_PE;
     *result = tree;
     return(res);
 }
@@ -6638,7 +6909,7 @@
 	int inputid = ctxt->input->id;
 
 	SKIP(7);
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 		           "Space required after 'ELEMENT'\n");
 	    return(-1);
@@ -6649,7 +6920,7 @@
 			   "xmlParseElementDecl: no name for Element\n");
 	    return(-1);
 	}
-	if (SKIP_BLANKS == 0) {
+	if (SKIP_BLANKS_PE == 0) {
 	    xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED,
 			   "Space required after the element name\n");
 	}
@@ -6672,18 +6943,12 @@
 	    /*
 	     * [ WFC: PEs in Internal Subset ] error handling.
 	     */
-	    if ((RAW == '%') && (ctxt->external == 0) &&
-	        (ctxt->inputNr == 1)) {
-		xmlFatalErrMsg(ctxt, XML_ERR_PEREF_IN_INT_SUBSET,
-	  "PEReference: forbidden within markup decl in internal subset\n");
-	    } else {
-		xmlFatalErrMsg(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED,
-		      "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
-            }
+            xmlFatalErrMsg(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED,
+                  "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
 	    return(-1);
 	}
 
-	SKIP_BLANKS;
+	SKIP_BLANKS_PE;
 
 	if (RAW != '>') {
 	    xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL);
@@ -6745,11 +7010,11 @@
             int id = ctxt->input->id;
 
             SKIP(3);
-            SKIP_BLANKS;
+            SKIP_BLANKS_PE;
 
             if (CMP7(CUR_PTR, 'I', 'N', 'C', 'L', 'U', 'D', 'E')) {
                 SKIP(7);
-                SKIP_BLANKS;
+                SKIP_BLANKS_PE;
                 if (RAW != '[') {
                     xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL);
                     xmlHaltParser(ctxt);
@@ -6769,7 +7034,7 @@
                     tmp = (int *) xmlRealloc(inputIds,
                             inputIdsSize * sizeof(int));
                     if (tmp == NULL) {
-                        xmlErrMemory(ctxt, NULL);
+                        xmlErrMemory(ctxt);
                         goto error;
                     }
                     inputIds = tmp;
@@ -6780,7 +7045,7 @@
                 size_t ignoreDepth = 0;
 
                 SKIP(6);
-                SKIP_BLANKS;
+                SKIP_BLANKS_PE;
                 if (RAW != '[') {
                     xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL);
                     xmlHaltParser(ctxt);
@@ -6793,36 +7058,35 @@
                 }
                 NEXT;
 
-                while ((PARSER_STOPPED(ctxt) == 0) && (RAW != 0)) {
+                while (PARSER_STOPPED(ctxt) == 0) {
+                    if (RAW == 0) {
+                        xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL);
+                        goto error;
+                    }
                     if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
                         SKIP(3);
                         ignoreDepth++;
                         /* Check for integer overflow */
                         if (ignoreDepth == 0) {
-                            xmlErrMemory(ctxt, NULL);
+                            xmlErrMemory(ctxt);
                             goto error;
                         }
                     } else if ((RAW == ']') && (NXT(1) == ']') &&
                                (NXT(2) == '>')) {
+                        SKIP(3);
                         if (ignoreDepth == 0)
                             break;
-                        SKIP(3);
                         ignoreDepth--;
                     } else {
                         NEXT;
                     }
                 }
 
-		if (RAW == 0) {
-		    xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL);
-                    goto error;
-		}
                 if (ctxt->input->id != id) {
                     xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY,
                                    "All markup of the conditional section is"
                                    " not in the same entity\n");
                 }
-                SKIP(3);
             } else {
                 xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID_KEYWORD, NULL);
                 xmlHaltParser(ctxt);
@@ -6848,7 +7112,7 @@
         if (depth == 0)
             break;
 
-        SKIP_BLANKS;
+        SKIP_BLANKS_PE;
         SHRINK;
         GROW;
     }
@@ -6913,8 +7177,6 @@
 	    xmlParsePI(ctxt);
 	}
     }
-
-    ctxt->instate = XML_PARSER_DTD;
 }
 
 /**
@@ -6931,7 +7193,6 @@
 void
 xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
     xmlChar *version;
-    int oldstate;
 
     /*
      * We know that '<?xml' is here.
@@ -6943,10 +7204,6 @@
 	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");
@@ -6959,7 +7216,7 @@
     if (version == NULL) {
 	version = xmlCharStrdup(XML_DEFAULT_VERSION);
         if (version == NULL) {
-            xmlErrMemory(ctxt, NULL);
+            xmlErrMemory(ctxt);
             return;
         }
     } else {
@@ -6974,13 +7231,6 @@
      * We must have the encoding declaration
      */
     xmlParseEncodingDecl(ctxt);
-    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
-	/*
-	 * The XML REC instructs us to stop parsing right here
-	 */
-        ctxt->instate = oldstate;
-        return;
-    }
 
     SKIP_BLANKS;
     if ((RAW == '?') && (NXT(1) == '>')) {
@@ -6999,8 +7249,6 @@
                 break;
         }
     }
-
-    ctxt->instate = oldstate;
 }
 
 /**
@@ -7018,37 +7266,34 @@
 void
 xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID,
                        const xmlChar *SystemID) {
-    xmlDetectSAX2(ctxt);
+    int oldInputNr;
+
+    xmlCtxtInitializeLate(ctxt);
 
     xmlDetectEncoding(ctxt);
 
     if (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) {
 	xmlParseTextDecl(ctxt);
-	if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
-	    /*
-	     * The XML REC instructs us to stop parsing right here
-	     */
-	    xmlHaltParser(ctxt);
-	    return;
-	}
     }
     if (ctxt->myDoc == NULL) {
         ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
 	if (ctxt->myDoc == NULL) {
-	    xmlErrMemory(ctxt, "New Doc failed");
+	    xmlErrMemory(ctxt);
 	    return;
 	}
 	ctxt->myDoc->properties = XML_DOC_INTERNAL;
     }
     if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL) &&
         (xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID) == NULL)) {
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
     }
 
-    ctxt->instate = XML_PARSER_DTD;
-    ctxt->external = 1;
-    SKIP_BLANKS;
-    while ((PARSER_STOPPED(ctxt) == 0) && (RAW != 0)) {
+    ctxt->inSubset = 2;
+    oldInputNr = ctxt->inputNr;
+
+    SKIP_BLANKS_PE;
+    while (((RAW != 0) || (ctxt->inputNr > oldInputNr)) &&
+           (!PARSER_STOPPED(ctxt))) {
 	GROW;
         if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
             xmlParseConditionalSections(ctxt);
@@ -7059,14 +7304,16 @@
             xmlHaltParser(ctxt);
             return;
         }
-        SKIP_BLANKS;
+        SKIP_BLANKS_PE;
         SHRINK;
     }
 
+    while (ctxt->inputNr > oldInputNr)
+        xmlPopPE(ctxt);
+
     if (RAW != 0) {
 	xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL);
     }
-
 }
 
 /**
@@ -7086,12 +7333,9 @@
  */
 void
 xmlParseReference(xmlParserCtxtPtr ctxt) {
-    xmlEntityPtr ent;
+    xmlEntityPtr ent = NULL;
+    const xmlChar *name;
     xmlChar *val;
-    int was_checked;
-    xmlNodePtr list = NULL;
-    xmlParserErrors ret = XML_ERR_OK;
-
 
     if (RAW != '&')
         return;
@@ -7121,11 +7365,12 @@
     /*
      * We are seeing an entity reference
      */
-    ent = xmlParseEntityRef(ctxt);
+    name = xmlParseEntityRefInternal(ctxt);
+    if (name != NULL)
+        ent = xmlLookupGeneralEntity(ctxt, name, /* isAttr */ 0);
     if (ent == NULL) return;
     if (!ctxt->wellFormed)
 	return;
-    was_checked = ent->flags & XML_ENT_PARSED;
 
     /* special case of predefined entities */
     if ((ent->name == NULL) ||
@@ -7169,9 +7414,6 @@
      *
      * Proposed fix:
      *
-     * - Remove the ent->owner optimization which tries to avoid the
-     *   initial copy of the entity. Always make entities own the
-     *   subtree.
      * - Ignore current namespace declarations when parsing the
      *   entity. If a prefix can't be resolved, don't report an error
      *   but mark it as unresolved.
@@ -7184,391 +7426,130 @@
      * expansion like we already do with custom SAX callbacks.
      * External entity content should be cached in this case.
      */
-    if (((ent->flags & XML_ENT_PARSED) == 0) &&
-        ((ent->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY) ||
-         (ctxt->options & (XML_PARSE_NOENT | XML_PARSE_DTDVALID)))) {
-	unsigned long oldsizeentcopy = ctxt->sizeentcopy;
-
-	/*
-	 * This is a bit hackish but this seems the best
-	 * way to make sure both SAX and DOM entity support
-	 * behaves okay.
-	 */
-	void *user_data;
-	if (ctxt->userData == ctxt)
-	    user_data = NULL;
-	else
-	    user_data = ctxt->userData;
-
-        /* Avoid overflow as much as possible */
-        ctxt->sizeentcopy = 0;
-
-        if (ent->flags & XML_ENT_EXPANDING) {
-            xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
-            xmlHaltParser(ctxt);
-            return;
-        }
-
-        ent->flags |= XML_ENT_EXPANDING;
-
-	/*
-	 * Check that this entity is well formed
-	 * 4.3.2: An internal general parsed entity is well-formed
-	 * if its replacement text matches the production labeled
-	 * content.
-	 */
-	if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) {
-	    ctxt->depth++;
-	    ret = xmlParseBalancedChunkMemoryInternal(ctxt, ent->content,
-	                                              user_data, &list);
-	    ctxt->depth--;
-
-	} else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
-	    ctxt->depth++;
-	    ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, ctxt->sax,
-	                                   user_data, ctxt->depth, ent->URI,
-					   ent->ExternalID, &list);
-	    ctxt->depth--;
-	} else {
-	    ret = XML_ERR_ENTITY_PE_INTERNAL;
-	    xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR,
-			 "invalid entity type found\n", NULL);
-	}
-
-        ent->flags &= ~XML_ENT_EXPANDING;
-        ent->flags |= XML_ENT_PARSED | XML_ENT_CHECKED;
-        ent->expandedSize = ctxt->sizeentcopy;
-	if (ret == XML_ERR_ENTITY_LOOP) {
-            xmlHaltParser(ctxt);
-	    xmlFreeNodeList(list);
-	    return;
-	}
-	if (xmlParserEntityCheck(ctxt, oldsizeentcopy)) {
-	    xmlFreeNodeList(list);
-	    return;
-	}
-
-	if ((ret == XML_ERR_OK) && (list != NULL)) {
-            ent->children = list;
+    if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) ||
+        (((ctxt->options & XML_PARSE_NO_XXE) == 0) &&
+         ((ctxt->replaceEntities) ||
+          (ctxt->validate)))) {
+        if ((ent->flags & XML_ENT_PARSED) == 0) {
+            xmlCtxtParseEntity(ctxt, ent);
+        } else if (ent->children == NULL) {
             /*
-             * Prune it directly in the generated document
-             * except for single text nodes.
+             * Probably running in SAX mode and the callbacks don't
+             * build the entity content. Parse the entity again.
+             *
+             * This will also be triggered in normal tree builder mode
+             * if an entity happens to be empty, causing unnecessary
+             * reloads. It's hard to come up with a reliable check in
+             * which mode we're running.
              */
-            if ((ctxt->replaceEntities == 0) ||
-                (ctxt->parseMode == XML_PARSE_READER) ||
-                ((list->type == XML_TEXT_NODE) &&
-                 (list->next == NULL))) {
-                ent->owner = 1;
-                while (list != NULL) {
-                    list->parent = (xmlNodePtr) ent;
-                    if (list->doc != ent->doc)
-                        xmlSetTreeDoc(list, ent->doc);
-                    if (list->next == NULL)
-                        ent->last = list;
-                    list = list->next;
-                }
-                list = NULL;
-            } else {
-                ent->owner = 0;
-                while (list != NULL) {
-                    list->parent = (xmlNodePtr) ctxt->node;
-                    list->doc = ctxt->myDoc;
-                    if (list->next == NULL)
-                        ent->last = list;
-                    list = list->next;
-                }
-                list = ent->children;
-#ifdef LIBXML_LEGACY_ENABLED
-                if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)
-                    xmlAddEntityReference(ent, list, NULL);
-#endif /* LIBXML_LEGACY_ENABLED */
-            }
-	} else if ((ret != XML_ERR_OK) &&
-		   (ret != XML_WAR_UNDECLARED_ENTITY)) {
-	    xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY,
-		     "Entity '%s' failed to parse\n", ent->name);
-            if (ent->content != NULL)
-                ent->content[0] = 0;
-	} else if (list != NULL) {
-	    xmlFreeNodeList(list);
-	    list = NULL;
-	}
-
-        /* Prevent entity from being parsed and expanded twice (Bug 760367). */
-        was_checked = 0;
-    }
-
-    /*
-     * Now that the entity content has been gathered
-     * provide it to the application, this can take different forms based
-     * on the parsing modes.
-     */
-    if (ent->children == NULL) {
-	/*
-	 * Probably running in SAX mode and the callbacks don't
-	 * build the entity content. So unless we already went
-	 * though parsing for first checking go though the entity
-	 * content to generate callbacks associated to the entity
-	 */
-	if (was_checked != 0) {
-	    void *user_data;
-	    /*
-	     * This is a bit hackish but this seems the best
-	     * way to make sure both SAX and DOM entity support
-	     * behaves okay.
-	     */
-	    if (ctxt->userData == ctxt)
-		user_data = NULL;
-	    else
-		user_data = ctxt->userData;
-
-	    if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) {
-		ctxt->depth++;
-		ret = xmlParseBalancedChunkMemoryInternal(ctxt,
-				   ent->content, user_data, NULL);
-		ctxt->depth--;
-	    } else if (ent->etype ==
-		       XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
-	        unsigned long oldsizeentities = ctxt->sizeentities;
-
-		ctxt->depth++;
-		ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt,
-			   ctxt->sax, user_data, ctxt->depth,
-			   ent->URI, ent->ExternalID, NULL);
-		ctxt->depth--;
-
-                /* Undo the change to sizeentities */
-                ctxt->sizeentities = oldsizeentities;
-	    } else {
-		ret = XML_ERR_ENTITY_PE_INTERNAL;
-		xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR,
-			     "invalid entity type found\n", NULL);
-	    }
-	    if (ret == XML_ERR_ENTITY_LOOP) {
-		xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
-		return;
-	    }
-            if (xmlParserEntityCheck(ctxt, 0))
-                return;
-	}
-	if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
-	    (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) {
-	    /*
-	     * Entity reference callback comes second, it's somewhat
-	     * superfluous but a compatibility to historical behaviour
-	     */
-	    ctxt->sax->reference(ctxt->userData, ent->name);
-	}
-	return;
+            xmlCtxtParseEntity(ctxt, ent);
+        }
     }
 
     /*
      * We also check for amplification if entities aren't substituted.
      * They might be expanded later.
      */
-    if ((was_checked != 0) &&
-        (xmlParserEntityCheck(ctxt, ent->expandedSize)))
+    if (xmlParserEntityCheck(ctxt, ent->expandedSize))
         return;
 
-    /*
-     * If we didn't get any children for the entity being built
-     */
-    if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
-	(ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) {
+    if ((ctxt->sax == NULL) || (ctxt->disableSAX))
+        return;
+
+    if (ctxt->replaceEntities == 0) {
 	/*
-	 * Create a node.
+	 * Create a reference
 	 */
-	ctxt->sax->reference(ctxt->userData, ent->name);
-	return;
-    }
+        if (ctxt->sax->reference != NULL)
+	    ctxt->sax->reference(ctxt->userData, ent->name);
+    } else if ((ent->children != NULL) && (ctxt->node != NULL)) {
+        xmlNodePtr copy, cur;
 
-    if (ctxt->replaceEntities)  {
-	/*
-	 * There is a problem on the handling of _private for entities
-	 * (bug 155816): Should we copy the content of the field from
-	 * the entity (possibly overwriting some value set by the user
-	 * when a copy is created), should we leave it alone, or should
-	 * we try to take care of different situations?  The problem
-	 * is exacerbated by the usage of this field by the xmlReader.
-	 * To fix this bug, we look at _private on the created node
-	 * and, if it's NULL, we copy in whatever was in the entity.
-	 * If it's not NULL we leave it alone.  This is somewhat of a
-	 * hack - maybe we should have further tests to determine
-	 * what to do.
+        /*
+         * Seems we are generating the DOM content, copy the tree
 	 */
-	if (ctxt->node != NULL) {
-	    /*
-	     * Seems we are generating the DOM content, do
-	     * a simple tree copy for all references except the first
-	     * In the first occurrence list contains the replacement.
-	     */
-	    if (((list == NULL) && (ent->owner == 0)) ||
-		(ctxt->parseMode == XML_PARSE_READER)) {
-		xmlNodePtr nw = NULL, cur, firstChild = NULL;
+        cur = ent->children;
 
-		/*
-		 * when operating on a reader, the entities definitions
-		 * are always owning the entities subtree.
-		if (ctxt->parseMode == XML_PARSE_READER)
-		    ent->owner = 1;
-		 */
+        /*
+         * Handle first text node with SAX to coalesce text efficiently
+         */
+        if ((cur->type == XML_TEXT_NODE) ||
+            (cur->type == XML_CDATA_SECTION_NODE)) {
+            int len = xmlStrlen(cur->content);
 
-		cur = ent->children;
-		while (cur != NULL) {
-		    nw = xmlDocCopyNode(cur, ctxt->myDoc, 1);
-		    if (nw == NULL) {
-                        xmlErrMemory(ctxt, NULL);
-                    } else {
-			if (nw->_private == NULL)
-			    nw->_private = cur->_private;
-			if (firstChild == NULL){
-			    firstChild = nw;
-			}
-			nw = xmlAddChild(ctxt->node, nw);
-                        if (nw == NULL)
-                            xmlErrMemory(ctxt, NULL);
-		    }
-		    if (cur == ent->last) {
-			/*
-			 * needed to detect some strange empty
-			 * node cases in the reader tests
-			 */
-			if ((ctxt->parseMode == XML_PARSE_READER) &&
-			    (nw != NULL) &&
-			    (nw->type == XML_ELEMENT_NODE) &&
-			    (nw->children == NULL))
-			    nw->extra = 1;
+            if ((cur->type == XML_TEXT_NODE) ||
+                (ctxt->sax->cdataBlock == NULL)) {
+                if (ctxt->sax->characters != NULL)
+                    ctxt->sax->characters(ctxt, cur->content, len);
+            } else {
+                if (ctxt->sax->cdataBlock != NULL)
+                    ctxt->sax->cdataBlock(ctxt, cur->content, len);
+            }
 
-			break;
-		    }
-		    cur = cur->next;
-		}
-#ifdef LIBXML_LEGACY_ENABLED
-		if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)
-		  xmlAddEntityReference(ent, firstChild, nw);
-#endif /* LIBXML_LEGACY_ENABLED */
-	    } else if ((list == NULL) || (ctxt->inputNr > 0)) {
-		xmlNodePtr nw = NULL, cur, next, last,
-			   firstChild = NULL;
+            cur = cur->next;
+        }
 
-		/*
-		 * Copy the entity child list and make it the new
-		 * entity child list. The goal is to make sure any
-		 * ID or REF referenced will be the one from the
-		 * document content and not the entity copy.
-		 */
-		cur = ent->children;
-		ent->children = NULL;
-		last = ent->last;
-		ent->last = NULL;
-		while (cur != NULL) {
-		    next = cur->next;
-		    cur->next = NULL;
-		    cur->parent = NULL;
-		    nw = xmlDocCopyNode(cur, ctxt->myDoc, 1);
-		    if (nw == NULL) {
-                        xmlErrMemory(ctxt, NULL);
-                    } else {
-			if (nw->_private == NULL)
-			    nw->_private = cur->_private;
-			if (firstChild == NULL){
-			    firstChild = cur;
-			}
-			if (xmlAddChild((xmlNodePtr) ent, nw) == NULL)
-                            xmlErrMemory(ctxt, NULL);
-		    }
-		    if (xmlAddChild(ctxt->node, cur) == NULL)
-                        xmlErrMemory(ctxt, NULL);
-		    if (cur == last)
-			break;
-		    cur = next;
-		}
-		if (ent->owner == 0)
-		    ent->owner = 1;
-#ifdef LIBXML_LEGACY_ENABLED
-		if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)
-		  xmlAddEntityReference(ent, firstChild, nw);
-#endif /* LIBXML_LEGACY_ENABLED */
-	    } else {
-		const xmlChar *nbktext;
+        while (cur != NULL) {
+            xmlNodePtr last;
 
-		/*
-		 * the name change is to avoid coalescing of the
-		 * node with a possible previous text one which
-		 * would make ent->children a dangling pointer
-		 */
-		nbktext = xmlDictLookup(ctxt->dict, BAD_CAST "nbktext",
-					-1);
-		if (ent->children->type == XML_TEXT_NODE)
-		    ent->children->name = nbktext;
-		if ((ent->last != ent->children) &&
-		    (ent->last->type == XML_TEXT_NODE))
-		    ent->last->name = nbktext;
-		xmlAddChildList(ctxt->node, ent->children);
-	    }
+            /*
+             * Handle last text node with SAX to coalesce text efficiently
+             */
+            if ((cur->next == NULL) &&
+                ((cur->type == XML_TEXT_NODE) ||
+                 (cur->type == XML_CDATA_SECTION_NODE))) {
+                int len = xmlStrlen(cur->content);
 
-	    /*
-	     * This is to avoid a nasty side effect, see
-	     * characters() in SAX.c
-	     */
-	    ctxt->nodemem = 0;
-	    ctxt->nodelen = 0;
-	    return;
-	}
+                if ((cur->type == XML_TEXT_NODE) ||
+                    (ctxt->sax->cdataBlock == NULL)) {
+                    if (ctxt->sax->characters != NULL)
+                        ctxt->sax->characters(ctxt, cur->content, len);
+                } else {
+                    if (ctxt->sax->cdataBlock != NULL)
+                        ctxt->sax->cdataBlock(ctxt, cur->content, len);
+                }
+
+                break;
+            }
+
+            /*
+             * Reset coalesce buffer stats only for non-text nodes.
+             */
+            ctxt->nodemem = 0;
+            ctxt->nodelen = 0;
+
+            copy = xmlDocCopyNode(cur, ctxt->myDoc, 1);
+
+            if (copy == NULL) {
+                xmlErrMemory(ctxt);
+                break;
+            }
+
+            if (ctxt->parseMode == XML_PARSE_READER) {
+                /* Needed for reader */
+                copy->extra = cur->extra;
+                /* Maybe needed for reader */
+                copy->_private = cur->_private;
+            }
+
+            copy->parent = ctxt->node;
+            last = ctxt->node->last;
+            if (last == NULL) {
+                ctxt->node->children = copy;
+            } else {
+                last->next = copy;
+                copy->prev = last;
+            }
+            ctxt->node->last = copy;
+
+            cur = cur->next;
+        }
     }
 }
 
-/**
- * xmlParseEntityRef:
- * @ctxt:  an XML parser context
- *
- * DEPRECATED: Internal function, don't use.
- *
- * Parse an entitiy reference. Always consumes '&'.
- *
- * [68] EntityRef ::= '&' Name ';'
- *
- * [ WFC: Entity Declared ]
- * In a document without any DTD, a document with only an internal DTD
- * subset which contains no parameter entity references, or a document
- * with "standalone='yes'", the Name given in the entity reference
- * must match that in an entity declaration, except that well-formed
- * documents need not declare any of the following entities: amp, lt,
- * gt, apos, quot.  The declaration of a parameter entity must precede
- * any reference to it.  Similarly, the declaration of a general entity
- * must precede any reference to it which appears in a default value in an
- * attribute-list declaration. Note that if entities are declared in the
- * external subset or in external parameter entities, a non-validating
- * processor is not obligated to read and process their declarations;
- * for such documents, the rule that an entity must be declared is a
- * well-formedness constraint only if standalone='yes'.
- *
- * [ WFC: Parsed Entity ]
- * An entity reference must not contain the name of an unparsed entity
- *
- * Returns the xmlEntityPtr if found, or NULL otherwise.
- */
-xmlEntityPtr
-xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
-    const xmlChar *name;
-    xmlEntityPtr ent = NULL;
-
-    GROW;
-
-    if (RAW != '&')
-        return(NULL);
-    NEXT;
-    name = xmlParseName(ctxt);
-    if (name == NULL) {
-	xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
-		       "xmlParseEntityRef: no name\n");
-        return(NULL);
-    }
-    if (RAW != ';') {
-	xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL);
-	return(NULL);
-    }
-    NEXT;
+static xmlEntityPtr
+xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr) {
+    xmlEntityPtr ent;
 
     /*
      * Predefined entities override any extra definition
@@ -7642,6 +7623,7 @@
     else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
 	xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY,
 		 "Entity reference to unparsed entity %s\n", name);
+        ent = NULL;
     }
 
     /*
@@ -7649,56 +7631,75 @@
      * Attribute values cannot contain direct or indirect
      * entity references to external entities.
      */
-    else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
-	     (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
-	xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL,
-	     "Attribute references external entity '%s'\n", name);
-    }
-    /*
-     * [ WFC: No < in Attribute Values ]
-     * The replacement text of any entity referred to directly or
-     * indirectly in an attribute value (other than "&lt;") must
-     * not contain a <.
-     */
-    else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
-	     (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) {
-	if ((ent->flags & XML_ENT_CHECKED_LT) == 0) {
-            if ((ent->content != NULL) && (xmlStrchr(ent->content, '<')))
-                ent->flags |= XML_ENT_CONTAINS_LT;
-            ent->flags |= XML_ENT_CHECKED_LT;
+    else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
+        if (inAttr) {
+            xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL,
+                 "Attribute references external entity '%s'\n", name);
+            ent = NULL;
         }
-        if (ent->flags & XML_ENT_CONTAINS_LT)
-            xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE,
-                    "'<' in entity '%s' is not allowed in attributes "
-                    "values\n", name);
     }
 
-    /*
-     * Internal check, no parameter entities here ...
-     */
-    else {
-	switch (ent->etype) {
-	    case XML_INTERNAL_PARAMETER_ENTITY:
-	    case XML_EXTERNAL_PARAMETER_ENTITY:
-	    xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER,
-	     "Attempt to reference the parameter entity '%s'\n",
-			      name);
-	    break;
-	    default:
-	    break;
-	}
-    }
-
-    /*
-     * [ WFC: No Recursion ]
-     * A parsed entity must not contain a recursive reference
-     * to itself, either directly or indirectly.
-     * Done somewhere else
-     */
     return(ent);
 }
 
 /**
+ * xmlParseEntityRefInternal:
+ * @ctxt:  an XML parser context
+ * @inAttr:  whether we are in an attribute value
+ *
+ * Parse an entity reference. Always consumes '&'.
+ *
+ * [68] EntityRef ::= '&' Name ';'
+ *
+ * Returns the name, or NULL in case of error.
+ */
+static const xmlChar *
+xmlParseEntityRefInternal(xmlParserCtxtPtr ctxt) {
+    const xmlChar *name;
+
+    GROW;
+
+    if (RAW != '&')
+        return(NULL);
+    NEXT;
+    name = xmlParseName(ctxt);
+    if (name == NULL) {
+	xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
+		       "xmlParseEntityRef: no name\n");
+        return(NULL);
+    }
+    if (RAW != ';') {
+	xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL);
+	return(NULL);
+    }
+    NEXT;
+
+    return(name);
+}
+
+/**
+ * xmlParseEntityRef:
+ * @ctxt:  an XML parser context
+ *
+ * DEPRECATED: Internal function, don't use.
+ *
+ * Returns the xmlEntityPtr if found, or NULL otherwise.
+ */
+xmlEntityPtr
+xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
+    const xmlChar *name;
+
+    if (ctxt == NULL)
+        return(NULL);
+
+    name = xmlParseEntityRefInternal(ctxt);
+    if (name == NULL)
+        return(NULL);
+
+    return(xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 0));
+}
+
+/**
  * xmlParseStringEntityRef:
  * @ctxt:  an XML parser context
  * @str:  a pointer to an index in the string
@@ -7729,12 +7730,11 @@
  * Returns the xmlEntityPtr if found, or NULL otherwise. The str pointer
  * is updated to the current location in the string.
  */
-static xmlEntityPtr
+static xmlChar *
 xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) {
     xmlChar *name;
     const xmlChar *ptr;
     xmlChar cur;
-    xmlEntityPtr ent = NULL;
 
     if ((str == NULL) || (*str == NULL))
         return(NULL);
@@ -7759,133 +7759,8 @@
     }
     ptr++;
 
-
-    /*
-     * Predefined entities override any extra definition
-     */
-    if ((ctxt->options & XML_PARSE_OLDSAX) == 0) {
-        ent = xmlGetPredefinedEntity(name);
-        if (ent != NULL) {
-            xmlFree(name);
-            *str = ptr;
-            return(ent);
-        }
-    }
-
-    /*
-     * Ask first SAX for entity resolution, otherwise try the
-     * entities which may have stored in the parser context.
-     */
-    if (ctxt->sax != NULL) {
-	if (ctxt->sax->getEntity != NULL)
-	    ent = ctxt->sax->getEntity(ctxt->userData, name);
-	if ((ent == NULL) && (ctxt->options & XML_PARSE_OLDSAX))
-	    ent = xmlGetPredefinedEntity(name);
-	if ((ent == NULL) && (ctxt->userData==ctxt)) {
-	    ent = xmlSAX2GetEntity(ctxt, name);
-	}
-    }
-
-    /*
-     * [ WFC: Entity Declared ]
-     * In a document without any DTD, a document with only an
-     * internal DTD subset which contains no parameter entity
-     * references, or a document with "standalone='yes'", the
-     * Name given in the entity reference must match that in an
-     * entity declaration, except that well-formed documents
-     * need not declare any of the following entities: amp, lt,
-     * gt, apos, quot.
-     * The declaration of a parameter entity must precede any
-     * reference to it.
-     * Similarly, the declaration of a general entity must
-     * precede any reference to it which appears in a default
-     * value in an attribute-list declaration. Note that if
-     * entities are declared in the external subset or in
-     * external parameter entities, a non-validating processor
-     * is not obligated to read and process their declarations;
-     * for such documents, the rule that an entity must be
-     * declared is a well-formedness constraint only if
-     * standalone='yes'.
-     */
-    if (ent == NULL) {
-	if ((ctxt->standalone == 1) ||
-	    ((ctxt->hasExternalSubset == 0) &&
-	     (ctxt->hasPErefs == 0))) {
-	    xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY,
-		     "Entity '%s' not defined\n", name);
-	} else {
-	    xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY,
-			  "Entity '%s' not defined\n",
-			  name);
-	}
-	/* TODO ? check regressions ctxt->valid = 0; */
-    }
-
-    /*
-     * [ WFC: Parsed Entity ]
-     * An entity reference must not contain the name of an
-     * unparsed entity
-     */
-    else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
-	xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY,
-		 "Entity reference to unparsed entity %s\n", name);
-    }
-
-    /*
-     * [ WFC: No External Entity References ]
-     * Attribute values cannot contain direct or indirect
-     * entity references to external entities.
-     */
-    else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
-	     (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
-	xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL,
-	 "Attribute references external entity '%s'\n", name);
-    }
-    /*
-     * [ WFC: No < in Attribute Values ]
-     * The replacement text of any entity referred to directly or
-     * indirectly in an attribute value (other than "&lt;") must
-     * not contain a <.
-     */
-    else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
-	     (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) {
-	if ((ent->flags & XML_ENT_CHECKED_LT) == 0) {
-            if ((ent->content != NULL) && (xmlStrchr(ent->content, '<')))
-                ent->flags |= XML_ENT_CONTAINS_LT;
-            ent->flags |= XML_ENT_CHECKED_LT;
-        }
-        if (ent->flags & XML_ENT_CONTAINS_LT)
-            xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE,
-                    "'<' in entity '%s' is not allowed in attributes "
-                    "values\n", name);
-    }
-
-    /*
-     * Internal check, no parameter entities here ...
-     */
-    else {
-	switch (ent->etype) {
-	    case XML_INTERNAL_PARAMETER_ENTITY:
-	    case XML_EXTERNAL_PARAMETER_ENTITY:
-		xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER,
-	     "Attempt to reference the parameter entity '%s'\n",
-				  name);
-	    break;
-	    default:
-	    break;
-	}
-    }
-
-    /*
-     * [ WFC: No Recursion ]
-     * A parsed entity must not contain a recursive reference
-     * to itself, either directly or indirectly.
-     * Done somewhere else
-     */
-
-    xmlFree(name);
     *str = ptr;
-    return(ent);
+    return(name);
 }
 
 /**
@@ -7935,9 +7810,6 @@
 	xmlFatalErrMsg(ctxt, XML_ERR_PEREF_NO_NAME, "PEReference: no name\n");
 	return;
     }
-    if (xmlParserDebugEntities)
-	xmlGenericError(xmlGenericErrorContext,
-		"PEReference: %s\n", name);
     if (RAW != ';') {
 	xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL);
         return;
@@ -7994,16 +7866,11 @@
 		  "Internal: %%%s; is not a parameter entity\n",
 			  name, NULL);
 	} else {
-            unsigned long parentConsumed;
-            xmlEntityPtr oldEnt;
-
 	    if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
-	        ((ctxt->options & XML_PARSE_NOENT) == 0) &&
-		((ctxt->options & XML_PARSE_DTDVALID) == 0) &&
-		((ctxt->options & XML_PARSE_DTDLOAD) == 0) &&
-		((ctxt->options & XML_PARSE_DTDATTR) == 0) &&
-		(ctxt->replaceEntities == 0) &&
-		(ctxt->validate == 0))
+                ((ctxt->options & XML_PARSE_NO_XXE) ||
+		 ((ctxt->loadsubset == 0) &&
+		  (ctxt->replaceEntities == 0) &&
+		  (ctxt->validate == 0))))
 		return;
 
             if (entity->flags & XML_ENT_EXPANDING) {
@@ -8012,17 +7879,6 @@
                 return;
             }
 
-            /* Must be computed from old input before pushing new input. */
-            parentConsumed = ctxt->input->parentConsumed;
-            oldEnt = ctxt->input->entity;
-            if ((oldEnt == NULL) ||
-                ((oldEnt->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
-                 ((oldEnt->flags & XML_ENT_PARSED) == 0))) {
-                xmlSaturatedAdd(&parentConsumed, ctxt->input->consumed);
-                xmlSaturatedAddSizeT(&parentConsumed,
-                                     ctxt->input->cur - ctxt->input->base);
-            }
-
 	    input = xmlNewEntityInputStream(ctxt, entity);
 	    if (xmlPushInput(ctxt, input) < 0) {
                 xmlFreeInputStream(input);
@@ -8031,8 +7887,6 @@
 
             entity->flags |= XML_ENT_EXPANDING;
 
-            input->parentConsumed = parentConsumed;
-
 	    if (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) {
                 xmlDetectEncoding(ctxt);
 
@@ -8064,7 +7918,7 @@
     const xmlChar *oldencoding;
     xmlChar *content = NULL;
     size_t length, i;
-    int oldinputNr, oldinputMax, oldprogressive;
+    int oldinputNr, oldinputMax;
     int ret = -1;
     int res;
 
@@ -8072,38 +7926,29 @@
         ((entity->etype != XML_EXTERNAL_PARAMETER_ENTITY) &&
 	 (entity->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY)) ||
 	(entity->content != NULL)) {
-	xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
+	xmlFatalErr(ctxt, XML_ERR_ARGUMENT,
 	            "xmlLoadEntityContent parameter error");
         return(-1);
     }
 
-    if (xmlParserDebugEntities)
-	xmlGenericError(xmlGenericErrorContext,
-		"Reading %s entity content input\n", entity->name);
-
     input = xmlLoadExternalEntity((char *) entity->URI,
            (char *) entity->ExternalID, ctxt);
-    if (input == NULL) {
-	xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
-	            "xmlLoadEntityContent input error");
+    if (input == NULL)
         return(-1);
-    }
 
     oldinput = ctxt->input;
     oldinputNr = ctxt->inputNr;
     oldinputMax = ctxt->inputMax;
     oldinputTab = ctxt->inputTab;
     oldencoding = ctxt->encoding;
-    oldprogressive = ctxt->progressive;
 
     ctxt->input = NULL;
     ctxt->inputNr = 0;
     ctxt->inputMax = 1;
     ctxt->encoding = NULL;
-    ctxt->progressive = 0;
     ctxt->inputTab = xmlMalloc(sizeof(xmlParserInputPtr));
     if (ctxt->inputTab == NULL) {
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
         xmlFreeInputStream(input);
         goto error;
     }
@@ -8139,7 +7984,7 @@
     xmlBufResetInput(input->buf->buffer, input);
 
     if (res < 0) {
-        xmlFatalErr(ctxt, input->buf->error, NULL);
+        xmlCtxtErrIO(ctxt, input->buf->error, NULL);
         goto error;
     }
 
@@ -8147,7 +7992,7 @@
     content = xmlBufDetach(input->buf->buffer);
 
     if (length > INT_MAX) {
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
         goto error;
     }
 
@@ -8181,7 +8026,6 @@
     ctxt->inputMax = oldinputMax;
     ctxt->inputTab = oldinputTab;
     ctxt->encoding = oldencoding;
-    ctxt->progressive = oldprogressive;
 
     xmlFree(content);
 
@@ -8389,8 +8233,8 @@
      * Is there any DTD definition ?
      */
     if (RAW == '[') {
-        int baseInputNr = ctxt->inputNr;
-        ctxt->instate = XML_PARSER_DTD;
+        int oldInputNr = ctxt->inputNr;
+
         NEXT;
 	/*
 	 * Parse the succession of Markup declarations and
@@ -8398,14 +8242,14 @@
 	 * Subsequence (markupdecl | PEReference | S)*
 	 */
 	SKIP_BLANKS;
-	while (((RAW != ']') || (ctxt->inputNr > baseInputNr)) &&
+	while (((RAW != ']') || (ctxt->inputNr > oldInputNr)) &&
                (PARSER_STOPPED(ctxt) == 0)) {
 
             /*
              * Conditional sections are allowed from external entities included
              * by PE References in the internal subset.
              */
-            if ((ctxt->inputNr > 1) && (ctxt->input->filename != NULL) &&
+            if ((PARSER_EXTERNAL(ctxt)) &&
                 (RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
                 xmlParseConditionalSections(ctxt);
             } else if ((RAW == '<') && ((NXT(1) == '!') || (NXT(1) == '?'))) {
@@ -8413,16 +8257,17 @@
             } else if (RAW == '%') {
 	        xmlParsePEReference(ctxt);
             } else {
-		xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
-                        "xmlParseInternalSubset: error detected in"
-                        " Markup declaration\n");
-                xmlHaltParser(ctxt);
-                return;
+		xmlFatalErr(ctxt, XML_ERR_INT_SUBSET_NOT_FINISHED, NULL);
+                break;
             }
-	    SKIP_BLANKS;
+	    SKIP_BLANKS_PE;
             SHRINK;
             GROW;
 	}
+
+        while (ctxt->inputNr > oldInputNr)
+            xmlPopPE(ctxt);
+
 	if (RAW == ']') {
 	    NEXT;
 	    SKIP_BLANKS;
@@ -8432,7 +8277,7 @@
     /*
      * We should be at the end of the DOCTYPE declaration.
      */
-    if (RAW != '>') {
+    if ((ctxt->wellFormed) && (RAW != '>')) {
 	xmlFatalErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED, NULL);
 	return;
     }
@@ -8497,7 +8342,6 @@
         NEXT;
 	SKIP_BLANKS;
 	val = xmlParseAttValue(ctxt);
-	ctxt->instate = XML_PARSER_CONTENT;
     } else {
 	xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
 	       "Specification mandates value for attribute %s\n", name);
@@ -8597,11 +8441,8 @@
 	   ((RAW != '/') || (NXT(1) != '>')) &&
 	   (IS_BYTE_CHAR(RAW))) && (PARSER_STOPPED(ctxt) == 0)) {
 	attname = xmlParseAttribute(ctxt, &attvalue);
-        if (attname == NULL) {
-	    xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
-			   "xmlParseStartTag: problem parsing attributes\n");
+        if (attname == NULL)
 	    break;
-	}
         if (attvalue != NULL) {
 	    /*
 	     * [ WFC: Unique Att Spec ]
@@ -8623,7 +8464,7 @@
 	        atts = (const xmlChar **)
 		       xmlMalloc(maxatts * sizeof(xmlChar *));
 		if (atts == NULL) {
-		    xmlErrMemory(ctxt, NULL);
+		    xmlErrMemory(ctxt);
 		    if (attvalue != NULL)
 			xmlFree(attvalue);
 		    goto failed;
@@ -8637,7 +8478,7 @@
 	        n = (const xmlChar **) xmlRealloc((void *) atts,
 					     maxatts * sizeof(const xmlChar *));
 		if (n == NULL) {
-		    xmlErrMemory(ctxt, NULL);
+		    xmlErrMemory(ctxt);
 		    if (attvalue != NULL)
 			xmlFree(attvalue);
 		    goto failed;
@@ -8826,7 +8667,7 @@
         l = xmlDictLookupHashed(ctxt->dict, BASE_PTR + start,
                                 CUR_PTR - (BASE_PTR + start));
         if (l.name == NULL) {
-            xmlErrMemory(ctxt, NULL);
+            xmlErrMemory(ctxt);
             return(l);
         }
         xmlNsErr(ctxt, XML_NS_ERR_QNAME,
@@ -8919,202 +8760,6 @@
 }
 
 /**
- * xmlParseAttValueInternal:
- * @ctxt:  an XML parser context
- * @len:  attribute len result
- * @alloc:  whether the attribute was reallocated as a new string
- * @normalize:  if 1 then further non-CDATA normalization must be done
- *
- * parse a value for an attribute.
- * NOTE: if no normalization is needed, the routine will return pointers
- *       directly from the data buffer.
- *
- * 3.3.3 Attribute-Value Normalization:
- * Before the value of an attribute is passed to the application or
- * checked for validity, the XML processor must normalize it as follows:
- * - a character reference is processed by appending the referenced
- *   character to the attribute value
- * - an entity reference is processed by recursively processing the
- *   replacement text of the entity
- * - a whitespace character (#x20, #xD, #xA, #x9) is processed by
- *   appending #x20 to the normalized value, except that only a single
- *   #x20 is appended for a "#xD#xA" sequence that is part of an external
- *   parsed entity or the literal entity value of an internal parsed entity
- * - other characters are processed by appending them to the normalized value
- * If the declared value is not CDATA, then the XML processor must further
- * process the normalized attribute value by discarding any leading and
- * trailing space (#x20) characters, and by replacing sequences of space
- * (#x20) characters by a single space (#x20) character.
- * All attributes for which no declaration has been read should be treated
- * by a non-validating parser as if declared CDATA.
- *
- * Returns the AttValue parsed or NULL. The value has to be freed by the
- *     caller if it was copied, this can be detected by val[*len] == 0.
- */
-
-#define GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) \
-    const xmlChar *oldbase = ctxt->input->base;\
-    GROW;\
-    if (oldbase != ctxt->input->base) {\
-        ptrdiff_t delta = ctxt->input->base - oldbase;\
-        start = start + delta;\
-        in = in + delta;\
-    }\
-    end = ctxt->input->end;
-
-static xmlChar *
-xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc,
-                         int normalize)
-{
-    xmlChar limit = 0;
-    const xmlChar *in = NULL, *start, *end, *last;
-    xmlChar *ret = NULL;
-    int line, col;
-    int maxLength = (ctxt->options & XML_PARSE_HUGE) ?
-                    XML_MAX_HUGE_LENGTH :
-                    XML_MAX_TEXT_LENGTH;
-
-    GROW;
-    in = (xmlChar *) CUR_PTR;
-    line = ctxt->input->line;
-    col = ctxt->input->col;
-    if (*in != '"' && *in != '\'') {
-        xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL);
-        return (NULL);
-    }
-    ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
-
-    /*
-     * try to handle in this routine the most common case where no
-     * allocation of a new string is required and where content is
-     * pure ASCII.
-     */
-    limit = *in++;
-    col++;
-    end = ctxt->input->end;
-    start = in;
-    if (in >= end) {
-        GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end)
-    }
-    if (normalize) {
-        /*
-	 * Skip any leading spaces
-	 */
-	while ((in < end) && (*in != limit) &&
-	       ((*in == 0x20) || (*in == 0x9) ||
-	        (*in == 0xA) || (*in == 0xD))) {
-	    if (*in == 0xA) {
-	        line++; col = 1;
-	    } else {
-	        col++;
-	    }
-	    in++;
-	    start = in;
-	    if (in >= end) {
-                GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end)
-                if ((in - start) > maxLength) {
-                    xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
-                                   "AttValue length too long\n");
-                    return(NULL);
-                }
-	    }
-	}
-	while ((in < end) && (*in != limit) && (*in >= 0x20) &&
-	       (*in <= 0x7f) && (*in != '&') && (*in != '<')) {
-	    col++;
-	    if ((*in++ == 0x20) && (*in == 0x20)) break;
-	    if (in >= end) {
-                GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end)
-                if ((in - start) > maxLength) {
-                    xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
-                                   "AttValue length too long\n");
-                    return(NULL);
-                }
-	    }
-	}
-	last = in;
-	/*
-	 * skip the trailing blanks
-	 */
-	while ((last[-1] == 0x20) && (last > start)) last--;
-	while ((in < end) && (*in != limit) &&
-	       ((*in == 0x20) || (*in == 0x9) ||
-	        (*in == 0xA) || (*in == 0xD))) {
-	    if (*in == 0xA) {
-	        line++, col = 1;
-	    } else {
-	        col++;
-	    }
-	    in++;
-	    if (in >= end) {
-		const xmlChar *oldbase = ctxt->input->base;
-		GROW;
-		if (oldbase != ctxt->input->base) {
-		    ptrdiff_t delta = ctxt->input->base - oldbase;
-		    start = start + delta;
-		    in = in + delta;
-		    last = last + delta;
-		}
-		end = ctxt->input->end;
-                if ((in - start) > maxLength) {
-                    xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
-                                   "AttValue length too long\n");
-                    return(NULL);
-                }
-	    }
-	}
-        if ((in - start) > maxLength) {
-            xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
-                           "AttValue length too long\n");
-            return(NULL);
-        }
-	if (*in != limit) goto need_complex;
-    } else {
-	while ((in < end) && (*in != limit) && (*in >= 0x20) &&
-	       (*in <= 0x7f) && (*in != '&') && (*in != '<')) {
-	    in++;
-	    col++;
-	    if (in >= end) {
-                GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end)
-                if ((in - start) > maxLength) {
-                    xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
-                                   "AttValue length too long\n");
-                    return(NULL);
-                }
-	    }
-	}
-	last = in;
-        if ((in - start) > maxLength) {
-            xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
-                           "AttValue length too long\n");
-            return(NULL);
-        }
-	if (*in != limit) goto need_complex;
-    }
-    in++;
-    col++;
-    if (len != NULL) {
-        if (alloc) *alloc = 0;
-        *len = last - start;
-        ret = (xmlChar *) start;
-    } else {
-        if (alloc) *alloc = 1;
-        ret = xmlStrndup(start, last - start);
-        if (ret == NULL) {
-            xmlErrMemory(ctxt, NULL);
-            return(NULL);
-        }
-    }
-    CUR_PTR = in;
-    ctxt->input->line = line;
-    ctxt->input->col = col;
-    return ret;
-need_complex:
-    if (alloc) *alloc = 1;
-    return xmlParseAttValueComplex(ctxt, len, normalize);
-}
-
-/**
  * xmlParseAttribute2:
  * @ctxt:  an XML parser context
  * @pref:  the element prefix
@@ -9177,24 +8822,6 @@
         val = xmlParseAttValueInternal(ctxt, len, alloc, normalize);
         if (val == NULL)
             goto error;
-	if (normalize) {
-	    /*
-	     * Sometimes a second normalisation pass for spaces is needed
-	     * but that only happens if charrefs or entities references
-	     * have been used in the attribute value, i.e. the attribute
-	     * value have been extracted in an allocated string already.
-	     */
-	    if (*alloc) {
-	        const xmlChar *val2;
-
-	        val2 = xmlAttrNormalizeSpace2(ctxt, val, len);
-		if ((val2 != NULL) && (val2 != val)) {
-		    xmlFree(val);
-		    val = (xmlChar *) val2;
-		}
-	    }
-	}
-        ctxt->instate = XML_PARSER_CONTENT;
     } else {
         xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
                           "Specification mandates value for attribute %s\n",
@@ -9245,7 +8872,7 @@
     return (hname);
 
 mem_error:
-    xmlErrMemory(ctxt, NULL);
+    xmlErrMemory(ctxt);
 error:
     if ((val != NULL) && (*alloc != 0))
         xmlFree(val);
@@ -9346,14 +8973,13 @@
     const xmlChar **atts = ctxt->atts;
     unsigned attrHashSize = 0;
     int maxatts = ctxt->maxatts;
-    int nratts, nbatts, nbdef, inputid;
+    int nratts, nbatts, nbdef;
     int i, j, nbNs, nbTotalDef, attval, nsIndex, maxAtts;
     int alloc = 0;
 
     if (RAW != '<') return(NULL);
     NEXT1;
 
-    inputid = ctxt->input->id;
     nbatts = 0;
     nratts = 0;
     nbdef = 0;
@@ -9362,7 +8988,7 @@
     attval = 0;
 
     if (xmlParserNsStartElement(ctxt->nsdb) < 0) {
-        xmlErrMemory(ctxt, NULL);
+        xmlErrMemory(ctxt);
         return(NULL);
     }
 
@@ -9415,11 +9041,8 @@
 	hattname = xmlParseAttribute2(ctxt, prefix, localname,
                                           &haprefix, &attvalue, &len,
                                           &alloc);
-        if (hattname.name == NULL) {
-	    xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
-	         "xmlParseStartTag: problem parsing attributes\n");
+        if (hattname.name == NULL)
 	    break;
-	}
         if (attvalue == NULL)
             goto next_attr;
         attname = hattname.name;
@@ -9433,12 +9056,12 @@
             huri = xmlDictLookupHashed(ctxt->dict, attvalue, len);
             uri = huri.name;
             if (uri == NULL) {
-                xmlErrMemory(ctxt, NULL);
+                xmlErrMemory(ctxt);
                 goto next_attr;
             }
             if (*uri != 0) {
                 if (xmlParseURISafe((const char *) uri, &parsedUri) < 0) {
-                    xmlErrMemory(ctxt, NULL);
+                    xmlErrMemory(ctxt);
                     goto next_attr;
                 }
                 if (parsedUri == NULL) {
@@ -9480,7 +9103,7 @@
             huri = xmlDictLookupHashed(ctxt->dict, attvalue, len);
             uri = huri.name;
             if (uri == NULL) {
-                xmlErrMemory(ctxt, NULL);
+                xmlErrMemory(ctxt);
                 goto next_attr;
             }
 
@@ -9524,7 +9147,7 @@
                 goto next_attr;
             } else {
                 if (xmlParseURISafe((const char *) uri, &parsedUri) < 0) {
-                    xmlErrMemory(ctxt, NULL);
+                    xmlErrMemory(ctxt);
                     goto next_attr;
                 }
                 if (parsedUri == NULL) {
@@ -9598,13 +9221,6 @@
         GROW;
     }
 
-    if (ctxt->input->id != inputid) {
-        xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
-                    "Unexpected change of input\n");
-        localname = NULL;
-        goto done;
-    }
-
     /*
      * Namespaces from default attributes
      */
@@ -9655,7 +9271,8 @@
             haprefix.name = aprefix;
             haprefix.hashValue = (size_t) atts[i+2];
             nsIndex = xmlParserNsLookup(ctxt, &haprefix, NULL);
-	    if (nsIndex == INT_MAX) {
+
+	    if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) {
                 xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
 		    "Namespace prefix %s for %s on %s is not defined\n",
 		    aprefix, attname, localname);
@@ -9684,7 +9301,7 @@
 
             tmp = xmlRealloc(ctxt->attrHash, attrHashSize * sizeof(tmp[0]));
             if (tmp == NULL) {
-                xmlErrMemory(ctxt, NULL);
+                xmlErrMemory(ctxt);
                 goto done;
             }
 
@@ -9706,6 +9323,12 @@
             nameHashValue = ctxt->attallocs[j] | 0x80000000;
 
             if (nsIndex == NS_INDEX_EMPTY) {
+                /*
+                 * Prefix with empty namespace means an undeclared
+                 * prefix which was already reported above.
+                 */
+                if (aprefix != NULL)
+                    continue;
                 nsuri = NULL;
                 uriHashValue = URI_HASH_EMPTY;
             } else if (nsIndex == NS_INDEX_XML) {
@@ -9772,7 +9395,8 @@
                     uriHashValue = URI_HASH_XML;
                 } else if (aprefix != NULL) {
                     nsIndex = xmlParserNsLookup(ctxt, &attr->prefix, NULL);
-                    if (nsIndex == INT_MAX) {
+                    if ((nsIndex == INT_MAX) ||
+                        (nsIndex < ctxt->nsdb->minNsIndex)) {
                         xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
                                  "Namespace prefix %s for %s on %s is not "
                                  "defined\n",
@@ -9991,7 +9615,6 @@
         return;
     SKIP(6);
 
-    ctxt->instate = XML_PARSER_CDATA_SECTION;
     r = CUR_CHAR(rl);
     if (!IS_CHAR(r)) {
 	xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL);
@@ -10007,7 +9630,7 @@
     cur = CUR_CHAR(l);
     buf = (xmlChar *) xmlMallocAtomic(size);
     if (buf == NULL) {
-	xmlErrMemory(ctxt, NULL);
+	xmlErrMemory(ctxt);
         goto out;
     }
     while (IS_CHAR(cur) &&
@@ -10017,7 +9640,7 @@
 
 	    tmp = (xmlChar *) xmlRealloc(buf, size * 2);
 	    if (tmp == NULL) {
-		xmlErrMemory(ctxt, NULL);
+		xmlErrMemory(ctxt);
                 goto out;
 	    }
 	    buf = tmp;
@@ -10055,7 +9678,6 @@
     }
 
 out:
-    ctxt->instate = XML_PARSER_CONTENT;
     xmlFree(buf);
 }
 
@@ -10069,7 +9691,9 @@
 
 static void
 xmlParseContentInternal(xmlParserCtxtPtr ctxt) {
-    int nameNr = ctxt->nameNr;
+    int oldNameNr = ctxt->nameNr;
+    int oldSpaceNr = ctxt->spaceNr;
+    int oldNodeNr = ctxt->nodeNr;
 
     GROW;
     while ((ctxt->input->cur < ctxt->input->end) &&
@@ -10104,7 +9728,7 @@
 	 */
 	else if (*cur == '<') {
             if (NXT(1) == '/') {
-                if (ctxt->nameNr <= nameNr)
+                if (ctxt->nameNr <= oldNameNr)
                     break;
 	        xmlParseElementEnd(ctxt);
             } else {
@@ -10131,31 +9755,56 @@
 	SHRINK;
 	GROW;
     }
+
+    if ((ctxt->nameNr > oldNameNr) &&
+        (ctxt->input->cur >= ctxt->input->end) &&
+        (ctxt->wellFormed)) {
+        const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
+        int line = ctxt->pushTab[ctxt->nameNr - 1].line;
+        xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
+                "Premature end of data in tag %s line %d\n",
+                name, line, NULL);
+    }
+
+    /*
+     * Clean up in error case
+     */
+
+    while (ctxt->nodeNr > oldNodeNr)
+        nodePop(ctxt);
+
+    while (ctxt->nameNr > oldNameNr) {
+        xmlStartTag *tag = &ctxt->pushTab[ctxt->nameNr - 1];
+
+        if (tag->nsNr != 0)
+            xmlParserNsPop(ctxt, tag->nsNr);
+
+        namePop(ctxt);
+    }
+
+    while (ctxt->spaceNr > oldSpaceNr)
+        spacePop(ctxt);
 }
 
 /**
  * xmlParseContent:
  * @ctxt:  an XML parser context
  *
- * Parse a content sequence. Stops at EOF or '</'.
- *
- * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ * Parse XML element content. This is useful if you're only interested
+ * in custom SAX callbacks. If you want a node list, use
+ * xmlParseInNodeContext.
  */
-
 void
 xmlParseContent(xmlParserCtxtPtr ctxt) {
-    int nameNr = ctxt->nameNr;
+    if ((ctxt == NULL) || (ctxt->input == NULL))
+        return;
+
+    xmlCtxtInitializeLate(ctxt);
 
     xmlParseContentInternal(ctxt);
 
-    if ((ctxt->errNo == XML_ERR_OK) &&
-        (ctxt->nameNr > nameNr)) {
-        const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
-        int line = ctxt->pushTab[ctxt->nameNr - 1].line;
-        xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
-                "Premature end of data in tag %s line %d\n",
-		name, line, NULL);
-    }
+    if (ctxt->input->cur < ctxt->input->end)
+	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
 }
 
 /**
@@ -10182,7 +9831,7 @@
     xmlParseContentInternal(ctxt);
 
     if (ctxt->input->cur >= ctxt->input->end) {
-        if (ctxt->errNo == XML_ERR_OK) {
+        if (ctxt->wellFormed) {
             const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
             int line = ctxt->pushTab[ctxt->nameNr - 1].line;
             xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
@@ -10206,6 +9855,7 @@
  */
 static int
 xmlParseElementStart(xmlParserCtxtPtr ctxt) {
+    int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256;
     const xmlChar *name;
     const xmlChar *prefix = NULL;
     const xmlChar *URI = NULL;
@@ -10214,11 +9864,10 @@
     xmlNodePtr cur;
     int nbNs = 0;
 
-    if (((unsigned int) ctxt->nameNr > xmlParserMaxDepth) &&
-        ((ctxt->options & XML_PARSE_HUGE) == 0)) {
-	xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR,
-		 "Excessive depth in document: %d use XML_PARSE_HUGE option\n",
-			  xmlParserMaxDepth);
+    if (ctxt->nameNr > maxDepth) {
+        xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT,
+                "Excessive depth in document: %d use XML_PARSE_HUGE option\n",
+                ctxt->nameNr);
 	xmlHaltParser(ctxt);
 	return(-1);
     }
@@ -10386,7 +10035,7 @@
 
     buf = (xmlChar *) xmlMallocAtomic(size);
     if (buf == NULL) {
-	xmlErrMemory(ctxt, NULL);
+	xmlErrMemory(ctxt);
 	return(NULL);
     }
     cur = CUR;
@@ -10412,7 +10061,7 @@
 	    tmp = (xmlChar *) xmlRealloc(buf, size);
 	    if (tmp == NULL) {
 	        xmlFree(buf);
-		xmlErrMemory(ctxt, NULL);
+		xmlErrMemory(ctxt);
 		return(NULL);
 	    }
 	    buf = tmp;
@@ -10501,7 +10150,7 @@
         ((cur >= 'A') && (cur <= 'Z'))) {
 	buf = (xmlChar *) xmlMallocAtomic(size);
 	if (buf == NULL) {
-	    xmlErrMemory(ctxt, NULL);
+	    xmlErrMemory(ctxt);
 	    return(NULL);
 	}
 
@@ -10519,7 +10168,7 @@
 		size *= 2;
 		tmp = (xmlChar *) xmlRealloc(buf, size);
 		if (tmp == NULL) {
-		    xmlErrMemory(ctxt, NULL);
+		    xmlErrMemory(ctxt);
 		    xmlFree(buf);
 		    return(NULL);
 		}
@@ -10765,12 +10414,6 @@
 	xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Blank needed here\n");
     }
     xmlParseEncodingDecl(ctxt);
-    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
-	/*
-	 * The XML REC instructs us to stop parsing right here
-	 */
-        return;
-    }
 
     /*
      * We may have the standalone status.
@@ -10837,25 +10480,52 @@
     }
 }
 
+static void
+xmlFinishDocument(xmlParserCtxtPtr ctxt) {
+    xmlDocPtr doc;
+
+    /*
+     * SAX: end of the document processing.
+     */
+    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+        ctxt->sax->endDocument(ctxt->userData);
+
+    doc = ctxt->myDoc;
+    if (doc != NULL) {
+        if (ctxt->wellFormed) {
+            doc->properties |= XML_DOC_WELLFORMED;
+            if (ctxt->valid)
+                doc->properties |= XML_DOC_DTDVALID;
+            if (ctxt->nsWellFormed)
+                doc->properties |= XML_DOC_NSVALID;
+        }
+
+        if (ctxt->options & XML_PARSE_OLD10)
+            doc->properties |= XML_DOC_OLD10;
+
+        /*
+         * Remove locally kept entity definitions if the tree was not built
+         */
+	if (xmlStrEqual(doc->version, SAX_COMPAT_MODE)) {
+            xmlFreeDoc(doc);
+            ctxt->myDoc = NULL;
+        }
+    }
+}
+
 /**
  * xmlParseDocument:
  * @ctxt:  an XML parser context
  *
- * parse an XML document (and build a tree if using the standard SAX
- * interface).
+ * Parse an XML document and invoke the SAX handlers. This is useful
+ * if you're only interested in custom SAX callbacks. If you want a
+ * document tree, use xmlCtxtParseDocument.
  *
- * [1] document ::= prolog element Misc*
- *
- * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
- *
- * Returns 0, -1 in case of error. the parser context is augmented
- *                as a result of the parsing.
+ * Returns 0, -1 in case of error.
  */
 
 int
 xmlParseDocument(xmlParserCtxtPtr ctxt) {
-    xmlInitParser();
-
     if ((ctxt == NULL) || (ctxt->input == NULL))
         return(-1);
 
@@ -10864,7 +10534,7 @@
     /*
      * SAX: detecting the level.
      */
-    xmlDetectSAX2(ctxt);
+    xmlCtxtInitializeLate(ctxt);
 
     /*
      * Document locator is unused. Only for backward compatibility.
@@ -10888,17 +10558,11 @@
 	 * Note that we will switch encoding on the fly.
 	 */
 	xmlParseXMLDecl(ctxt);
-	if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
-	    /*
-	     * The XML REC instructs us to stop parsing right here
-	     */
-	    return(-1);
-	}
 	SKIP_BLANKS;
     } else {
 	ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
         if (ctxt->version == NULL) {
-            xmlErrMemory(ctxt, NULL);
+            xmlErrMemory(ctxt);
             return(-1);
         }
     }
@@ -10924,7 +10588,6 @@
 	ctxt->inSubset = 1;
 	xmlParseDocTypeDecl(ctxt);
 	if (RAW == '[') {
-	    ctxt->instate = XML_PARSER_DTD;
 	    xmlParseInternalSubset(ctxt);
 	}
 
@@ -10940,7 +10603,6 @@
 
         xmlCleanSpecialAttr(ctxt);
 
-	ctxt->instate = XML_PARSER_PROLOG;
 	xmlParseMisc(ctxt);
     }
 
@@ -10949,12 +10611,11 @@
      */
     GROW;
     if (RAW != '<') {
-	xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY,
-		       "Start tag expected, '<' not found\n");
+        if (ctxt->wellFormed)
+            xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY,
+                           "Start tag expected, '<' not found\n");
     } else {
-	ctxt->instate = XML_PARSER_CONTENT;
 	xmlParseElement(ctxt);
-	ctxt->instate = XML_PARSER_EPILOG;
 
 	/*
 	 * The Misc part at the end
@@ -10962,7 +10623,7 @@
 	xmlParseMisc(ctxt);
 
         if (ctxt->input->cur < ctxt->input->end) {
-            if (ctxt->errNo == XML_ERR_OK)
+            if (ctxt->wellFormed)
 	        xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL);
         } else if ((ctxt->input->buf != NULL) &&
                    (ctxt->input->buf->encoder != NULL) &&
@@ -10970,37 +10631,16 @@
             xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR,
                            "Truncated multi-byte sequence at EOF\n");
         }
-	ctxt->instate = XML_PARSER_EOF;
     }
 
-    /*
-     * SAX: end of the document processing.
-     */
-    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
-        ctxt->sax->endDocument(ctxt->userData);
+    ctxt->instate = XML_PARSER_EOF;
+    xmlFinishDocument(ctxt);
 
-    /*
-     * Remove locally kept entity definitions if the tree was not built
-     */
-    if ((ctxt->myDoc != NULL) &&
-	(xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE))) {
-	xmlFreeDoc(ctxt->myDoc);
-	ctxt->myDoc = NULL;
-    }
-
-    if ((ctxt->wellFormed) && (ctxt->myDoc != NULL)) {
-        ctxt->myDoc->properties |= XML_DOC_WELLFORMED;
-	if (ctxt->valid)
-	    ctxt->myDoc->properties |= XML_DOC_DTDVALID;
-	if (ctxt->nsWellFormed)
-	    ctxt->myDoc->properties |= XML_DOC_NSVALID;
-	if (ctxt->options & XML_PARSE_OLD10)
-	    ctxt->myDoc->properties |= XML_DOC_OLD10;
-    }
     if (! ctxt->wellFormed) {
 	ctxt->valid = 0;
 	return(-1);
     }
+
     return(0);
 }
 
@@ -11023,7 +10663,7 @@
     if ((ctxt == NULL) || (ctxt->input == NULL))
         return(-1);
 
-    xmlDetectSAX2(ctxt);
+    xmlCtxtInitializeLate(ctxt);
 
     /*
      * Document locator is unused. Only for backward compatibility.
@@ -11049,12 +10689,6 @@
 	 * Note that we will switch encoding on the fly.
 	 */
 	xmlParseXMLDecl(ctxt);
-	if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
-	    /*
-	     * The XML REC instructs us to stop parsing right here
-	     */
-	    return(-1);
-	}
 	SKIP_BLANKS;
     } else {
 	ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
@@ -11065,18 +10699,14 @@
     /*
      * Doing validity checking on chunk doesn't make sense
      */
-    ctxt->instate = XML_PARSER_CONTENT;
+    ctxt->options &= ~XML_PARSE_DTDVALID;
     ctxt->validate = 0;
-    ctxt->loadsubset = 0;
     ctxt->depth = 0;
 
-    xmlParseContent(ctxt);
+    xmlParseContentInternal(ctxt);
 
-    if ((RAW == '<') && (NXT(1) == '/')) {
+    if (ctxt->input->cur < ctxt->input->end)
 	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
-    } else if (RAW != 0) {
-	xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL);
-    }
 
     /*
      * SAX: end of the document processing.
@@ -11489,25 +11119,17 @@
 			(IS_BLANK_CH(ctxt->input->cur[5]))) {
 			ret += 5;
 			xmlParseXMLDecl(ctxt);
-			if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
-			    /*
-			     * The XML REC instructs us to stop parsing right
-			     * here
-			     */
-			    xmlHaltParser(ctxt);
-			    return(0);
-			}
 		    } else {
 			ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
                         if (ctxt->version == NULL) {
-                            xmlErrMemory(ctxt, NULL);
+                            xmlErrMemory(ctxt);
                             break;
                         }
 		    }
 		} else {
 		    ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
 		    if (ctxt->version == NULL) {
-		        xmlErrMemory(ctxt, NULL);
+		        xmlErrMemory(ctxt);
 			break;
 		    }
 		}
@@ -11533,9 +11155,8 @@
 	        if (cur != '<') {
 		    xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY,
                                    "Start tag expected, '<' not found");
-		    xmlHaltParser(ctxt);
-		    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
-			ctxt->sax->endDocument(ctxt->userData);
+                    ctxt->instate = XML_PARSER_EOF;
+                    xmlFinishDocument(ctxt);
 		    goto done;
 		}
 		if ((!terminate) && (!xmlParseLookupGt(ctxt)))
@@ -11556,9 +11177,8 @@
 #endif /* LIBXML_SAX1_ENABLED */
 		if (name == NULL) {
 		    spacePop(ctxt);
-		    xmlHaltParser(ctxt);
-		    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
-			ctxt->sax->endDocument(ctxt->userData);
+                    ctxt->instate = XML_PARSER_EOF;
+                    xmlFinishDocument(ctxt);
 		    goto done;
 		}
 #ifdef LIBXML_VALID_ENABLED
@@ -11868,8 +11488,7 @@
                     if (ctxt->errNo == XML_ERR_OK)
                         xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL);
 		    ctxt->instate = XML_PARSER_EOF;
-                    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
-                        ctxt->sax->endDocument(ctxt->userData);
+                    xmlFinishDocument(ctxt);
                 } else {
 		    ctxt->instate = XML_PARSER_START_TAG;
 		}
@@ -11889,7 +11508,7 @@
                 break;
 	    }
             default:
-		xmlGenericError(xmlGenericErrorContext,
+                xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR,
 			"PP: internal error\n");
 		ctxt->instate = XML_PARSER_EOF;
 		break;
@@ -11898,19 +11517,10 @@
 done:
     return(ret);
 encoding_error:
-    if (ctxt->input->end - ctxt->input->cur < 4) {
-	__xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR,
-		     "Input is not proper UTF-8, indicate encoding !\n",
-		     NULL, NULL);
-    } else {
-        char buffer[150];
-
-	snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
-			ctxt->input->cur[0], ctxt->input->cur[1],
-			ctxt->input->cur[2], ctxt->input->cur[3]);
-	__xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR,
-		     "Input is not proper UTF-8, indicate encoding !\n%s",
-		     BAD_CAST buffer, NULL);
+    /* Only report the first error */
+    if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) {
+        xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL);
+        ctxt->input->flags |= XML_INPUT_ENCODING_ERROR;
     }
     return(0);
 }
@@ -11918,29 +11528,42 @@
 /**
  * xmlParseChunk:
  * @ctxt:  an XML parser context
- * @chunk:  an char array
- * @size:  the size in byte of the chunk
+ * @chunk:  chunk of memory
+ * @size:  size of chunk in bytes
  * @terminate:  last chunk indicator
  *
- * Parse a Chunk of memory
+ * Parse a chunk of memory in push parser mode.
  *
- * Returns zero if no error, the xmlParserErrors otherwise.
+ * Assumes that the parser context was initialized with
+ * xmlCreatePushParserCtxt.
+ *
+ * The last chunk, which will often be empty, must be marked with
+ * the @terminate flag. With the default SAX callbacks, the resulting
+ * document will be available in ctxt->myDoc. This pointer will not
+ * be freed by the library.
+ *
+ * If the document isn't well-formed, ctxt->myDoc is set to NULL.
+ * The push parser doesn't support recovery mode.
+ *
+ * Returns an xmlParserErrors code (0 on success).
  */
 int
 xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
               int terminate) {
+    size_t curBase;
+    size_t maxLength;
     int end_in_lf = 0;
 
-    if (ctxt == NULL)
-        return(XML_ERR_INTERNAL_ERROR);
+    if ((ctxt == NULL) || (size < 0))
+        return(XML_ERR_ARGUMENT);
     if (ctxt->disableSAX != 0)
         return(ctxt->errNo);
     if (ctxt->input == NULL)
-        return(-1);
+        return(XML_ERR_INTERNAL_ERROR);
 
-    ctxt->progressive = 1;
+    ctxt->input->flags |= XML_INPUT_PROGRESSIVE;
     if (ctxt->instate == XML_PARSER_START)
-        xmlDetectSAX2(ctxt);
+        xmlCtxtInitializeLate(ctxt);
     if ((size > 0) && (chunk != NULL) && (!terminate) &&
         (chunk[size - 1] == '\r')) {
 	end_in_lf = 1;
@@ -11955,7 +11578,7 @@
 	res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
         xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos);
 	if (res < 0) {
-            xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
+            xmlCtxtErrIO(ctxt, ctxt->input->buf->error, NULL);
 	    xmlHaltParser(ctxt);
 	    return(ctxt->errNo);
 	}
@@ -11963,14 +11586,16 @@
 
     xmlParseTryOrFinish(ctxt, terminate);
 
-    if ((ctxt->input != NULL) &&
-         (((ctxt->input->end - ctxt->input->cur) > XML_MAX_LOOKUP_LIMIT) ||
-         ((ctxt->input->cur - ctxt->input->base) > XML_MAX_LOOKUP_LIMIT)) &&
-        ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+    curBase = ctxt->input->cur - ctxt->input->base;
+    maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+                XML_MAX_HUGE_LENGTH :
+                XML_MAX_LOOKUP_LIMIT;
+    if (curBase > maxLength) {
         xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT,
                     "Buffer size limit exceeded, try XML_PARSE_HUGE\n");
         xmlHaltParser(ctxt);
     }
+
     if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1))
         return(ctxt->errNo);
 
@@ -11982,7 +11607,7 @@
 	res = xmlParserInputBufferPush(ctxt->input->buf, 1, "\r");
 	xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos);
         if (res < 0) {
-            xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
+            xmlCtxtErrIO(ctxt, ctxt->input->buf->error, NULL);
             xmlHaltParser(ctxt);
             return(ctxt->errNo);
         }
@@ -12012,10 +11637,9 @@
                            "Truncated multi-byte sequence at EOF\n");
         }
 	if (ctxt->instate != XML_PARSER_EOF) {
-	    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
-		ctxt->sax->endDocument(ctxt->userData);
+            ctxt->instate = XML_PARSER_EOF;
+            xmlFinishDocument(ctxt);
 	}
-	ctxt->instate = XML_PARSER_EOF;
     }
     if (ctxt->wellFormed == 0)
 	return((xmlParserErrors) ctxt->errNo);
@@ -12031,85 +11655,42 @@
 
 /**
  * xmlCreatePushParserCtxt:
- * @sax:  a SAX handler
- * @user_data:  The user data returned on SAX callbacks
- * @chunk:  a pointer to an array of chars
- * @size:  number of chars in the array
- * @filename:  an optional file name or URI
+ * @sax:  a SAX handler (optional)
+ * @user_data:  user data for SAX callbacks (optional)
+ * @chunk:  initial chunk (optional, deprecated)
+ * @size:  size of initial chunk in bytes
+ * @filename:  file name or URI (optional)
  *
  * Create a parser context for using the XML parser in push mode.
- * If @buffer and @size are non-NULL, the data is used to detect
- * the encoding.  The remaining characters will be parsed so they
- * don't need to be fed in again through xmlParseChunk.
- * To allow content encoding detection, @size should be >= 4
- * The value of @filename is used for fetching external entities
- * and error/warning reports.
+ * See xmlParseChunk.
  *
- * Returns the new parser context or NULL
+ * Passing an initial chunk is useless and deprecated.
+ *
+ * @filename is used as base URI to fetch external entities and for
+ * error reports.
+ *
+ * Returns the new parser context or NULL in case of error.
  */
 
 xmlParserCtxtPtr
 xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
                         const char *chunk, int size, const char *filename) {
     xmlParserCtxtPtr ctxt;
-    xmlParserInputPtr inputStream;
-    xmlParserInputBufferPtr buf;
-
-    buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
-    if (buf == NULL) return(NULL);
+    xmlParserInputPtr input;
 
     ctxt = xmlNewSAXParserCtxt(sax, user_data);
-    if (ctxt == NULL) {
-	xmlFreeParserInputBuffer(buf);
+    if (ctxt == NULL)
 	return(NULL);
-    }
+
+    ctxt->options &= ~XML_PARSE_NODICT;
     ctxt->dictNames = 1;
-    if (filename == NULL) {
-	ctxt->directory = NULL;
-    } else {
-        ctxt->directory = xmlParserGetDirectory(filename);
-        if (ctxt->directory == NULL) {
-            xmlFreeParserCtxt(ctxt);
-            xmlFreeParserInputBuffer(buf);
-            return(NULL);
-        }
-    }
 
-    inputStream = xmlNewInputStream(ctxt);
-    if (inputStream == NULL) {
+    input = xmlNewInputPush(ctxt, filename, chunk, size, NULL);
+    if (input == NULL) {
 	xmlFreeParserCtxt(ctxt);
-	xmlFreeParserInputBuffer(buf);
 	return(NULL);
     }
-
-    if (filename == NULL)
-	inputStream->filename = NULL;
-    else {
-	inputStream->filename = (char *)
-	    xmlCanonicPath((const xmlChar *) filename);
-	if (inputStream->filename == NULL) {
-            xmlFreeInputStream(inputStream);
-	    xmlFreeParserCtxt(ctxt);
-	    xmlFreeParserInputBuffer(buf);
-	    return(NULL);
-	}
-    }
-    inputStream->buf = buf;
-    xmlBufResetInput(inputStream->buf->buffer, inputStream);
-    inputPush(ctxt, inputStream);
-
-    if ((size != 0) && (chunk != NULL) &&
-        (ctxt->input != NULL) && (ctxt->input->buf != NULL)) {
-	size_t pos = ctxt->input->cur - ctxt->input->base;
-        int res;
-
-	res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
-        xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos);
-        if (res < 0) {
-            xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
-            xmlHaltParser(ctxt);
-        }
-    }
+    inputPush(ctxt, input);
 
     return(ctxt);
 }
@@ -12132,12 +11713,14 @@
 
 /**
  * xmlCreateIOParserCtxt:
- * @sax:  a SAX handler
- * @user_data:  The user data returned on SAX callbacks
+ * @sax:  a SAX handler (optional)
+ * @user_data:  user data for SAX callbacks (optional)
  * @ioread:  an I/O read function
- * @ioclose:  an I/O close function
+ * @ioclose:  an I/O close function (optional)
  * @ioctx:  an I/O handler
- * @enc:  the charset encoding if known
+ * @enc:  the charset encoding if known (deprecated)
+ *
+ * DEPRECATED: Use xmlNewParserCtxt and xmlCtxtReadIO.
  *
  * Create a parser context for using the XML parser with an existing
  * I/O stream
@@ -12146,33 +11729,24 @@
  */
 xmlParserCtxtPtr
 xmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
-	xmlInputReadCallback   ioread, xmlInputCloseCallback  ioclose,
-	void *ioctx, xmlCharEncoding enc) {
+                      xmlInputReadCallback ioread,
+                      xmlInputCloseCallback ioclose,
+                      void *ioctx, xmlCharEncoding enc) {
     xmlParserCtxtPtr ctxt;
-    xmlParserInputPtr inputStream;
-    xmlParserInputBufferPtr buf;
-
-    if (ioread == NULL) return(NULL);
-
-    buf = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, enc);
-    if (buf == NULL) {
-        if (ioclose != NULL)
-            ioclose(ioctx);
-        return (NULL);
-    }
+    xmlParserInputPtr input;
+    const char *encoding;
 
     ctxt = xmlNewSAXParserCtxt(sax, user_data);
-    if (ctxt == NULL) {
-	xmlFreeParserInputBuffer(buf);
+    if (ctxt == NULL)
 	return(NULL);
-    }
 
-    inputStream = xmlNewIOInputStream(ctxt, buf, enc);
-    if (inputStream == NULL) {
+    encoding = xmlGetCharEncodingName(enc);
+    input = xmlNewInputIO(ctxt, NULL, ioread, ioclose, ioctx, encoding, 0);
+    if (input == NULL) {
 	xmlFreeParserCtxt(ctxt);
-	return(NULL);
+        return (NULL);
     }
-    inputPush(ctxt, inputStream);
+    inputPush(ctxt, input);
 
     return(ctxt);
 }
@@ -12212,11 +11786,6 @@
 	return(NULL);
     }
 
-    /* We are loading a DTD */
-    ctxt->options |= XML_PARSE_DTDLOAD;
-
-    xmlDetectSAX2(ctxt);
-
     /*
      * generate a parser input from the I/O handler
      */
@@ -12242,18 +11811,15 @@
     /*
      * let's parse that entity knowing it's an external subset.
      */
-    ctxt->inSubset = 2;
     ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
     if (ctxt->myDoc == NULL) {
-	xmlErrMemory(ctxt, "New Doc failed");
+	xmlErrMemory(ctxt);
 	return(NULL);
     }
     ctxt->myDoc->properties = XML_DOC_INTERNAL;
     ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none",
 	                               BAD_CAST "none", BAD_CAST "none");
 
-    xmlDetectEncoding(ctxt);
-
     xmlParseExternalSubset(ctxt, BAD_CAST "none", BAD_CAST "none");
 
     if (ctxt->myDoc != NULL) {
@@ -12309,9 +11875,6 @@
 	return(NULL);
     }
 
-    /* We are loading a DTD */
-    ctxt->options |= XML_PARSE_DTDLOAD;
-
     /*
      * Canonicalise the system ID
      */
@@ -12355,10 +11918,9 @@
     /*
      * let's parse that entity knowing it's an external subset.
      */
-    ctxt->inSubset = 2;
     ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
     if (ctxt->myDoc == NULL) {
-	xmlErrMemory(ctxt, "New Doc failed");
+	xmlErrMemory(ctxt);
 	xmlFreeParserCtxt(ctxt);
 	return(NULL);
     }
@@ -12420,6 +11982,203 @@
  *									*
  ************************************************************************/
 
+static xmlNodePtr
+xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
+                    int hasTextDecl, int buildTree) {
+    xmlNodePtr root = NULL;
+    xmlNodePtr list = NULL;
+    xmlChar *rootName = BAD_CAST "#root";
+    int result;
+
+    if (buildTree) {
+        root = xmlNewDocNode(ctxt->myDoc, NULL, rootName, NULL);
+        if (root == NULL) {
+            xmlErrMemory(ctxt);
+            goto error;
+        }
+    }
+
+    if (xmlPushInput(ctxt, input) < 0)
+        goto error;
+
+    nameNsPush(ctxt, rootName, NULL, NULL, 0, 0);
+    spacePush(ctxt, -1);
+
+    if (buildTree)
+        nodePush(ctxt, root);
+
+    if (hasTextDecl) {
+        xmlDetectEncoding(ctxt);
+
+        /*
+         * Parse a possible text declaration first
+         */
+        if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) &&
+            (IS_BLANK_CH(NXT(5)))) {
+            xmlParseTextDecl(ctxt);
+            /*
+             * An XML-1.0 document can't reference an entity not XML-1.0
+             */
+            if ((xmlStrEqual(ctxt->version, BAD_CAST "1.0")) &&
+                (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) {
+                xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH,
+                               "Version mismatch between document and "
+                               "entity\n");
+            }
+        }
+    }
+
+    xmlParseContentInternal(ctxt);
+
+    if (ctxt->input->cur < ctxt->input->end)
+	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
+
+    if ((ctxt->wellFormed) ||
+        ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) {
+        if (root != NULL) {
+            xmlNodePtr cur;
+
+            /*
+             * Return the newly created nodeset after unlinking it from
+             * its pseudo parent.
+             */
+            cur = root->children;
+            list = cur;
+            while (cur != NULL) {
+                cur->parent = NULL;
+                cur = cur->next;
+            }
+            root->children = NULL;
+            root->last = NULL;
+        }
+    }
+
+    /*
+     * Read the rest of the stream in case of errors. We want
+     * to account for the whole entity size.
+     */
+    do {
+        ctxt->input->cur = ctxt->input->end;
+        xmlParserShrink(ctxt);
+        result = xmlParserGrow(ctxt);
+    } while (result > 0);
+
+    if (buildTree)
+        nodePop(ctxt);
+
+    namePop(ctxt);
+    spacePop(ctxt);
+
+    /* xmlPopInput would free the stream */
+    inputPop(ctxt);
+
+error:
+    xmlFreeNode(root);
+
+    return(list);
+}
+
+static void
+xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) {
+    xmlParserInputPtr input;
+    xmlNodePtr list;
+    unsigned long consumed;
+    int isExternal;
+    int buildTree;
+    int oldMinNsIndex;
+    int oldNodelen, oldNodemem;
+
+    isExternal = (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY);
+    buildTree = (ctxt->node != NULL);
+
+    /*
+     * Recursion check
+     */
+    if (ent->flags & XML_ENT_EXPANDING) {
+        xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);
+        xmlHaltParser(ctxt);
+        goto error;
+    }
+
+    /*
+     * Load entity
+     */
+    input = xmlNewEntityInputStream(ctxt, ent);
+    if (input == NULL)
+        goto error;
+
+    /*
+     * When building a tree, we need to limit the scope of namespace
+     * declarations, so that entities don't reference xmlNs structs
+     * from the parent of a reference.
+     */
+    oldMinNsIndex = ctxt->nsdb->minNsIndex;
+    if (buildTree)
+        ctxt->nsdb->minNsIndex = ctxt->nsNr;
+
+    oldNodelen = ctxt->nodelen;
+    oldNodemem = ctxt->nodemem;
+    ctxt->nodelen = 0;
+    ctxt->nodemem = 0;
+
+    /*
+     * Parse content
+     *
+     * This initiates a recursive call chain:
+     *
+     * - xmlCtxtParseContent
+     * - xmlParseContentInternal
+     * - xmlParseReference
+     * - xmlCtxtParseEntity
+     *
+     * The nesting depth is limited by the maximum number of inputs,
+     * see xmlPushInput.
+     *
+     * It's possible to make this non-recursive (minNsIndex must be
+     * stored in the input struct) at the expense of code readability.
+     */
+
+    ent->flags |= XML_ENT_EXPANDING;
+
+    list = xmlCtxtParseContent(ctxt, input, isExternal, buildTree);
+
+    ent->flags &= ~XML_ENT_EXPANDING;
+
+    ctxt->nsdb->minNsIndex = oldMinNsIndex;
+    ctxt->nodelen = oldNodelen;
+    ctxt->nodemem = oldNodemem;
+
+    /*
+     * Entity size accounting
+     */
+    consumed = input->consumed;
+    xmlSaturatedAddSizeT(&consumed, input->end - input->base);
+
+    if ((ent->flags & XML_ENT_CHECKED) == 0)
+        xmlSaturatedAdd(&ent->expandedSize, consumed);
+
+    if ((ent->flags & XML_ENT_PARSED) == 0) {
+        if (isExternal)
+            xmlSaturatedAdd(&ctxt->sizeentities, consumed);
+
+        ent->children = list;
+
+        while (list != NULL) {
+            list->parent = (xmlNodePtr) ent;
+            if (list->next == NULL)
+                ent->last = list;
+            list = list->next;
+        }
+    } else {
+        xmlFreeNodeList(list);
+    }
+
+    xmlFreeInputStream(input);
+
+error:
+    ent->flags |= XML_ENT_PARSED | XML_ENT_CHECKED;
+}
+
 /**
  * xmlParseCtxtExternalEntity:
  * @ctx:  the existing parsing context
@@ -12438,250 +12197,31 @@
  */
 
 int
-xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL,
-	               const xmlChar *ID, xmlNodePtr *lst) {
-    void *userData;
+xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctxt, const xmlChar *URL,
+                           const xmlChar *ID, xmlNodePtr *listOut) {
+    xmlParserInputPtr input;
+    xmlNodePtr list;
 
-    if (ctx == NULL) return(-1);
-    /*
-     * If the user provided their own SAX callbacks, then reuse the
-     * userData callback field, otherwise the expected setup in a
-     * DOM builder is to have userData == ctxt
-     */
-    if (ctx->userData == ctx)
-        userData = NULL;
-    else
-        userData = ctx->userData;
-    return xmlParseExternalEntityPrivate(ctx->myDoc, ctx, ctx->sax,
-                                         userData, ctx->depth + 1,
-                                         URL, ID, lst);
-}
+    if (listOut != NULL)
+        *listOut = NULL;
 
-/**
- * xmlParseExternalEntityPrivate:
- * @doc:  the document the chunk pertains to
- * @oldctxt:  the previous parser context if available
- * @sax:  the SAX handler block (possibly NULL)
- * @user_data:  The user data returned on SAX callbacks (possibly NULL)
- * @depth:  Used for loop detection, use 0
- * @URL:  the URL for the entity to load
- * @ID:  the System ID for the entity to load
- * @list:  the return value for the set of parsed nodes
- *
- * Private version of xmlParseExternalEntity()
- *
- * Returns 0 if the entity is well formed, -1 in case of args problem and
- *    the parser error code otherwise
- */
-
-static xmlParserErrors
-xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
-	              xmlSAXHandlerPtr sax,
-		      void *user_data, int depth, const xmlChar *URL,
-		      const xmlChar *ID, xmlNodePtr *list) {
-    xmlParserCtxtPtr ctxt;
-    xmlDocPtr newDoc;
-    xmlNodePtr newRoot;
-    xmlParserErrors ret = XML_ERR_OK;
-
-    if (((depth > 40) &&
-	((oldctxt == NULL) || (oldctxt->options & XML_PARSE_HUGE) == 0)) ||
-	(depth > 100)) {
-        if (oldctxt != NULL)
-            xmlFatalErrMsg(oldctxt, XML_ERR_ENTITY_LOOP,
-                           "Maximum entity nesting depth exceeded");
-        return(XML_ERR_ENTITY_LOOP);
-    }
-
-    if (list != NULL)
-        *list = NULL;
-    if ((URL == NULL) && (ID == NULL))
-	return(XML_ERR_INTERNAL_ERROR);
-    if (doc == NULL)
-	return(XML_ERR_INTERNAL_ERROR);
-
-    ctxt = xmlCreateEntityParserCtxtInternal(sax, user_data, URL, ID, NULL,
-                                             oldctxt);
     if (ctxt == NULL)
-        return(oldctxt ? oldctxt->errNo : XML_ERR_INTERNAL_ERROR);
-    if (oldctxt != NULL) {
-        ctxt->nbErrors = oldctxt->nbErrors;
-        ctxt->nbWarnings = oldctxt->nbWarnings;
-    }
-    xmlDetectSAX2(ctxt);
+        return(XML_ERR_ARGUMENT);
 
-    newDoc = xmlNewDoc(BAD_CAST "1.0");
-    if (newDoc == NULL) {
-        xmlErrMemory(oldctxt, NULL);
-        goto error;
-    }
-    newDoc->properties = XML_DOC_INTERNAL;
-    if (doc) {
-        newDoc->intSubset = doc->intSubset;
-        newDoc->extSubset = doc->extSubset;
-        if (doc->dict) {
-            newDoc->dict = doc->dict;
-            xmlDictReference(newDoc->dict);
-        }
-        if (doc->URL != NULL) {
-            newDoc->URL = xmlStrdup(doc->URL);
-            if (newDoc->URL == NULL) {
-                xmlErrMemory(oldctxt, NULL);
-                goto error;
-            }
-        }
-    }
-    newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL);
-    if (newRoot == NULL) {
-        xmlErrMemory(oldctxt, NULL);
-        goto error;
-    }
-    xmlAddChild((xmlNodePtr) newDoc, newRoot);
-    nodePush(ctxt, newDoc->children);
-    if (doc == NULL) {
-        ctxt->myDoc = newDoc;
-    } else {
-        ctxt->myDoc = doc;
-        newRoot->doc = doc;
-    }
+    input = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt);
+    if (input == NULL)
+        return(ctxt->errNo);
 
-    xmlDetectEncoding(ctxt);
+    xmlCtxtInitializeLate(ctxt);
 
-    /*
-     * Parse a possible text declaration first
-     */
-    if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) {
-	xmlParseTextDecl(ctxt);
-        /*
-         * An XML-1.0 document can't reference an entity not XML-1.0
-         */
-        if ((xmlStrEqual(oldctxt->version, BAD_CAST "1.0")) &&
-            (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) {
-            xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH,
-                           "Version mismatch between document and entity\n");
-        }
-    }
+    list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 1, 1);
+    if (*listOut != NULL)
+        *listOut = list;
+    else
+        xmlFreeNodeList(list);
 
-    ctxt->instate = XML_PARSER_CONTENT;
-    ctxt->depth = depth;
-    if (oldctxt != NULL) {
-	ctxt->_private = oldctxt->_private;
-	ctxt->loadsubset = oldctxt->loadsubset;
-	ctxt->validate = oldctxt->validate;
-	ctxt->valid = oldctxt->valid;
-	ctxt->replaceEntities = oldctxt->replaceEntities;
-        if (oldctxt->validate) {
-            ctxt->vctxt.error = oldctxt->vctxt.error;
-            ctxt->vctxt.warning = oldctxt->vctxt.warning;
-            ctxt->vctxt.userData = ctxt;
-            ctxt->vctxt.flags = oldctxt->vctxt.flags;
-        }
-	ctxt->external = oldctxt->external;
-        if (ctxt->dict) xmlDictFree(ctxt->dict);
-        ctxt->dict = oldctxt->dict;
-        ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3);
-        ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5);
-        ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36);
-        ctxt->dictNames = oldctxt->dictNames;
-        ctxt->attsDefault = oldctxt->attsDefault;
-        ctxt->attsSpecial = oldctxt->attsSpecial;
-        ctxt->linenumbers = oldctxt->linenumbers;
-	ctxt->record_info = oldctxt->record_info;
-	ctxt->node_seq.maximum = oldctxt->node_seq.maximum;
-	ctxt->node_seq.length = oldctxt->node_seq.length;
-	ctxt->node_seq.buffer = oldctxt->node_seq.buffer;
-    } else {
-	/*
-	 * Doing validity checking on chunk without context
-	 * doesn't make sense
-	 */
-	ctxt->_private = NULL;
-	ctxt->validate = 0;
-	ctxt->external = 2;
-	ctxt->loadsubset = 0;
-    }
-
-    xmlParseContent(ctxt);
-
-    if ((RAW == '<') && (NXT(1) == '/')) {
-	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
-    } else if (RAW != 0) {
-	xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL);
-    }
-    if (ctxt->node != newDoc->children) {
-	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
-    }
-
-    if (ctxt->wellFormed) {
-	if (list != NULL) {
-	    xmlNodePtr cur;
-
-	    /*
-	     * Return the newly created nodeset after unlinking it from
-	     * they pseudo parent.
-	     */
-	    cur = newDoc->children->children;
-	    *list = cur;
-	    while (cur != NULL) {
-		cur->parent = NULL;
-		cur = cur->next;
-	    }
-            newDoc->children->children = NULL;
-	}
-	ctxt->errNo = XML_ERR_OK;
-    }
-
-    /*
-     * Also record the size of the entity parsed
-     */
-    if (ctxt->input != NULL && oldctxt != NULL) {
-        unsigned long consumed = ctxt->input->consumed;
-
-        xmlSaturatedAddSizeT(&consumed, ctxt->input->cur - ctxt->input->base);
-
-        xmlSaturatedAdd(&oldctxt->sizeentities, consumed);
-        xmlSaturatedAdd(&oldctxt->sizeentities, ctxt->sizeentities);
-
-        xmlSaturatedAdd(&oldctxt->sizeentcopy, consumed);
-        xmlSaturatedAdd(&oldctxt->sizeentcopy, ctxt->sizeentcopy);
-    }
-
-    if (oldctxt != NULL) {
-        ctxt->dict = NULL;
-        ctxt->attsDefault = NULL;
-        ctxt->attsSpecial = NULL;
-        oldctxt->nbErrors = ctxt->nbErrors;
-        oldctxt->nbWarnings = ctxt->nbWarnings;
-        oldctxt->validate = ctxt->validate;
-        oldctxt->valid = ctxt->valid;
-        oldctxt->node_seq.maximum = ctxt->node_seq.maximum;
-        oldctxt->node_seq.length = ctxt->node_seq.length;
-        oldctxt->node_seq.buffer = ctxt->node_seq.buffer;
-    }
-    ctxt->node_seq.maximum = 0;
-    ctxt->node_seq.length = 0;
-    ctxt->node_seq.buffer = NULL;
-
-error:
-    if ((oldctxt != NULL) && (ctxt->errNo != 0)) {
-        oldctxt->errNo = ctxt->errNo;
-        oldctxt->wellFormed = ctxt->wellFormed;
-        if (ctxt->disableSAX > oldctxt->disableSAX)
-            oldctxt->disableSAX = ctxt->disableSAX;
-        if (xmlCopyError(&ctxt->lastError, &oldctxt->lastError) < 0) {
-            xmlErrMemory(oldctxt, NULL);
-        }
-    }
-
-    ret = ctxt->errNo;
-    xmlFreeParserCtxt(ctxt);
-    if (newDoc != NULL) {
-        newDoc->intSubset = NULL;
-        newDoc->extSubset = NULL;
-        xmlFreeDoc(newDoc);
-    }
-
-    return(ret);
+    xmlFreeInputStream(input);
+    return(ctxt->errNo);
 }
 
 #ifdef LIBXML_SAX1_ENABLED
@@ -12707,9 +12247,26 @@
 
 int
 xmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data,
-	  int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *lst) {
-    return(xmlParseExternalEntityPrivate(doc, NULL, sax, user_data, depth, URL,
-		                       ID, lst));
+	  int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *list) {
+    xmlParserCtxtPtr ctxt;
+    int ret;
+
+    if (list != NULL)
+        *list = NULL;
+
+    if (doc == NULL)
+        return(XML_ERR_ARGUMENT);
+
+    ctxt = xmlNewSAXParserCtxt(sax, user_data);
+    if (ctxt == NULL)
+        return(XML_ERR_NO_MEMORY);
+
+    ctxt->depth = depth;
+    ctxt->myDoc = doc;
+    ret = xmlParseCtxtExternalEntity(ctxt, URL, ID, list);
+
+    xmlFreeParserCtxt(ctxt);
+    return(ret);
 }
 
 /**
@@ -12741,243 +12298,6 @@
 #endif /* LIBXML_SAX1_ENABLED */
 
 /**
- * xmlParseBalancedChunkMemoryInternal:
- * @oldctxt:  the existing parsing context
- * @string:  the input string in UTF8 or ISO-Latin (zero terminated)
- * @user_data:  the user data field for the parser context
- * @lst:  the return value for the set of parsed nodes
- *
- *
- * Parse a well-balanced chunk of an XML document
- * called by the parser
- * The allowed sequence for the Well Balanced Chunk is the one defined by
- * the content production in the XML grammar:
- *
- * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
- *
- * Returns XML_ERR_OK if the chunk is well balanced, and the parser
- * error code otherwise
- *
- * In case recover is set to 1, the nodelist will not be empty even if
- * the parsed chunk is not well balanced.
- */
-static xmlParserErrors
-xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt,
-	const xmlChar *string, void *user_data, xmlNodePtr *lst) {
-    xmlParserCtxtPtr ctxt;
-    xmlDocPtr newDoc = NULL;
-    xmlNodePtr newRoot;
-    xmlSAXHandlerPtr oldsax = NULL;
-    xmlNodePtr content = NULL;
-    xmlNodePtr last = NULL;
-    xmlParserErrors ret = XML_ERR_OK;
-    xmlHashedString hprefix, huri;
-    unsigned i;
-
-    if (((oldctxt->depth > 40) && ((oldctxt->options & XML_PARSE_HUGE) == 0)) ||
-        (oldctxt->depth >  100)) {
-	xmlFatalErrMsg(oldctxt, XML_ERR_ENTITY_LOOP,
-                       "Maximum entity nesting depth exceeded");
-	return(XML_ERR_ENTITY_LOOP);
-    }
-
-
-    if (lst != NULL)
-        *lst = NULL;
-    if (string == NULL)
-        return(XML_ERR_INTERNAL_ERROR);
-
-    ctxt = xmlCreateDocParserCtxt(string);
-    if (ctxt == NULL) {
-        xmlErrMemory(oldctxt, NULL);
-        return(XML_ERR_NO_MEMORY);
-    }
-
-    if (oldctxt->myDoc == NULL) {
-	newDoc = xmlNewDoc(BAD_CAST "1.0");
-	if (newDoc == NULL) {
-            xmlErrMemory(oldctxt, NULL);
-            ret = XML_ERR_NO_MEMORY;
-            goto error;
-	}
-	newDoc->properties = XML_DOC_INTERNAL;
-	newDoc->dict = ctxt->dict;
-	xmlDictReference(newDoc->dict);
-	ctxt->myDoc = newDoc;
-    } else {
-	ctxt->myDoc = oldctxt->myDoc;
-        content = ctxt->myDoc->children;
-	last = ctxt->myDoc->last;
-    }
-    newRoot = xmlNewDocNode(ctxt->myDoc, NULL, BAD_CAST "pseudoroot", NULL);
-    if (newRoot == NULL) {
-        xmlErrMemory(oldctxt, NULL);
-        ret = XML_ERR_NO_MEMORY;
-        goto error;
-    }
-    ctxt->myDoc->children = NULL;
-    ctxt->myDoc->last = NULL;
-    xmlAddChild((xmlNodePtr) ctxt->myDoc, newRoot);
-    nodePush(ctxt, ctxt->myDoc->children);
-
-    ctxt->nbErrors = oldctxt->nbErrors;
-    ctxt->nbWarnings = oldctxt->nbWarnings;
-    if (user_data != NULL)
-	ctxt->userData = user_data;
-    else
-	ctxt->userData = ctxt;
-    if (ctxt->dict != NULL) xmlDictFree(ctxt->dict);
-    ctxt->dict = oldctxt->dict;
-    ctxt->input_id = oldctxt->input_id;
-    /* TODO: check malloc */
-    ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3);
-    ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5);
-    ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36);
-
-    /*
-     * Propagate namespaces down the entity
-     *
-     * Making entities and namespaces work correctly requires additional
-     * changes, see xmlParseReference.
-     */
-
-    /* Default namespace */
-    hprefix.name = NULL;
-    hprefix.hashValue = 0;
-    huri.name = xmlParserNsLookupUri(oldctxt, &hprefix);
-    huri.hashValue = 0;
-    if (huri.name != NULL)
-        xmlParserNsPush(ctxt, NULL, &huri, NULL, 0);
-
-    for (i = 0; i < oldctxt->nsdb->hashSize; i++) {
-        xmlParserNsBucket *bucket = &oldctxt->nsdb->hash[i];
-        const xmlChar **ns;
-        xmlParserNsExtra *extra;
-        unsigned nsIndex;
-
-        if ((bucket->hashValue != 0) &&
-            (bucket->index != INT_MAX)) {
-            nsIndex = bucket->index;
-            ns = &oldctxt->nsTab[nsIndex * 2];
-            extra = &oldctxt->nsdb->extra[nsIndex];
-
-            hprefix.name = ns[0];
-            hprefix.hashValue = bucket->hashValue;
-            huri.name = ns[1];
-            huri.hashValue = extra->uriHashValue;
-            /*
-             * Don't copy SAX data to avoid a use-after-free with XML reader.
-             * This matches the pre-2.12 behavior.
-             */
-            xmlParserNsPush(ctxt, &hprefix, &huri, NULL, 0);
-        }
-    }
-
-    oldsax = ctxt->sax;
-    ctxt->sax = oldctxt->sax;
-    xmlDetectSAX2(ctxt);
-    ctxt->replaceEntities = oldctxt->replaceEntities;
-    ctxt->options = oldctxt->options;
-
-    ctxt->_private = oldctxt->_private;
-    ctxt->instate = XML_PARSER_CONTENT;
-    ctxt->depth = oldctxt->depth;
-
-    ctxt->validate = 0;
-    ctxt->loadsubset = oldctxt->loadsubset;
-    if ((oldctxt->validate) || (oldctxt->replaceEntities != 0)) {
-	/*
-	 * ID/IDREF registration will be done in xmlValidateElement below
-	 */
-	ctxt->loadsubset |= XML_SKIP_IDS;
-    }
-    ctxt->dictNames = oldctxt->dictNames;
-    ctxt->attsDefault = oldctxt->attsDefault;
-    ctxt->attsSpecial = oldctxt->attsSpecial;
-
-    xmlParseContent(ctxt);
-    if ((RAW == '<') && (NXT(1) == '/')) {
-	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
-    } else if (RAW != 0) {
-	xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL);
-    }
-    if (ctxt->node != ctxt->myDoc->children) {
-	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
-    }
-
-    if (!ctxt->wellFormed) {
-	ret = (xmlParserErrors)ctxt->errNo;
-        oldctxt->errNo = ctxt->errNo;
-        oldctxt->wellFormed = 0;
-        if (ctxt->disableSAX > oldctxt->disableSAX)
-            oldctxt->disableSAX = ctxt->disableSAX;
-        if (xmlCopyError(&ctxt->lastError, &oldctxt->lastError) < 0) {
-            xmlErrMemory(oldctxt, NULL);
-            ret = XML_ERR_NO_MEMORY;
-        }
-    } else {
-        ret = XML_ERR_OK;
-    }
-
-    if ((lst != NULL) && (ret == XML_ERR_OK)) {
-	xmlNodePtr cur;
-
-	/*
-	 * Return the newly created nodeset after unlinking it from
-	 * they pseudo parent.
-	 */
-	cur = ctxt->myDoc->children->children;
-	*lst = cur;
-	while (cur != NULL) {
-#ifdef LIBXML_VALID_ENABLED
-	    if ((oldctxt->validate) && (oldctxt->wellFormed) &&
-		(oldctxt->myDoc) && (oldctxt->myDoc->intSubset) &&
-		(cur->type == XML_ELEMENT_NODE)) {
-		oldctxt->valid &= xmlValidateElement(&oldctxt->vctxt,
-			oldctxt->myDoc, cur);
-	    }
-#endif /* LIBXML_VALID_ENABLED */
-	    cur->parent = NULL;
-	    cur = cur->next;
-	}
-	ctxt->myDoc->children->children = NULL;
-    }
-    if (ctxt->myDoc != NULL) {
-	xmlFreeNode(ctxt->myDoc->children);
-        ctxt->myDoc->children = content;
-        ctxt->myDoc->last = last;
-    }
-
-    /*
-     * Also record the size of the entity parsed
-     */
-    if (ctxt->input != NULL && oldctxt != NULL) {
-        unsigned long consumed = ctxt->input->consumed;
-
-        xmlSaturatedAddSizeT(&consumed, ctxt->input->cur - ctxt->input->base);
-
-        xmlSaturatedAdd(&oldctxt->sizeentcopy, consumed);
-        xmlSaturatedAdd(&oldctxt->sizeentcopy, ctxt->sizeentcopy);
-    }
-
-    oldctxt->nbErrors = ctxt->nbErrors;
-    oldctxt->nbWarnings = ctxt->nbWarnings;
-
-    ctxt->sax = oldsax;
-    ctxt->dict = NULL;
-    ctxt->attsDefault = NULL;
-    ctxt->attsSpecial = NULL;
-
-error:
-    xmlFreeParserCtxt(ctxt);
-    if (newDoc != NULL) {
-	xmlFreeDoc(newDoc);
-    }
-
-    return(ret);
-}
-
-/**
  * xmlParseInNodeContext:
  * @node:  the context node
  * @data:  the input string
@@ -13010,7 +12330,7 @@
      * check all input parameters, grab the document
      */
     if ((lst == NULL) || (node == NULL) || (data == NULL) || (datalen < 0))
-        return(XML_ERR_INTERNAL_ERROR);
+        return(XML_ERR_ARGUMENT);
     switch (node->type) {
         case XML_ELEMENT_NODE:
         case XML_ATTRIBUTE_NODE:
@@ -13063,25 +12383,30 @@
 
     /*
      * Use input doc's dict if present, else assure XML_PARSE_NODICT is set.
-     * We need a dictionary for xmlDetectSAX2, so if there's no doc dict
+     * We need a dictionary for xmlCtxtInitializeLate, so if there's no doc dict
      * we must wait until the last moment to free the original one.
      */
     if (doc->dict != NULL) {
         if (ctxt->dict != NULL)
 	    xmlDictFree(ctxt->dict);
 	ctxt->dict = doc->dict;
-    } else
+    } else {
         options |= XML_PARSE_NODICT;
+        ctxt->dictNames = 0;
+    }
 
     if (doc->encoding != NULL)
         xmlSwitchEncodingName(ctxt, (const char *) doc->encoding);
 
-    xmlCtxtUseOptionsInternal(ctxt, options, NULL);
-    xmlDetectSAX2(ctxt);
+    xmlCtxtUseOptions(ctxt, options);
+    xmlCtxtInitializeLate(ctxt);
     ctxt->myDoc = doc;
     /* parsing in context, i.e. as within existing content */
     ctxt->input_id = 2;
-    ctxt->instate = XML_PARSER_CONTENT;
+
+    /*
+     * TODO: Use xmlCtxtParseContent
+     */
 
     fake = xmlNewDocComment(node->doc, NULL);
     if (fake == NULL) {
@@ -13090,8 +12415,10 @@
     }
     xmlAddChild(node, fake);
 
-    if (node->type == XML_ELEMENT_NODE) {
+    if (node->type == XML_ELEMENT_NODE)
 	nodePush(ctxt, node);
+
+    if ((ctxt->html == 0) && (node->type == XML_ELEMENT_NODE)) {
 	/*
 	 * initialize the SAX2 namespaces stack
 	 */
@@ -13123,26 +12450,18 @@
         __htmlParseContent(ctxt);
     else
 #endif
-	xmlParseContent(ctxt);
+	xmlParseContentInternal(ctxt);
+
+    if (ctxt->input->cur < ctxt->input->end)
+	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
 
     xmlParserNsPop(ctxt, nsnr);
-    if ((RAW == '<') && (NXT(1) == '/')) {
-	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
-    } else if (RAW != 0) {
-	xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL);
-    }
-    if ((ctxt->node != NULL) && (ctxt->node != node)) {
-	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
-	ctxt->wellFormed = 0;
-    }
 
-    if (!ctxt->wellFormed) {
-        if (ctxt->errNo == 0)
-	    ret = XML_ERR_INTERNAL_ERROR;
-	else
-	    ret = (xmlParserErrors)ctxt->errNo;
-    } else {
+    if ((ctxt->wellFormed) ||
+        ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) {
         ret = XML_ERR_OK;
+    } else {
+	ret = (xmlParserErrors) ctxt->errNo;
     }
 
     /*
@@ -13189,19 +12508,18 @@
  * @user_data:  The user data returned on SAX callbacks (possibly NULL)
  * @depth:  Used for loop detection, use 0
  * @string:  the input string in UTF8 or ISO-Latin (zero terminated)
- * @lst:  the return value for the set of parsed nodes
+ * @list:  the return value for the set of parsed nodes
  * @recover: return nodes even if the data is broken (use 0)
  *
- *
  * Parse a well-balanced chunk of an XML document
- * called by the parser
+ *
  * The allowed sequence for the Well Balanced Chunk is the one defined by
  * the content production in the XML grammar:
  *
  * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
  *
- * Returns 0 if the chunk is well balanced, -1 in case of args problem and
- *    the parser error code otherwise
+ * Returns 0 if the chunk is well balanced, or thehe parser error code
+ * otherwise.
  *
  * In case recover is set to 1, the nodelist will not be empty even if
  * the parsed chunk is not well balanced, assuming the parsing succeeded to
@@ -13209,142 +12527,46 @@
  */
 int
 xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax,
-     void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst,
+     void *user_data, int depth, const xmlChar *string, xmlNodePtr *listOut,
      int recover) {
     xmlParserCtxtPtr ctxt;
-    xmlDocPtr newDoc;
-    xmlSAXHandlerPtr oldsax = NULL;
-    xmlNodePtr content, newRoot;
-    int ret = 0;
+    xmlParserInputPtr input;
+    xmlNodePtr list;
+    int ret;
 
-    if (depth > 40) {
-	return(XML_ERR_ENTITY_LOOP);
-    }
+    if (listOut != NULL)
+        *listOut = NULL;
 
-
-    if (lst != NULL)
-        *lst = NULL;
     if (string == NULL)
-        return(-1);
+        return(XML_ERR_ARGUMENT);
 
-    ctxt = xmlCreateDocParserCtxt(string);
-    if (ctxt == NULL) return(-1);
-    ctxt->userData = ctxt;
-    if (sax != NULL) {
-	oldsax = ctxt->sax;
-        ctxt->sax = sax;
-	if (user_data != NULL)
-	    ctxt->userData = user_data;
-    }
-    newDoc = xmlNewDoc(BAD_CAST "1.0");
-    if (newDoc == NULL) {
-	xmlFreeParserCtxt(ctxt);
-	return(-1);
-    }
-    newDoc->properties = XML_DOC_INTERNAL;
-    if ((doc != NULL) && (doc->dict != NULL)) {
-        xmlDictFree(ctxt->dict);
-	ctxt->dict = doc->dict;
-	xmlDictReference(ctxt->dict);
-	ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3);
-	ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5);
-	ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36);
-	ctxt->dictNames = 1;
-        newDoc->dict = ctxt->dict;
-        xmlDictReference(newDoc->dict);
-    } 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;
-    }
-    newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL);
-    if (newRoot == NULL) {
-	if (sax != NULL)
-	    ctxt->sax = oldsax;
-	xmlFreeParserCtxt(ctxt);
-	newDoc->intSubset = NULL;
-	newDoc->extSubset = NULL;
-        xmlFreeDoc(newDoc);
-	return(-1);
-    }
-    xmlAddChild((xmlNodePtr) newDoc, newRoot);
-    nodePush(ctxt, newRoot);
-    /* doc == NULL is only supported for historic reasons */
-    if (doc == NULL) {
-	ctxt->myDoc = newDoc;
-    } else {
-	ctxt->myDoc = newDoc;
-	/* Ensure that doc has XML spec namespace */
-	xmlSearchNsByHref(doc, (xmlNodePtr)doc, XML_XML_NAMESPACE);
-	newDoc->oldNs = doc->oldNs;
-    }
-    ctxt->instate = XML_PARSER_CONTENT;
-    ctxt->input_id = 2;
+    ctxt = xmlNewSAXParserCtxt(sax, user_data);
+    if (ctxt == NULL)
+        return(XML_ERR_NO_MEMORY);
+
+    xmlCtxtInitializeLate(ctxt);
+
     ctxt->depth = depth;
-
-    /*
-     * Doing validity checking on chunk doesn't make sense
-     */
-    ctxt->validate = 0;
-    ctxt->loadsubset = 0;
-    xmlDetectSAX2(ctxt);
-
-    if ( doc != NULL ){
-        content = doc->children;
-        doc->children = NULL;
-        xmlParseContent(ctxt);
-        doc->children = content;
-    }
-    else {
-        xmlParseContent(ctxt);
-    }
-    if ((RAW == '<') && (NXT(1) == '/')) {
-	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
-    } else if (RAW != 0) {
-	xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL);
-    }
-    if (ctxt->node != newDoc->children) {
-	xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
+    ctxt->myDoc = doc;
+    if (recover) {
+        ctxt->options |= XML_PARSE_RECOVER;
+        ctxt->recovery = 1;
     }
 
-    if (!ctxt->wellFormed) {
-        if (ctxt->errNo == 0)
-	    ret = 1;
-	else
-	    ret = ctxt->errNo;
-    } else {
-      ret = 0;
-    }
+    input = xmlNewStringInputStream(ctxt, string);
+    if (input == NULL)
+        return(ctxt->errNo);
 
-    if ((lst != NULL) && ((ret == 0) || (recover == 1))) {
-	xmlNodePtr cur;
+    list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 0, 1);
+    if (listOut != NULL)
+        *listOut = list;
+    else
+        xmlFreeNodeList(list);
 
-	/*
-	 * Return the newly created nodeset after unlinking it from
-	 * they pseudo parent.
-	 */
-	cur = newDoc->children->children;
-	*lst = cur;
-	while (cur != NULL) {
-	    xmlSetTreeDoc(cur, doc);
-	    cur->parent = NULL;
-	    cur = cur->next;
-	}
-	newDoc->children->children = NULL;
-    }
+    ret = ctxt->errNo;
 
-    if (sax != NULL)
-	ctxt->sax = oldsax;
+    xmlFreeInputStream(input);
     xmlFreeParserCtxt(ctxt);
-    newDoc->intSubset = NULL;
-    newDoc->extSubset = NULL;
-    /* This leaks the namespace list if doc == NULL */
-    newDoc->oldNs = NULL;
-    xmlFreeDoc(newDoc);
-
     return(ret);
 }
 
@@ -13376,23 +12598,24 @@
 	return(NULL);
     }
     if (sax != NULL) {
-	if (ctxt->sax != NULL)
-	    xmlFree(ctxt->sax);
-        ctxt->sax = sax;
+        if (sax->initialized == XML_SAX2_MAGIC) {
+            *ctxt->sax = *sax;
+        } else {
+            memset(ctxt->sax, 0, sizeof(*ctxt->sax));
+            memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1));
+        }
         ctxt->userData = NULL;
     }
 
     xmlParseExtParsedEnt(ctxt);
 
-    if (ctxt->wellFormed)
+    if (ctxt->wellFormed) {
 	ret = ctxt->myDoc;
-    else {
+    } else {
         ret = NULL;
         xmlFreeDoc(ctxt->myDoc);
-        ctxt->myDoc = NULL;
     }
-    if (sax != NULL)
-        ctxt->sax = NULL;
+
     xmlFreeParserCtxt(ctxt);
 
     return(ret);
@@ -13418,92 +12641,13 @@
 #endif /* LIBXML_SAX1_ENABLED */
 
 /**
- * xmlCreateEntityParserCtxtInternal:
- * @URL:  the entity URL
- * @ID:  the entity PUBLIC ID
- * @base:  a possible base for the target URI
- * @pctx:  parser context used to set options on new context
- *
- * Create a parser context for an external entity
- * Automatic support for ZLIB/Compress compressed document is provided
- * by default if found at compile-time.
- *
- * Returns the new parser context or NULL
- */
-static xmlParserCtxtPtr
-xmlCreateEntityParserCtxtInternal(xmlSAXHandlerPtr sax, void *userData,
-        const xmlChar *URL, const xmlChar *ID, const xmlChar *base,
-        xmlParserCtxtPtr pctx) {
-    xmlParserCtxtPtr ctxt;
-    xmlParserInputPtr inputStream;
-    xmlChar *uri = NULL;
-
-    ctxt = xmlNewSAXParserCtxt(sax, userData);
-    if (ctxt == NULL) {
-        xmlErrMemory(pctx, NULL);
-	return(NULL);
-    }
-
-    if (pctx != NULL) {
-        ctxt->options = pctx->options;
-        ctxt->_private = pctx->_private;
-	ctxt->input_id = pctx->input_id;
-    }
-
-    /* Don't read from stdin. */
-    if (xmlStrcmp(URL, BAD_CAST "-") == 0)
-        URL = BAD_CAST "./-";
-
-    if (base != NULL) {
-        if (xmlBuildURISafe(URL, base, &uri) < 0) {
-            xmlErrMemory(ctxt, NULL);
-            goto error;
-        }
-        if (uri != NULL)
-            URL = uri;
-    }
-
-    inputStream = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt);
-    if (inputStream == NULL)
-        goto error;
-
-    inputPush(ctxt, inputStream);
-
-    if (ctxt->directory == NULL) {
-        ctxt->directory = xmlParserGetDirectory((char *)URL);
-        if (ctxt->directory == NULL) {
-            xmlErrMemory(ctxt, NULL);
-            goto error;
-        }
-    }
-
-    xmlFree(uri);
-    return(ctxt);
-
-error:
-    if (pctx != NULL) {
-        if (xmlCopyError(&ctxt->lastError, &pctx->lastError) < 0) {
-            xmlErrMemory(pctx, NULL);
-        } else {
-            pctx->errNo = ctxt->errNo;
-            if (ctxt->disableSAX > pctx->disableSAX)
-                pctx->disableSAX = ctxt->disableSAX;
-            if (ctxt->wellFormed == 0)
-                pctx->wellFormed = 0;
-        }
-    }
-
-    xmlFree(uri);
-    xmlFreeParserCtxt(ctxt);
-    return(NULL);
-}
-
-/**
  * xmlCreateEntityParserCtxt:
  * @URL:  the entity URL
  * @ID:  the entity PUBLIC ID
  * @base:  a possible base for the target URI
  *
+ * DEPRECATED: Use xmlNewInputURL.
+ *
  * Create a parser context for an external entity
  * Automatic support for ZLIB/Compress compressed document is provided
  * by default if found at compile-time.
@@ -13513,8 +12657,35 @@
 xmlParserCtxtPtr
 xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID,
 	                  const xmlChar *base) {
-    return xmlCreateEntityParserCtxtInternal(NULL, NULL, URL, ID, base, NULL);
+    xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
+    xmlChar *uri = NULL;
 
+    ctxt = xmlNewParserCtxt();
+    if (ctxt == NULL)
+	return(NULL);
+
+    if (base != NULL) {
+        if (xmlBuildURISafe(URL, base, &uri) < 0)
+            goto error;
+        if (uri != NULL)
+            URL = uri;
+    }
+
+    input = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt);
+    if (input == NULL)
+        goto error;
+
+    if (inputPush(ctxt, input) < 0)
+        goto error;
+
+    xmlFree(uri);
+    return(ctxt);
+
+error:
+    xmlFree(uri);
+    xmlFreeParserCtxt(ctxt);
+    return(NULL);
 }
 
 /************************************************************************
@@ -13528,6 +12699,8 @@
  * @filename:  the filename or URL
  * @options:  a combination of xmlParserOption
  *
+ * DEPRECATED: Use xmlNewParserCtxt and xmlCtxtReadFile.
+ *
  * Create a parser context for a file or URL content.
  * Automatic support for ZLIB/Compress compressed document is provided
  * by default if found at compile-time and for file accesses
@@ -13538,28 +12711,21 @@
 xmlCreateURLParserCtxt(const char *filename, int options)
 {
     xmlParserCtxtPtr ctxt;
-    xmlParserInputPtr inputStream;
-    char *directory = NULL;
+    xmlParserInputPtr input;
 
     ctxt = xmlNewParserCtxt();
     if (ctxt == NULL)
 	return(NULL);
 
-    if (options)
-	xmlCtxtUseOptionsInternal(ctxt, options, NULL);
+    xmlCtxtUseOptions(ctxt, options);
     ctxt->linenumbers = 1;
 
-    inputStream = xmlLoadExternalEntity(filename, NULL, ctxt);
-    if (inputStream == NULL) {
+    input = xmlLoadExternalEntity(filename, NULL, ctxt);
+    if (input == NULL) {
 	xmlFreeParserCtxt(ctxt);
 	return(NULL);
     }
-
-    inputPush(ctxt, inputStream);
-    if ((ctxt->directory == NULL) && (directory == NULL))
-        directory = xmlParserGetDirectory(filename);
-    if ((ctxt->directory == NULL) && (directory != NULL))
-        ctxt->directory = directory;
+    inputPush(ctxt, input);
 
     return(ctxt);
 }
@@ -13568,6 +12734,8 @@
  * xmlCreateFileParserCtxt:
  * @filename:  the filename
  *
+ * DEPRECATED: Use xmlNewParserCtxt and xmlCtxtReadFile.
+ *
  * Create a parser context for a file content.
  * Automatic support for ZLIB/Compress compressed document is provided
  * by default if found at compile-time.
@@ -13607,48 +12775,25 @@
                         int recovery, void *data) {
     xmlDocPtr ret;
     xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
 
-    xmlInitParser();
-
-    ctxt = xmlCreateFileParserCtxt(filename);
-    if (ctxt == NULL) {
+    ctxt = xmlNewSAXParserCtxt(sax, NULL);
+    if (ctxt == NULL)
 	return(NULL);
-    }
-    if (sax != NULL) {
-	if (ctxt->sax != NULL)
-	    xmlFree(ctxt->sax);
-        ctxt->sax = sax;
-    }
-    xmlDetectSAX2(ctxt);
-    if (data!=NULL) {
+
+    if (data != NULL)
 	ctxt->_private = data;
+
+    if (recovery) {
+        ctxt->options |= XML_PARSE_RECOVER;
+        ctxt->recovery = 1;
     }
 
-    if (ctxt->directory == NULL)
-        ctxt->directory = xmlParserGetDirectory(filename);
+    input = xmlNewInputURL(ctxt, filename, NULL, NULL, 0);
 
-    ctxt->recovery = recovery;
+    ret = xmlCtxtParseDocument(ctxt, input);
 
-    xmlParseDocument(ctxt);
-
-    if ((ctxt->wellFormed) || recovery) {
-        ret = ctxt->myDoc;
-	if ((ret != NULL) && (ctxt->input->buf != NULL)) {
-	    if (ctxt->input->buf->compressed > 0)
-		ret->compression = 9;
-	    else
-		ret->compression = ctxt->input->buf->compressed;
-	}
-    }
-    else {
-       ret = NULL;
-       xmlFreeDoc(ctxt->myDoc);
-       ctxt->myDoc = NULL;
-    }
-    if (sax != NULL)
-        ctxt->sax = NULL;
     xmlFreeParserCtxt(ctxt);
-
     return(ret);
 }
 
@@ -13754,15 +12899,9 @@
 
     xmlClearParserCtxt(ctxt);
 
-    input = xmlNewInputStream(ctxt);
+    input = xmlNewInputString(ctxt, filename, (const char *) buffer, NULL, 0);
     if (input == NULL)
         return;
-
-    if (filename != NULL)
-        input->filename = (char *) xmlCanonicPath((const xmlChar *)filename);
-    input->base = buffer;
-    input->cur = buffer;
-    input->end = &buffer[xmlStrlen(buffer)];
     inputPush(ctxt, input);
 }
 
@@ -13788,12 +12927,14 @@
     ctxt = xmlCreateFileParserCtxt(filename);
     if (ctxt == NULL) return -1;
     if (sax != NULL) {
-        if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler)
-            xmlFree(ctxt->sax);
-        ctxt->sax = sax;
+        if (sax->initialized == XML_SAX2_MAGIC) {
+            *ctxt->sax = *sax;
+        } else {
+            memset(ctxt->sax, 0, sizeof(*ctxt->sax));
+            memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1));
+        }
 	ctxt->userData = user_data;
     }
-    xmlDetectSAX2(ctxt);
 
     xmlParseDocument(ctxt);
 
@@ -13835,35 +12976,21 @@
 xmlCreateMemoryParserCtxt(const char *buffer, int size) {
     xmlParserCtxtPtr ctxt;
     xmlParserInputPtr input;
-    xmlParserInputBufferPtr buf;
 
-    if (buffer == NULL)
-	return(NULL);
-    if (size <= 0)
+    if (size < 0)
 	return(NULL);
 
     ctxt = xmlNewParserCtxt();
     if (ctxt == NULL)
 	return(NULL);
 
-    buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
-    if (buf == NULL) {
-	xmlFreeParserCtxt(ctxt);
-	return(NULL);
-    }
-
-    input = xmlNewInputStream(ctxt);
+    input = xmlNewInputMemory(ctxt, NULL, buffer, size, NULL, 0);
     if (input == NULL) {
-	xmlFreeParserInputBuffer(buf);
 	xmlFreeParserCtxt(ctxt);
 	return(NULL);
     }
-
-    input->filename = NULL;
-    input->buf = buf;
-    xmlBufResetInput(input->buf->buffer, input);
-
     inputPush(ctxt, input);
+
     return(ctxt);
 }
 
@@ -13891,38 +13018,32 @@
 
 xmlDocPtr
 xmlSAXParseMemoryWithData(xmlSAXHandlerPtr sax, const char *buffer,
-	          int size, int recovery, void *data) {
+                          int size, int recovery, void *data) {
     xmlDocPtr ret;
     xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
 
-    xmlInitParser();
+    if (size < 0)
+        return(NULL);
 
-    ctxt = xmlCreateMemoryParserCtxt(buffer, size);
-    if (ctxt == NULL) return(NULL);
-    if (sax != NULL) {
-	if (ctxt->sax != NULL)
-	    xmlFree(ctxt->sax);
-        ctxt->sax = sax;
-    }
-    xmlDetectSAX2(ctxt);
-    if (data!=NULL) {
+    ctxt = xmlNewSAXParserCtxt(sax, NULL);
+    if (ctxt == NULL)
+        return(NULL);
+
+    if (data != NULL)
 	ctxt->_private=data;
+
+    if (recovery) {
+        ctxt->options |= XML_PARSE_RECOVER;
+        ctxt->recovery = 1;
     }
 
-    ctxt->recovery = recovery;
+    input = xmlNewInputMemory(ctxt, NULL, buffer, size, NULL,
+                              XML_INPUT_BUF_STATIC);
 
-    xmlParseDocument(ctxt);
+    ret = xmlCtxtParseDocument(ctxt, input);
 
-    if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
-    else {
-       ret = NULL;
-       xmlFreeDoc(ctxt->myDoc);
-       ctxt->myDoc = NULL;
-    }
-    if (sax != NULL)
-	ctxt->sax = NULL;
     xmlFreeParserCtxt(ctxt);
-
     return(ret);
 }
 
@@ -14000,17 +13121,17 @@
     int ret = 0;
     xmlParserCtxtPtr ctxt;
 
-    xmlInitParser();
-
     ctxt = xmlCreateMemoryParserCtxt(buffer, size);
     if (ctxt == NULL) return -1;
     if (sax != NULL) {
-        if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler)
-            xmlFree(ctxt->sax);
-        ctxt->sax = sax;
+        if (sax->initialized == XML_SAX2_MAGIC) {
+            *ctxt->sax = *sax;
+        } else {
+            memset(ctxt->sax, 0, sizeof(*ctxt->sax));
+            memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1));
+        }
 	ctxt->userData = user_data;
     }
-    xmlDetectSAX2(ctxt);
 
     xmlParseDocument(ctxt);
 
@@ -14044,33 +13165,18 @@
 xmlCreateDocParserCtxt(const xmlChar *str) {
     xmlParserCtxtPtr ctxt;
     xmlParserInputPtr input;
-    xmlParserInputBufferPtr buf;
-
-    if (str == NULL)
-	return(NULL);
 
     ctxt = xmlNewParserCtxt();
     if (ctxt == NULL)
 	return(NULL);
 
-    buf = xmlParserInputBufferCreateString(str);
-    if (buf == NULL) {
-	xmlFreeParserCtxt(ctxt);
-	return(NULL);
-    }
-
-    input = xmlNewInputStream(ctxt);
+    input = xmlNewInputString(ctxt, NULL, (const char *) str, NULL, 0);
     if (input == NULL) {
-	xmlFreeParserInputBuffer(buf);
 	xmlFreeParserCtxt(ctxt);
 	return(NULL);
     }
-
-    input->filename = NULL;
-    input->buf = buf;
-    xmlBufResetInput(input->buf->buffer, input);
-
     inputPush(ctxt, input);
+
     return(ctxt);
 }
 
@@ -14107,7 +13213,6 @@
         ctxt->sax = sax;
         ctxt->userData = NULL;
     }
-    xmlDetectSAX2(ctxt);
 
     xmlParseDocument(ctxt);
     if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
@@ -14140,47 +13245,6 @@
 }
 #endif /* LIBXML_SAX1_ENABLED */
 
-#ifdef LIBXML_LEGACY_ENABLED
-/************************************************************************
- *									*
- *	Specific function to keep track of entities references		*
- *	and used by the XSLT debugger					*
- *									*
- ************************************************************************/
-
-static xmlEntityReferenceFunc xmlEntityRefFunc = NULL;
-
-/**
- * xmlAddEntityReference:
- * @ent : A valid entity
- * @firstNode : A valid first node for children of entity
- * @lastNode : A valid last node of children entity
- *
- * Notify of a reference to an entity of type XML_EXTERNAL_GENERAL_PARSED_ENTITY
- */
-static void
-xmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode,
-                      xmlNodePtr lastNode)
-{
-    if (xmlEntityRefFunc != NULL) {
-        (*xmlEntityRefFunc) (ent, firstNode, lastNode);
-    }
-}
-
-
-/**
- * xmlSetEntityReferenceFunc:
- * @func: A valid function
- *
- * Set the function to call call back when a xml reference has been made
- */
-void
-xmlSetEntityReferenceFunc(xmlEntityReferenceFunc func)
-{
-    xmlEntityRefFunc = func;
-}
-#endif /* LIBXML_LEGACY_ENABLED */
-
 /************************************************************************
  *									*
  *	New set (2.6.0) of simpler and more flexible APIs		*
@@ -14244,8 +13308,6 @@
     ctxt->version = NULL;
     DICT_FREE(ctxt->encoding);
     ctxt->encoding = NULL;
-    DICT_FREE(ctxt->directory);
-    ctxt->directory = NULL;
     DICT_FREE(ctxt->extSubURI);
     ctxt->extSubURI = NULL;
     DICT_FREE(ctxt->extSubSystem);
@@ -14258,9 +13320,7 @@
     ctxt->hasExternalSubset = 0;
     ctxt->hasPErefs = 0;
     ctxt->html = 0;
-    ctxt->external = 0;
     ctxt->instate = XML_PARSER_START;
-    ctxt->token = 0;
 
     ctxt->wellFormed = 1;
     ctxt->nsWellFormed = 1;
@@ -14317,204 +13377,258 @@
 xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk,
                  int size, const char *filename, const char *encoding)
 {
-    xmlParserInputPtr inputStream;
-    xmlParserInputBufferPtr buf;
+    xmlParserInputPtr input;
 
     if (ctxt == NULL)
         return(1);
 
-    buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
-    if (buf == NULL)
-        return(1);
-
-    if (ctxt == NULL) {
-        xmlFreeParserInputBuffer(buf);
-        return(1);
-    }
-
     xmlCtxtReset(ctxt);
 
-    if (filename == NULL) {
-        ctxt->directory = NULL;
-    } else {
-        ctxt->directory = xmlParserGetDirectory(filename);
-    }
-
-    inputStream = xmlNewInputStream(ctxt);
-    if (inputStream == NULL) {
-        xmlFreeParserInputBuffer(buf);
+    input = xmlNewInputPush(ctxt, filename, chunk, size, encoding);
+    if (input == NULL)
         return(1);
-    }
-
-    if (filename == NULL)
-        inputStream->filename = NULL;
-    else
-        inputStream->filename = (char *)
-            xmlCanonicPath((const xmlChar *) filename);
-    inputStream->buf = buf;
-    xmlBufResetInput(buf->buffer, inputStream);
-
-    inputPush(ctxt, inputStream);
-
-    if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
-        (ctxt->input->buf != NULL)) {
-        size_t pos = ctxt->input->cur - ctxt->input->base;
-        int res;
-
-        res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
-        xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos);
-        if (res < 0) {
-            xmlFatalErr(ctxt, ctxt->input->buf->error, NULL);
-            xmlHaltParser(ctxt);
-            return(1);
-        }
-    }
-
-    if (encoding != NULL)
-        xmlSwitchEncodingName(ctxt, encoding);
+    inputPush(ctxt, input);
 
     return(0);
 }
 
+static int
+xmlCtxtSetOptionsInternal(xmlParserCtxtPtr ctxt, int options, int keepMask)
+{
+    int allMask;
+
+    if (ctxt == NULL)
+        return(-1);
+
+    /*
+     * XInclude options aren't handled by the parser.
+     *
+     * XML_PARSE_XINCLUDE
+     * XML_PARSE_NOXINCNODE
+     * XML_PARSE_NOBASEFIX
+     */
+    allMask = XML_PARSE_RECOVER |
+              XML_PARSE_NOENT |
+              XML_PARSE_DTDLOAD |
+              XML_PARSE_DTDATTR |
+              XML_PARSE_DTDVALID |
+              XML_PARSE_NOERROR |
+              XML_PARSE_NOWARNING |
+              XML_PARSE_PEDANTIC |
+              XML_PARSE_NOBLANKS |
+#ifdef LIBXML_SAX1_ENABLED
+              XML_PARSE_SAX1 |
+#endif
+              XML_PARSE_NONET |
+              XML_PARSE_NODICT |
+              XML_PARSE_NSCLEAN |
+              XML_PARSE_NOCDATA |
+              XML_PARSE_COMPACT |
+              XML_PARSE_OLD10 |
+              XML_PARSE_HUGE |
+              XML_PARSE_OLDSAX |
+              XML_PARSE_IGNORE_ENC |
+              XML_PARSE_BIG_LINES |
+              XML_PARSE_NO_XXE;
+
+    ctxt->options = (ctxt->options & keepMask) | (options & allMask);
+
+    /*
+     * For some options, struct members are historically the source
+     * of truth. The values are initalized from global variables and
+     * old code could also modify them directly. Several older API
+     * functions that don't take an options argument rely on these
+     * deprecated mechanisms.
+     *
+     * Once public access to struct members and the globals are
+     * disabled, we can use the options bitmask as source of
+     * truth, making all these struct members obsolete.
+     *
+     * The XML_DETECT_IDS flags is misnamed. It simply enables
+     * loading of the external subset.
+     */
+    ctxt->recovery = (options & XML_PARSE_RECOVER) ? 1 : 0;
+    ctxt->replaceEntities = (options & XML_PARSE_NOENT) ? 1 : 0;
+    ctxt->loadsubset = (options & XML_PARSE_DTDLOAD) ? XML_DETECT_IDS : 0;
+    ctxt->loadsubset |= (options & XML_PARSE_DTDATTR) ? XML_COMPLETE_ATTRS : 0;
+    ctxt->validate = (options & XML_PARSE_DTDVALID) ? 1 : 0;
+    ctxt->pedantic = (options & XML_PARSE_PEDANTIC) ? 1 : 0;
+    ctxt->keepBlanks = (options & XML_PARSE_NOBLANKS) ? 0 : 1;
+    ctxt->dictNames = (options & XML_PARSE_NODICT) ? 0 : 1;
+
+    /*
+     * Changing SAX callbacks is a bad idea. This should be fixed.
+     */
+    if (options & XML_PARSE_NOBLANKS) {
+        ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace;
+    }
+    if (options & XML_PARSE_NOCDATA) {
+        ctxt->sax->cdataBlock = NULL;
+    }
+    if (options & XML_PARSE_HUGE) {
+        if (ctxt->dict != NULL)
+            xmlDictSetLimit(ctxt->dict, 0);
+    }
+
+    ctxt->linenumbers = 1;
+
+    return(options & ~allMask);
+}
 
 /**
- * xmlCtxtUseOptionsInternal:
+ * xmlCtxtSetOptions:
  * @ctxt: an XML parser context
- * @options:  a combination of xmlParserOption
- * @encoding:  the user provided encoding to use
+ * @options:  a bitmask of xmlParserOption values
  *
- * Applies the options to the parser context
+ * Applies the options to the parser context. Unset options are
+ * cleared.
+ *
+ * Available since 2.13.0. With older versions, you can use
+ * xmlCtxtUseOptions.
+ *
+ * XML_PARSE_RECOVER
+ *
+ * Enable "recovery" mode which allows non-wellformed documents.
+ * How this mode behaves exactly is unspecified and may change
+ * without further notice. Use of this feature is DISCOURAGED.
+ *
+ * XML_PARSE_NOENT
+ *
+ * Despite the confusing name, this option enables substitution
+ * of entities. The resulting tree won't contain any entity
+ * reference nodes.
+ *
+ * This option also enables loading of external entities (both
+ * general and parameter entities) which is dangerous. If you
+ * process untrusted data, it's recommended to set the
+ * XML_PARSE_NO_XXE option to disable loading of external
+ * entities.
+ *
+ * XML_PARSE_DTDLOAD
+ *
+ * Enables loading of an external DTD and the loading and
+ * substitution of external parameter entities. Has no effect
+ * if XML_PARSE_NO_XXE is set.
+ *
+ * XML_PARSE_DTDATTR
+ *
+ * Adds default attributes from the DTD to the result document.
+ *
+ * Implies XML_PARSE_DTDLOAD, but loading of external content
+ * can be disabled with XML_PARSE_NO_XXE.
+ *
+ * XML_PARSE_DTDVALID
+ *
+ * This option enables DTD validation which requires to load
+ * external DTDs and external entities (both general and
+ * parameter entities) unless XML_PARSE_NO_XXE was set.
+ *
+ * XML_PARSE_NO_XXE
+ *
+ * Disables loading of external DTDs or entities.
+ *
+ * XML_PARSE_NOERROR
+ *
+ * Disable error and warning reports to the error handlers.
+ * Errors are still accessible with xmlCtxtGetLastError.
+ *
+ * XML_PARSE_NOWARNING
+ *
+ * Disable warning reports.
+ *
+ * XML_PARSE_PEDANTIC
+ *
+ * Enable some pedantic warnings.
+ *
+ * XML_PARSE_NOBLANKS
+ *
+ * Remove some text nodes containing only whitespace from the
+ * result document. Which nodes are removed depends on DTD
+ * element declarations or a conservative heuristic. The
+ * reindenting feature of the serialization code relies on this
+ * option to be set when parsing. Use of this option is
+ * DISCOURAGED.
+ *
+ * XML_PARSE_SAX1
+ *
+ * Always invoke the deprecated SAX1 startElement and endElement
+ * handlers. This option is DEPRECATED.
+ *
+ * XML_PARSE_NONET
+ *
+ * Disable network access with the builtin HTTP and FTP clients.
+ *
+ * XML_PARSE_NODICT
+ *
+ * Create a document without interned strings, making all
+ * strings separate memory allocations.
+ *
+ * XML_PARSE_NSCLEAN
+ *
+ * Remove redundant namespace declarations from the result
+ * document.
+ *
+ * XML_PARSE_NOCDATA
+ *
+ * Output normal text nodes instead of CDATA nodes.
+ *
+ * XML_PARSE_COMPACT
+ *
+ * Store small strings directly in the node struct to save
+ * memory.
+ *
+ * XML_PARSE_OLD10
+ *
+ * Use old Name productions from before XML 1.0 Fifth Edition.
+ * This options is DEPRECATED.
+ *
+ * XML_PARSE_HUGE
+ *
+ * Relax some internal limits.
+ *
+ * Maximum size of text nodes, tags, comments, processing instructions,
+ * CDATA sections, entity values
+ *
+ * normal: 10M
+ * huge:    1B
+ *
+ * Maximum size of names, system literals, pubid literals
+ *
+ * normal: 50K
+ * huge:   10M
+ *
+ * Maximum nesting depth of elements
+ *
+ * normal:  256
+ * huge:   2048
+ *
+ * Maximum nesting depth of entities
+ *
+ * normal: 20
+ * huge:   40
+ *
+ * XML_PARSE_OLDSAX
+ *
+ * Enable an unspecified legacy mode for SAX parsers. This
+ * option is DEPRECATED.
+ *
+ * XML_PARSE_IGNORE_ENC
+ *
+ * Ignore the encoding in the XML declaration. This option is
+ * mostly unneeded these days. The only effect is to enforce
+ * UTF-8 decoding of ASCII-like data.
+ *
+ * XML_PARSE_BIG_LINES
+ *
+ * Enable reporting of line numbers larger than 65535.
  *
  * Returns 0 in case of success, the set of unknown or unimplemented options
  *         in case of error.
  */
-static int
-xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options, const char *encoding)
+int
+xmlCtxtSetOptions(xmlParserCtxtPtr ctxt, int options)
 {
-    if (ctxt == NULL)
-        return(-1);
-    if (encoding != NULL) {
-        if (ctxt->encoding != NULL)
-	    xmlFree((xmlChar *) ctxt->encoding);
-        ctxt->encoding = xmlStrdup((const xmlChar *) encoding);
-    }
-    if (options & XML_PARSE_RECOVER) {
-        ctxt->recovery = 1;
-        options -= XML_PARSE_RECOVER;
-	ctxt->options |= XML_PARSE_RECOVER;
-    } else
-        ctxt->recovery = 0;
-    if (options & XML_PARSE_DTDLOAD) {
-        ctxt->loadsubset = XML_DETECT_IDS;
-        options -= XML_PARSE_DTDLOAD;
-	ctxt->options |= XML_PARSE_DTDLOAD;
-    } else
-        ctxt->loadsubset = 0;
-    if (options & XML_PARSE_DTDATTR) {
-        ctxt->loadsubset |= XML_COMPLETE_ATTRS;
-        options -= XML_PARSE_DTDATTR;
-	ctxt->options |= XML_PARSE_DTDATTR;
-    }
-    if (options & XML_PARSE_NOENT) {
-        ctxt->replaceEntities = 1;
-        /* ctxt->loadsubset |= XML_DETECT_IDS; */
-        options -= XML_PARSE_NOENT;
-	ctxt->options |= XML_PARSE_NOENT;
-    } else
-        ctxt->replaceEntities = 0;
-    if (options & XML_PARSE_PEDANTIC) {
-        ctxt->pedantic = 1;
-        options -= XML_PARSE_PEDANTIC;
-	ctxt->options |= XML_PARSE_PEDANTIC;
-    } else
-        ctxt->pedantic = 0;
-    if (options & XML_PARSE_NOBLANKS) {
-        ctxt->keepBlanks = 0;
-        ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace;
-        options -= XML_PARSE_NOBLANKS;
-	ctxt->options |= XML_PARSE_NOBLANKS;
-    } else
-        ctxt->keepBlanks = 1;
-    if (options & XML_PARSE_DTDVALID) {
-        ctxt->validate = 1;
-        if (options & XML_PARSE_NOWARNING)
-            ctxt->vctxt.warning = NULL;
-        if (options & XML_PARSE_NOERROR)
-            ctxt->vctxt.error = NULL;
-        options -= XML_PARSE_DTDVALID;
-	ctxt->options |= XML_PARSE_DTDVALID;
-    } else
-        ctxt->validate = 0;
-    if (options & XML_PARSE_NOWARNING) {
-        ctxt->sax->warning = NULL;
-        options -= XML_PARSE_NOWARNING;
-    }
-    if (options & XML_PARSE_NOERROR) {
-        ctxt->sax->error = NULL;
-        ctxt->sax->fatalError = NULL;
-        options -= XML_PARSE_NOERROR;
-    }
-#ifdef LIBXML_SAX1_ENABLED
-    if (options & XML_PARSE_SAX1) {
-        ctxt->sax->startElementNs = NULL;
-        ctxt->sax->endElementNs = NULL;
-        ctxt->sax->initialized = 1;
-        options -= XML_PARSE_SAX1;
-	ctxt->options |= XML_PARSE_SAX1;
-    }
-#endif /* LIBXML_SAX1_ENABLED */
-    if (options & XML_PARSE_NODICT) {
-        ctxt->dictNames = 0;
-        options -= XML_PARSE_NODICT;
-	ctxt->options |= XML_PARSE_NODICT;
-    } else {
-        ctxt->dictNames = 1;
-    }
-    if (options & XML_PARSE_NOCDATA) {
-        ctxt->sax->cdataBlock = NULL;
-        options -= XML_PARSE_NOCDATA;
-	ctxt->options |= XML_PARSE_NOCDATA;
-    }
-    if (options & XML_PARSE_NSCLEAN) {
-	ctxt->options |= XML_PARSE_NSCLEAN;
-        options -= XML_PARSE_NSCLEAN;
-    }
-    if (options & XML_PARSE_NONET) {
-	ctxt->options |= XML_PARSE_NONET;
-        options -= XML_PARSE_NONET;
-    }
-    if (options & XML_PARSE_COMPACT) {
-	ctxt->options |= XML_PARSE_COMPACT;
-        options -= XML_PARSE_COMPACT;
-    }
-    if (options & XML_PARSE_OLD10) {
-	ctxt->options |= XML_PARSE_OLD10;
-        options -= XML_PARSE_OLD10;
-    }
-    if (options & XML_PARSE_NOBASEFIX) {
-	ctxt->options |= XML_PARSE_NOBASEFIX;
-        options -= XML_PARSE_NOBASEFIX;
-    }
-    if (options & XML_PARSE_HUGE) {
-	ctxt->options |= XML_PARSE_HUGE;
-        options -= XML_PARSE_HUGE;
-        if (ctxt->dict != NULL)
-            xmlDictSetLimit(ctxt->dict, 0);
-    }
-    if (options & XML_PARSE_OLDSAX) {
-	ctxt->options |= XML_PARSE_OLDSAX;
-        options -= XML_PARSE_OLDSAX;
-    }
-    if (options & XML_PARSE_IGNORE_ENC) {
-	ctxt->options |= XML_PARSE_IGNORE_ENC;
-        options -= XML_PARSE_IGNORE_ENC;
-    }
-    if (options & XML_PARSE_BIG_LINES) {
-	ctxt->options |= XML_PARSE_BIG_LINES;
-        options -= XML_PARSE_BIG_LINES;
-    }
-    ctxt->linenumbers = 1;
-    return (options);
+    return(xmlCtxtSetOptionsInternal(ctxt, options, 0));
 }
 
 /**
@@ -14522,7 +13636,22 @@
  * @ctxt: an XML parser context
  * @options:  a combination of xmlParserOption
  *
- * Applies the options to the parser context
+ * DEPRECATED: Use xmlCtxtSetOptions.
+ *
+ * Applies the options to the parser context. The following options
+ * are never cleared and can only be enabled:
+ *
+ * XML_PARSE_NOERROR
+ * XML_PARSE_NOWARNING
+ * XML_PARSE_NONET
+ * XML_PARSE_NSCLEAN
+ * XML_PARSE_NOCDATA
+ * XML_PARSE_COMPACT
+ * XML_PARSE_OLD10
+ * XML_PARSE_HUGE
+ * XML_PARSE_OLDSAX
+ * XML_PARSE_IGNORE_ENC
+ * XML_PARSE_BIG_LINES
  *
  * Returns 0 in case of success, the set of unknown or unimplemented options
  *         in case of error.
@@ -14530,7 +13659,24 @@
 int
 xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options)
 {
-   return(xmlCtxtUseOptionsInternal(ctxt, options, NULL));
+    int keepMask;
+
+    /*
+     * For historic reasons, some options can only be enabled.
+     */
+    keepMask = XML_PARSE_NOERROR |
+               XML_PARSE_NOWARNING |
+               XML_PARSE_NONET |
+               XML_PARSE_NSCLEAN |
+               XML_PARSE_NOCDATA |
+               XML_PARSE_COMPACT |
+               XML_PARSE_OLD10 |
+               XML_PARSE_HUGE |
+               XML_PARSE_OLDSAX |
+               XML_PARSE_IGNORE_ENC |
+               XML_PARSE_BIG_LINES;
+
+    return(xmlCtxtSetOptionsInternal(ctxt, options, keepMask));
 }
 
 /**
@@ -14553,87 +13699,100 @@
 }
 
 /**
- * xmlDoRead:
+ * xmlCtxtParseDocument:
  * @ctxt:  an XML parser context
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
- * @options:  a combination of xmlParserOption
- * @reuse:  keep the context for reuse
+ * @input:  parser input
  *
- * Common front-end for the xmlRead functions
+ * Parse an XML document and return the resulting document tree.
+ * Takes ownership of the input object.
  *
  * Returns the resulting document tree or NULL
  */
-static xmlDocPtr
-xmlDoRead(xmlParserCtxtPtr ctxt, const char *URL, const char *encoding,
-          int options, int reuse)
+xmlDocPtr
+xmlCtxtParseDocument(xmlParserCtxtPtr ctxt, xmlParserInputPtr input)
 {
     xmlDocPtr ret = NULL;
 
-    xmlCtxtUseOptionsInternal(ctxt, options, encoding);
-    if (encoding != NULL)
-        xmlSwitchEncodingName(ctxt, encoding);
-    if ((URL != NULL) && (ctxt->input != NULL) &&
-        (ctxt->input->filename == NULL)) {
-        ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL);
-        if (ctxt->input->filename == NULL) {
-            xmlErrMemory(ctxt, NULL);
-            goto error;
-        }
+    if ((ctxt == NULL) || (input == NULL))
+        return(NULL);
+
+    /* assert(ctxt->inputNr == 0); */
+    while (ctxt->inputNr > 0)
+        xmlFreeInputStream(inputPop(ctxt));
+
+    if (inputPush(ctxt, input) < 0) {
+        xmlFreeInputStream(input);
+        return(NULL);
     }
+
     xmlParseDocument(ctxt);
+
     if ((ctxt->wellFormed) ||
         ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) {
         ret = ctxt->myDoc;
     } else {
+        if (ctxt->errNo == XML_ERR_OK)
+            xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "unknown error\n");
+
         ret = NULL;
-	if (ctxt->myDoc != NULL) {
-	    xmlFreeDoc(ctxt->myDoc);
-	}
+	xmlFreeDoc(ctxt->myDoc);
     }
     ctxt->myDoc = NULL;
 
-error:
-    if (!reuse) {
-	xmlFreeParserCtxt(ctxt);
-    }
+    /* assert(ctxt->inputNr == 1); */
+    while (ctxt->inputNr > 0)
+        xmlFreeInputStream(inputPop(ctxt));
 
-    return (ret);
+    return(ret);
 }
 
 /**
  * xmlReadDoc:
  * @cur:  a pointer to a zero terminated string
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
+ * @URL:  base URL (optional)
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
- * parse an XML in-memory document and build a tree.
+ * Convenience function to parse an XML document from a
+ * zero-terminated string.
+ *
+ * See xmlCtxtReadDoc for details.
  *
  * Returns the resulting document tree
  */
 xmlDocPtr
-xmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options)
+xmlReadDoc(const xmlChar *cur, const char *URL, const char *encoding,
+           int options)
 {
     xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
+    xmlDocPtr doc;
 
-    if (cur == NULL)
-        return (NULL);
-    xmlInitParser();
-
-    ctxt = xmlCreateDocParserCtxt(cur);
+    ctxt = xmlNewParserCtxt();
     if (ctxt == NULL)
-        return (NULL);
-    return (xmlDoRead(ctxt, URL, encoding, options, 0));
+        return(NULL);
+
+    xmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputString(ctxt, URL, (const char *) cur, encoding,
+                              XML_INPUT_BUF_STATIC);
+
+    doc = xmlCtxtParseDocument(ctxt, input);
+
+    xmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * xmlReadFile:
  * @filename:  a file or URL
- * @encoding:  the document encoding, or NULL
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
- * parse an XML file from the filesystem or the network.
+ * Convenience function to parse an XML file from the filesystem,
+ * the network or a global user-define resource loader.
+ *
+ * See xmlCtxtReadFile for details.
  *
  * Returns the resulting document tree
  */
@@ -14641,49 +13800,77 @@
 xmlReadFile(const char *filename, const char *encoding, int options)
 {
     xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
+    xmlDocPtr doc;
 
-    xmlInitParser();
-    ctxt = xmlCreateURLParserCtxt(filename, options);
+    ctxt = xmlNewParserCtxt();
     if (ctxt == NULL)
-        return (NULL);
-    return (xmlDoRead(ctxt, NULL, encoding, options, 0));
+        return(NULL);
+
+    xmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0);
+
+    doc = xmlCtxtParseDocument(ctxt, input);
+
+    xmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * xmlReadMemory:
  * @buffer:  a pointer to a char array
  * @size:  the size of the array
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
+ * @url:  base URL (optional)
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
  * Parse an XML in-memory document and build a tree. The input buffer must
  * not contain a terminating null byte.
  *
+ * See xmlCtxtReadMemory for details.
+ *
  * Returns the resulting document tree
  */
 xmlDocPtr
-xmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options)
+xmlReadMemory(const char *buffer, int size, const char *url,
+              const char *encoding, int options)
 {
     xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
+    xmlDocPtr doc;
 
-    xmlInitParser();
-    ctxt = xmlCreateMemoryParserCtxt(buffer, size);
+    if (size < 0)
+	return(NULL);
+
+    ctxt = xmlNewParserCtxt();
     if (ctxt == NULL)
-        return (NULL);
-    return (xmlDoRead(ctxt, URL, encoding, options, 0));
+        return(NULL);
+
+    xmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputMemory(ctxt, url, buffer, size, encoding,
+                              XML_INPUT_BUF_STATIC);
+
+    doc = xmlCtxtParseDocument(ctxt, input);
+
+    xmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * xmlReadFd:
  * @fd:  an open file descriptor
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
+ * @URL:  base URL (optional)
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
- * parse an XML from a file descriptor and build a tree.
+ * Parse an XML from a file descriptor and build a tree.
+ *
+ * See xmlCtxtReadFd for details.
+ *
  * NOTE that the file descriptor will not be closed when the
- *      reader is closed or reset.
+ * context is freed or reset.
  *
  * Returns the resulting document tree
  */
@@ -14691,42 +13878,36 @@
 xmlReadFd(int fd, const char *URL, const char *encoding, int options)
 {
     xmlParserCtxtPtr ctxt;
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
+    xmlDocPtr doc;
 
-    if (fd < 0)
-        return (NULL);
-    xmlInitParser();
-
-    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
-    if (input == NULL)
-        return (NULL);
-    input->closecallback = NULL;
     ctxt = xmlNewParserCtxt();
-    if (ctxt == NULL) {
-        xmlFreeParserInputBuffer(input);
-        return (NULL);
-    }
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-        xmlFreeParserInputBuffer(input);
-	xmlFreeParserCtxt(ctxt);
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (xmlDoRead(ctxt, URL, encoding, options, 0));
+    if (ctxt == NULL)
+        return(NULL);
+
+    xmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputFd(ctxt, URL, fd, encoding, 0);
+    input->buf->closecallback = NULL;
+
+    doc = xmlCtxtParseDocument(ctxt, input);
+
+    xmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * xmlReadIO:
  * @ioread:  an I/O read function
- * @ioclose:  an I/O close function
+ * @ioclose:  an I/O close function (optional)
  * @ioctx:  an I/O handler
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
+ * @URL:  base URL (optional)
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
- * parse an XML document from I/O functions and source and build a tree.
+ * Parse an XML document from I/O functions and context and build a tree.
+ *
+ * See xmlCtxtReadIO for details.
  *
  * Returns the resulting document tree
  */
@@ -14735,45 +13916,37 @@
           void *ioctx, const char *URL, const char *encoding, int options)
 {
     xmlParserCtxtPtr ctxt;
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
+    xmlDocPtr doc;
 
-    if (ioread == NULL)
-        return (NULL);
-    xmlInitParser();
-
-    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
-                                         XML_CHAR_ENCODING_NONE);
-    if (input == NULL) {
-        if (ioclose != NULL)
-            ioclose(ioctx);
-        return (NULL);
-    }
     ctxt = xmlNewParserCtxt();
-    if (ctxt == NULL) {
-        xmlFreeParserInputBuffer(input);
-        return (NULL);
-    }
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-        xmlFreeParserInputBuffer(input);
-	xmlFreeParserCtxt(ctxt);
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (xmlDoRead(ctxt, URL, encoding, options, 0));
+    if (ctxt == NULL)
+        return(NULL);
+
+    xmlCtxtUseOptions(ctxt, options);
+
+    input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0);
+
+    doc = xmlCtxtParseDocument(ctxt, input);
+
+    xmlFreeParserCtxt(ctxt);
+    return(doc);
 }
 
 /**
  * xmlCtxtReadDoc:
  * @ctxt:  an XML parser context
  * @str:  a pointer to a zero terminated string
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
+ * @URL:  base URL (optional)
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
- * parse an XML in-memory document and build a tree.
- * This reuses the existing @ctxt parser context
+ * Parse an XML in-memory document and build a tree.
+ *
+ * @URL is used as base to resolve external entities and for error
+ * reporting.
+ *
+ * See xmlCtxtUseOptions for details.
  *
  * Returns the resulting document tree
  */
@@ -14781,41 +13954,31 @@
 xmlCtxtReadDoc(xmlParserCtxtPtr ctxt, const xmlChar *str,
                const char *URL, const char *encoding, int options)
 {
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
     if (ctxt == NULL)
-        return (NULL);
-    if (str == NULL)
-        return (NULL);
-    xmlInitParser();
+        return(NULL);
 
     xmlCtxtReset(ctxt);
+    xmlCtxtUseOptions(ctxt, options);
 
-    input = xmlParserInputBufferCreateString(str);
-    if (input == NULL) {
-	return(NULL);
-    }
+    input = xmlNewInputString(ctxt, URL, (const char *) str, encoding,
+                              XML_INPUT_BUF_STATIC);
 
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-	xmlFreeParserInputBuffer(input);
-	return(NULL);
-    }
-
-    inputPush(ctxt, stream);
-    return (xmlDoRead(ctxt, URL, encoding, options, 1));
+    return(xmlCtxtParseDocument(ctxt, input));
 }
 
 /**
  * xmlCtxtReadFile:
  * @ctxt:  an XML parser context
  * @filename:  a file or URL
- * @encoding:  the document encoding, or NULL
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
- * parse an XML file from the filesystem or the network.
- * This reuses the existing @ctxt parser context
+ * Parse an XML file from the filesystem, the network or a user-defined
+ * resource loader.
+ *
+ * See xmlNewInputURL and xmlCtxtUseOptions for details.
  *
  * Returns the resulting document tree
  */
@@ -14823,22 +13986,17 @@
 xmlCtxtReadFile(xmlParserCtxtPtr ctxt, const char *filename,
                 const char *encoding, int options)
 {
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
-    if (filename == NULL)
-        return (NULL);
     if (ctxt == NULL)
-        return (NULL);
-    xmlInitParser();
+        return(NULL);
 
     xmlCtxtReset(ctxt);
+    xmlCtxtUseOptions(ctxt, options);
 
-    stream = xmlLoadExternalEntity(filename, NULL, ctxt);
-    if (stream == NULL) {
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (xmlDoRead(ctxt, NULL, encoding, options, 1));
+    input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0);
+
+    return(xmlCtxtParseDocument(ctxt, input));
 }
 
 /**
@@ -14846,13 +14004,17 @@
  * @ctxt:  an XML parser context
  * @buffer:  a pointer to a char array
  * @size:  the size of the array
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
+ * @URL:  base URL (optional)
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
  * Parse an XML in-memory document and build a tree. The input buffer must
  * not contain a terminating null byte.
- * This reuses the existing @ctxt parser context
+ *
+ * @URL is used as base to resolve external entities and for error
+ * reporting.
+ *
+ * See xmlCtxtUseOptions for details.
  *
  * Returns the resulting document tree
  */
@@ -14860,45 +14022,37 @@
 xmlCtxtReadMemory(xmlParserCtxtPtr ctxt, const char *buffer, int size,
                   const char *URL, const char *encoding, int options)
 {
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
-    if (ctxt == NULL)
-        return (NULL);
-    if (buffer == NULL)
-        return (NULL);
-    xmlInitParser();
+    if ((ctxt == NULL) || (size < 0))
+        return(NULL);
 
     xmlCtxtReset(ctxt);
+    xmlCtxtUseOptions(ctxt, options);
 
-    input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
-    if (input == NULL) {
-        xmlErrMemory(ctxt, NULL);
-	return(NULL);
-    }
+    input = xmlNewInputMemory(ctxt, URL, buffer, size, encoding,
+                              XML_INPUT_BUF_STATIC);
 
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-	xmlFreeParserInputBuffer(input);
-	return(NULL);
-    }
-
-    inputPush(ctxt, stream);
-    return (xmlDoRead(ctxt, URL, encoding, options, 1));
+    return(xmlCtxtParseDocument(ctxt, input));
 }
 
 /**
  * xmlCtxtReadFd:
  * @ctxt:  an XML parser context
  * @fd:  an open file descriptor
- * @URL:  the base URL to use for the document
- * @encoding:  the document encoding, or NULL
+ * @URL:  base URL (optional)
+ * @encoding:  the document encoding (optional)
  * @options:  a combination of xmlParserOption
  *
- * parse an XML from a file descriptor and build a tree.
- * This reuses the existing @ctxt parser context
+ * Parse an XML document from a file descriptor and build a tree.
+ *
  * NOTE that the file descriptor will not be closed when the
- *      reader is closed or reset.
+ * context is freed or reset.
+ *
+ * @URL is used as base to resolve external entities and for error
+ * reporting.
+ *
+ * See xmlCtxtUseOptions for details.
  *
  * Returns the resulting document tree
  */
@@ -14906,29 +14060,18 @@
 xmlCtxtReadFd(xmlParserCtxtPtr ctxt, int fd,
               const char *URL, const char *encoding, int options)
 {
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
-    if (fd < 0)
-        return (NULL);
     if (ctxt == NULL)
-        return (NULL);
-    xmlInitParser();
+        return(NULL);
 
     xmlCtxtReset(ctxt);
+    xmlCtxtUseOptions(ctxt, options);
 
+    input = xmlNewInputFd(ctxt, URL, fd, encoding, 0);
+    input->buf->closecallback = NULL;
 
-    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
-    if (input == NULL)
-        return (NULL);
-    input->closecallback = NULL;
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-        xmlFreeParserInputBuffer(input);
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (xmlDoRead(ctxt, URL, encoding, options, 1));
+    return(xmlCtxtParseDocument(ctxt, input));
 }
 
 /**
@@ -14944,6 +14087,11 @@
  * parse an XML document from I/O functions and source and build a tree.
  * This reuses the existing @ctxt parser context
  *
+ * @URL is used as base to resolve external entities and for error
+ * reporting.
+ *
+ * See xmlCtxtUseOptions for details.
+ *
  * Returns the resulting document tree
  */
 xmlDocPtr
@@ -14952,30 +14100,16 @@
 	      const char *URL,
               const char *encoding, int options)
 {
-    xmlParserInputBufferPtr input;
-    xmlParserInputPtr stream;
+    xmlParserInputPtr input;
 
-    if (ioread == NULL)
-        return (NULL);
     if (ctxt == NULL)
-        return (NULL);
-    xmlInitParser();
+        return(NULL);
 
     xmlCtxtReset(ctxt);
+    xmlCtxtUseOptions(ctxt, options);
 
-    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
-                                         XML_CHAR_ENCODING_NONE);
-    if (input == NULL) {
-        if (ioclose != NULL)
-            ioclose(ioctx);
-        return (NULL);
-    }
-    stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
-    if (stream == NULL) {
-        xmlFreeParserInputBuffer(input);
-        return (NULL);
-    }
-    inputPush(ctxt, stream);
-    return (xmlDoRead(ctxt, URL, encoding, options, 1));
+    input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0);
+
+    return(xmlCtxtParseDocument(ctxt, input));
 }
 
diff --git a/src/parserInternals.c b/src/parserInternals.c
index 693cfd6..4d3dc7f 100644
--- a/src/parserInternals.c
+++ b/src/parserInternals.c
@@ -35,6 +35,7 @@
 #include <libxml/catalog.h>
 #endif
 #include <libxml/chvalid.h>
+#include <libxml/nanohttp.h>
 
 #define CUR(ctxt) ctxt->input->cur
 #define END(ctxt) ctxt->input->end
@@ -62,7 +63,6 @@
  * @version: the include version number
  *
  * check the compiled lib version against the include one.
- * This can warn or immediately kill the application
  */
 void
 xmlCheckVersion(int version) {
@@ -71,15 +71,11 @@
     xmlInitParser();
 
     if ((myversion / 10000) != (version / 10000)) {
-	xmlGenericError(xmlGenericErrorContext,
-		"Fatal: program compiled against libxml %d using libxml %d\n",
-		(version / 10000), (myversion / 10000));
 	fprintf(stderr,
 		"Fatal: program compiled against libxml %d using libxml %d\n",
 		(version / 10000), (myversion / 10000));
-    }
-    if ((myversion / 100) < (version / 100)) {
-	xmlGenericError(xmlGenericErrorContext,
+    } else if ((myversion / 100) < (version / 100)) {
+	fprintf(stderr,
 		"Warning: program compiled against libxml %d using older %d\n",
 		(version / 100), (myversion / 100));
     }
@@ -94,73 +90,147 @@
 
 
 /**
- * xmlErrMemory:
+ * xmlCtxtSetErrorHandler:
  * @ctxt:  an XML parser context
- * @extra:  extra information
+ * @handler:  error handler
+ * @data:  data for error handler
  *
- * Handle a redefinition of attribute error
+ * Register a callback function that will be called on errors and
+ * warnings. If handler is NULL, the error handler will be deactivated.
+ *
+ * This is the recommended way to collect errors from the parser and
+ * takes precedence over all other error reporting mechanisms.
+ * These are (in order of precedence):
+ *
+ * - per-context structured handler (xmlCtxtSetErrorHandler)
+ * - per-context structured "serror" SAX handler
+ * - global structured handler (xmlSetStructuredErrorFunc)
+ * - per-context generic "error" and "warning" SAX handlers
+ * - global generic handler (xmlSetGenericErrorFunc)
+ * - print to stderr
+ *
+ * Available since 2.13.0.
  */
 void
-xmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra ATTRIBUTE_UNUSED)
+xmlCtxtSetErrorHandler(xmlParserCtxtPtr ctxt, xmlStructuredErrorFunc handler,
+                       void *data)
 {
-    xmlError *lastError = &xmlLastError;
+    if (ctxt == NULL)
+        return;
+    ctxt->errorHandler = handler;
+    ctxt->errorCtxt = data;
+}
 
-    xmlResetLastError();
-    lastError->domain = XML_FROM_PARSER;
-    lastError->code = XML_ERR_NO_MEMORY;
-    lastError->level = XML_ERR_FATAL;
+/**
+ * xmlCtxtErrMemory:
+ * @ctxt:  an XML parser context
+ * @domain:  domain
+ *
+ * Handle an out-of-memory error
+ */
+void
+xmlCtxtErrMemory(xmlParserCtxtPtr ctxt)
+{
+    xmlStructuredErrorFunc schannel = NULL;
+    xmlGenericErrorFunc channel = NULL;
+    void *data;
 
     ctxt->errNo = XML_ERR_NO_MEMORY;
     ctxt->instate = XML_PARSER_EOF; /* TODO: Remove after refactoring */
     ctxt->wellFormed = 0;
     ctxt->disableSAX = 2;
 
-    xmlResetError(&ctxt->lastError);
-    ctxt->lastError.domain = XML_FROM_PARSER;
-    ctxt->lastError.code = XML_ERR_NO_MEMORY;
-    ctxt->lastError.level = XML_ERR_FATAL;
-
-    if ((ctxt->sax->initialized == XML_SAX2_MAGIC) &&
+    if (ctxt->errorHandler) {
+        schannel = ctxt->errorHandler;
+        data = ctxt->errorCtxt;
+    } else if ((ctxt->sax->initialized == XML_SAX2_MAGIC) &&
         (ctxt->sax->serror != NULL)) {
-        ctxt->sax->serror(ctxt->userData, &ctxt->lastError);
-    } else if (xmlStructuredError != NULL) {
-        xmlStructuredError(ctxt->userData, &ctxt->lastError);
+        schannel = ctxt->sax->serror;
+        data = ctxt->userData;
     } else {
-        xmlGenericErrorFunc channel = ctxt->sax->error;
-
-        if ((channel == xmlParserError) ||
-            (channel == xmlParserWarning) ||
-            (channel == xmlParserValidityError) ||
-            (channel == xmlParserValidityWarning))
-            channel = xmlGenericError;
-
-        if (channel != NULL)
-            channel(ctxt->userData, "parser error : out of memory\n");
+        channel = ctxt->sax->error;
+        data = ctxt->userData;
     }
+
+    xmlRaiseMemoryError(schannel, channel, data, XML_FROM_PARSER,
+                        &ctxt->lastError);
+}
+
+/**
+ * xmlCtxtErrIO:
+ * @ctxt:  parser context
+ * @code:  xmlParserErrors code
+ * @uri:  filename or URI (optional)
+ *
+ * If filename is empty, use the one from context input if available.
+ *
+ * Report an IO error to the parser context.
+ */
+void
+xmlCtxtErrIO(xmlParserCtxtPtr ctxt, int code, const char *uri)
+{
+    const char *errstr, *msg, *str1, *str2;
+    xmlErrorLevel level;
+
+    if (ctxt == NULL)
+        return;
+
+    /*
+     * Don't report a well-formedness error if an external entity could
+     * not be found. We assume that inputNr is zero for the document
+     * entity which is somewhat fragile.
+     */
+    if ((ctxt->inputNr > 0) &&
+        ((code == XML_IO_ENOENT) ||
+         (code == XML_IO_NETWORK_ATTEMPT) ||
+         (code == XML_IO_UNKNOWN))) {
+        if (ctxt->validate == 0)
+            level = XML_ERR_WARNING;
+        else
+            level = XML_ERR_ERROR;
+    } else {
+        level = XML_ERR_FATAL;
+    }
+
+    errstr = xmlErrString(code);
+
+    if (uri == NULL) {
+        msg = "%s\n";
+        str1 = errstr;
+        str2 = NULL;
+    } else {
+        msg = "failed to load \"%s\": %s\n";
+        str1 = uri;
+        str2 = errstr;
+    }
+
+    xmlCtxtErr(ctxt, NULL, XML_FROM_IO, code, level,
+               (const xmlChar *) uri, NULL, NULL, 0,
+               msg, str1, str2);
 }
 
 void
-xmlVErrParser(xmlParserCtxtPtr ctxt, xmlNodePtr node,
-              int domain, int code, xmlErrorLevel level,
-              const xmlChar *str1, const xmlChar *str2, const xmlChar *str3,
-              int int1, const char *msg, va_list ap)
+xmlCtxtVErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain,
+            xmlParserErrors code, xmlErrorLevel level,
+            const xmlChar *str1, const xmlChar *str2, const xmlChar *str3,
+            int int1, const char *msg, va_list ap)
 {
     xmlStructuredErrorFunc schannel = NULL;
-    xmlGenericErrorFunc channel;
-    void *data;
+    xmlGenericErrorFunc channel = NULL;
+    void *data = NULL;
     const char *file = NULL;
     int line = 0;
     int col = 0;
     int res;
 
-    if (PARSER_STOPPED(ctxt))
-	return;
-
     if (code == XML_ERR_NO_MEMORY) {
-        xmlErrMemory(ctxt, NULL);
+        xmlCtxtErrMemory(ctxt);
         return;
     }
 
+    if (PARSER_STOPPED(ctxt))
+	return;
+
     if (level == XML_ERR_WARNING) {
         if (ctxt->nbWarnings >= XML_MAX_ERRORS)
             return;
@@ -171,21 +241,29 @@
         ctxt->nbErrors += 1;
     }
 
-    if (ctxt->sax->initialized == XML_SAX2_MAGIC)
-        schannel = ctxt->sax->serror;
-
-    if ((domain == XML_FROM_VALID) || (domain == XML_FROM_DTD)) {
-        if (level == XML_ERR_WARNING)
-            channel = ctxt->vctxt.warning;
-        else
-            channel = ctxt->vctxt.error;
-        data = ctxt->vctxt.userData;
-    } else {
-        if (level == XML_ERR_WARNING)
-            channel = ctxt->sax->warning;
-        else
-            channel = ctxt->sax->error;
-        data = ctxt->userData;
+    if (((ctxt->options & XML_PARSE_NOERROR) == 0) &&
+        ((level != XML_ERR_WARNING) ||
+         ((ctxt->options & XML_PARSE_NOWARNING) == 0))) {
+        if (ctxt->errorHandler) {
+            schannel = ctxt->errorHandler;
+            data = ctxt->errorCtxt;
+        } else if ((ctxt->sax->initialized == XML_SAX2_MAGIC) &&
+            (ctxt->sax->serror != NULL)) {
+            schannel = ctxt->sax->serror;
+            data = ctxt->userData;
+        } else if ((domain == XML_FROM_VALID) || (domain == XML_FROM_DTD)) {
+            if (level == XML_ERR_WARNING)
+                channel = ctxt->vctxt.warning;
+            else
+                channel = ctxt->vctxt.error;
+            data = ctxt->vctxt.userData;
+        } else {
+            if (level == XML_ERR_WARNING)
+                channel = ctxt->sax->warning;
+            else
+                channel = ctxt->sax->error;
+            data = ctxt->userData;
+        }
     }
 
     if (ctxt->input != NULL) {
@@ -206,7 +284,7 @@
                          msg, ap);
 
     if (res < 0) {
-        xmlErrMemory(ctxt, NULL);
+        xmlCtxtErrMemory(ctxt);
         return;
     }
 
@@ -222,55 +300,20 @@
 }
 
 void
-xmlErrParser(xmlParserCtxtPtr ctxt, xmlNodePtr node,
-             int domain, int code, xmlErrorLevel level,
-             const xmlChar *str1, const xmlChar *str2, const xmlChar *str3,
-             int int1, const char *msg, ...)
+xmlCtxtErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain,
+           xmlParserErrors code, xmlErrorLevel level,
+           const xmlChar *str1, const xmlChar *str2, const xmlChar *str3,
+           int int1, const char *msg, ...)
 {
     va_list ap;
 
     va_start(ap, msg);
-    xmlVErrParser(ctxt, node, domain, code, level,
-                  str1, str2, str3, int1, msg, ap);
+    xmlCtxtVErr(ctxt, node, domain, code, level,
+                str1, str2, str3, int1, msg, ap);
     va_end(ap);
 }
 
 /**
- * __xmlErrEncoding:
- * @ctxt:  an XML parser context
- * @xmlerr:  the error number
- * @msg:  the error message
- * @str1:  an string info
- * @str2:  an string info
- *
- * Handle an encoding error
- */
-void
-__xmlErrEncoding(xmlParserCtxtPtr ctxt, xmlParserErrors xmlerr,
-                 const char *msg, const xmlChar * str1, const xmlChar * str2)
-{
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, xmlerr, XML_ERR_FATAL,
-                 str1, str2, NULL, 0, msg, str1, str2);
-}
-
-/**
- * xmlErrInternal:
- * @ctxt:  an XML parser context
- * @msg:  the error message
- * @str:  error information
- *
- * Handle an internal error
- */
-static void LIBXML_ATTR_FORMAT(2,0)
-xmlErrInternal(xmlParserCtxtPtr ctxt, const char *msg, const xmlChar * str)
-{
-    if (ctxt == NULL)
-        return;
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, XML_ERR_INTERNAL_ERROR,
-                 XML_ERR_FATAL, str, NULL, NULL, 0, msg, str);
-}
-
-/**
  * xmlFatalErr:
  * @ctxt:  an XML parser context
  * @error:  the error number
@@ -279,239 +322,29 @@
  * Handle a fatal parser error, i.e. violating Well-Formedness constraints
  */
 void
-xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info)
+xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors code, const char *info)
 {
     const char *errmsg;
+    xmlErrorLevel level;
 
-    switch (error) {
-        case XML_ERR_INVALID_HEX_CHARREF:
-            errmsg = "CharRef: invalid hexadecimal value";
-            break;
-        case XML_ERR_INVALID_DEC_CHARREF:
-            errmsg = "CharRef: invalid decimal value";
-            break;
-        case XML_ERR_INVALID_CHARREF:
-            errmsg = "CharRef: invalid value";
-            break;
-        case XML_ERR_INTERNAL_ERROR:
-            errmsg = "internal error";
-            break;
-        case XML_ERR_PEREF_AT_EOF:
-            errmsg = "PEReference at end of document";
-            break;
-        case XML_ERR_PEREF_IN_PROLOG:
-            errmsg = "PEReference in prolog";
-            break;
-        case XML_ERR_PEREF_IN_EPILOG:
-            errmsg = "PEReference in epilog";
-            break;
-        case XML_ERR_PEREF_NO_NAME:
-            errmsg = "PEReference: no name";
-            break;
-        case XML_ERR_PEREF_SEMICOL_MISSING:
-            errmsg = "PEReference: expecting ';'";
-            break;
-        case XML_ERR_ENTITY_LOOP:
-            errmsg = "Detected an entity reference loop";
-            break;
-        case XML_ERR_ENTITY_NOT_STARTED:
-            errmsg = "EntityValue: \" or ' expected";
-            break;
-        case XML_ERR_ENTITY_PE_INTERNAL:
-            errmsg = "PEReferences forbidden in internal subset";
-            break;
-        case XML_ERR_ENTITY_NOT_FINISHED:
-            errmsg = "EntityValue: \" or ' expected";
-            break;
-        case XML_ERR_ATTRIBUTE_NOT_STARTED:
-            errmsg = "AttValue: \" or ' expected";
-            break;
-        case XML_ERR_LT_IN_ATTRIBUTE:
-            errmsg = "Unescaped '<' not allowed in attributes values";
-            break;
-        case XML_ERR_LITERAL_NOT_STARTED:
-            errmsg = "SystemLiteral \" or ' expected";
-            break;
-        case XML_ERR_LITERAL_NOT_FINISHED:
-            errmsg = "Unfinished System or Public ID \" or ' expected";
-            break;
-        case XML_ERR_MISPLACED_CDATA_END:
-            errmsg = "Sequence ']]>' not allowed in content";
-            break;
-        case XML_ERR_URI_REQUIRED:
-            errmsg = "SYSTEM or PUBLIC, the URI is missing";
-            break;
-        case XML_ERR_PUBID_REQUIRED:
-            errmsg = "PUBLIC, the Public Identifier is missing";
-            break;
-        case XML_ERR_HYPHEN_IN_COMMENT:
-            errmsg = "Comment must not contain '--' (double-hyphen)";
-            break;
-        case XML_ERR_PI_NOT_STARTED:
-            errmsg = "xmlParsePI : no target name";
-            break;
-        case XML_ERR_RESERVED_XML_NAME:
-            errmsg = "Invalid PI name";
-            break;
-        case XML_ERR_NOTATION_NOT_STARTED:
-            errmsg = "NOTATION: Name expected here";
-            break;
-        case XML_ERR_NOTATION_NOT_FINISHED:
-            errmsg = "'>' required to close NOTATION declaration";
-            break;
-        case XML_ERR_VALUE_REQUIRED:
-            errmsg = "Entity value required";
-            break;
-        case XML_ERR_URI_FRAGMENT:
-            errmsg = "Fragment not allowed";
-            break;
-        case XML_ERR_ATTLIST_NOT_STARTED:
-            errmsg = "'(' required to start ATTLIST enumeration";
-            break;
-        case XML_ERR_NMTOKEN_REQUIRED:
-            errmsg = "NmToken expected in ATTLIST enumeration";
-            break;
-        case XML_ERR_ATTLIST_NOT_FINISHED:
-            errmsg = "')' required to finish ATTLIST enumeration";
-            break;
-        case XML_ERR_MIXED_NOT_STARTED:
-            errmsg = "MixedContentDecl : '|' or ')*' expected";
-            break;
-        case XML_ERR_PCDATA_REQUIRED:
-            errmsg = "MixedContentDecl : '#PCDATA' expected";
-            break;
-        case XML_ERR_ELEMCONTENT_NOT_STARTED:
-            errmsg = "ContentDecl : Name or '(' expected";
-            break;
-        case XML_ERR_ELEMCONTENT_NOT_FINISHED:
-            errmsg = "ContentDecl : ',' '|' or ')' expected";
-            break;
-        case XML_ERR_PEREF_IN_INT_SUBSET:
-            errmsg =
-                "PEReference: forbidden within markup decl in internal subset";
-            break;
-        case XML_ERR_GT_REQUIRED:
-            errmsg = "expected '>'";
-            break;
-        case XML_ERR_CONDSEC_INVALID:
-            errmsg = "XML conditional section '[' expected";
-            break;
-        case XML_ERR_EXT_SUBSET_NOT_FINISHED:
-            errmsg = "Content error in the external subset";
-            break;
-        case XML_ERR_CONDSEC_INVALID_KEYWORD:
-            errmsg =
-                "conditional section INCLUDE or IGNORE keyword expected";
-            break;
-        case XML_ERR_CONDSEC_NOT_FINISHED:
-            errmsg = "XML conditional section not closed";
-            break;
-        case XML_ERR_XMLDECL_NOT_STARTED:
-            errmsg = "Text declaration '<?xml' required";
-            break;
-        case XML_ERR_XMLDECL_NOT_FINISHED:
-            errmsg = "parsing XML declaration: '?>' expected";
-            break;
-        case XML_ERR_EXT_ENTITY_STANDALONE:
-            errmsg = "external parsed entities cannot be standalone";
-            break;
-        case XML_ERR_ENTITYREF_SEMICOL_MISSING:
-            errmsg = "EntityRef: expecting ';'";
-            break;
-        case XML_ERR_DOCTYPE_NOT_FINISHED:
-            errmsg = "DOCTYPE improperly terminated";
-            break;
-        case XML_ERR_LTSLASH_REQUIRED:
-            errmsg = "EndTag: '</' not found";
-            break;
-        case XML_ERR_EQUAL_REQUIRED:
-            errmsg = "expected '='";
-            break;
-        case XML_ERR_STRING_NOT_CLOSED:
-            errmsg = "String not closed expecting \" or '";
-            break;
-        case XML_ERR_STRING_NOT_STARTED:
-            errmsg = "String not started expecting ' or \"";
-            break;
-        case XML_ERR_ENCODING_NAME:
-            errmsg = "Invalid XML encoding name";
-            break;
-        case XML_ERR_STANDALONE_VALUE:
-            errmsg = "standalone accepts only 'yes' or 'no'";
-            break;
-        case XML_ERR_DOCUMENT_EMPTY:
-            errmsg = "Document is empty";
-            break;
-        case XML_ERR_DOCUMENT_END:
-            errmsg = "Extra content at the end of the document";
-            break;
-        case XML_ERR_NOT_WELL_BALANCED:
-            errmsg = "chunk is not well balanced";
-            break;
-        case XML_ERR_EXTRA_CONTENT:
-            errmsg = "extra content at the end of well balanced chunk";
-            break;
-        case XML_ERR_VERSION_MISSING:
-            errmsg = "Malformed declaration expecting version";
-            break;
-        case XML_ERR_NAME_TOO_LONG:
-            errmsg = "Name too long";
-            break;
-        case XML_ERR_INVALID_ENCODING:
-            errmsg = "Invalid bytes in character encoding";
-            break;
-        case XML_IO_UNKNOWN:
-            errmsg = "I/O error";
-            break;
-        case XML_ERR_RESOURCE_LIMIT:
-            errmsg = "Resource limit exceeded";
-            break;
-        case XML_ERR_ARGUMENT:
-            errmsg = "Invalid argument";
-            break;
-        case XML_ERR_SYSTEM:
-            errmsg = "Out of system resources";
-            break;
-        case XML_ERR_REDECL_PREDEF_ENTITY:
-            errmsg = "Invalid redeclaration of predefined entity";
-            break;
-#if 0
-        case:
-            errmsg = "";
-            break;
-#endif
-        default:
-            errmsg = "Unregistered error message";
-    }
+    if (code == XML_ERR_UNSUPPORTED_ENCODING)
+        level = XML_ERR_WARNING;
+    else
+        level = XML_ERR_FATAL;
+
+    errmsg = xmlErrString(code);
 
     if (info == NULL) {
-        xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
-                     NULL, NULL, NULL, 0, "%s\n", errmsg);
+        xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, code, level,
+                   NULL, NULL, NULL, 0, "%s\n", errmsg);
     } else {
-        xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
-                     (const xmlChar *) info, NULL, NULL, 0,
-                     "%s: %s\n", errmsg, info);
+        xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, code, level,
+                   (const xmlChar *) info, NULL, NULL, 0,
+                   "%s: %s\n", errmsg, info);
     }
 }
 
 /**
- * xmlErrEncodingInt:
- * @ctxt:  an XML parser context
- * @error:  the error number
- * @msg:  the error message
- * @val:  an integer value
- *
- * n encoding error
- */
-static void LIBXML_ATTR_FORMAT(3,0)
-xmlErrEncodingInt(xmlParserCtxtPtr ctxt, xmlParserErrors error,
-                  const char *msg, int val)
-{
-    xmlErrParser(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL,
-                 NULL, NULL, NULL, val, msg, val);
-}
-
-/**
  * xmlIsLetter:
  * @c:  an unicode character (int)
  *
@@ -575,21 +408,25 @@
 xmlParserGrow(xmlParserCtxtPtr ctxt) {
     xmlParserInputPtr in = ctxt->input;
     xmlParserInputBufferPtr buf = in->buf;
-    ptrdiff_t curEnd = in->end - in->cur;
-    ptrdiff_t curBase = in->cur - in->base;
+    size_t curEnd = in->end - in->cur;
+    size_t curBase = in->cur - in->base;
+    size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ?
+                       XML_MAX_HUGE_LENGTH :
+                       XML_MAX_LOOKUP_LIMIT;
     int ret;
 
     if (buf == NULL)
         return(0);
     /* Don't grow push parser buffer. */
-    if ((ctxt->progressive) && (ctxt->inputNr <= 1))
+    if (PARSER_PROGRESSIVE(ctxt))
+        return(0);
+    /* Don't grow memory buffers. */
+    if ((buf->encoder == NULL) && (buf->readcallback == NULL))
         return(0);
     if (buf->error != 0)
         return(-1);
 
-    if (((curEnd > XML_MAX_LOOKUP_LIMIT) ||
-         (curBase > XML_MAX_LOOKUP_LIMIT)) &&
-        ((ctxt->options & XML_PARSE_HUGE) == 0)) {
+    if (curBase > maxLength) {
         xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT,
                     "Buffer size limit exceeded, try XML_PARSE_HUGE\n");
         xmlHaltParser(ctxt);
@@ -603,7 +440,7 @@
     xmlBufUpdateInput(buf->buffer, in, curBase);
 
     if (ret < 0) {
-        xmlFatalErr(ctxt, buf->error, NULL);
+        xmlCtxtErrIO(ctxt, buf->error, NULL);
     }
 
     return(ret);
@@ -633,6 +470,10 @@
     if (in->cur == NULL) return(-1);
     if (in->buf->buffer == NULL) return(-1);
 
+    /* Don't grow memory buffers. */
+    if ((in->buf->encoder == NULL) && (in->buf->readcallback == NULL))
+        return(0);
+
     indx = in->cur - in->base;
     if (xmlBufUse(in->buf->buffer) > (unsigned int) indx + INPUT_CHUNK) {
         return(0);
@@ -666,6 +507,11 @@
 
     if (buf == NULL)
         return;
+    /* Don't shrink pull parser memory buffers. */
+    if ((!PARSER_PROGRESSIVE(ctxt)) &&
+        (buf->encoder == NULL) &&
+        (buf->readcallback == NULL))
+        return;
 
     used = in->cur - in->base;
     /*
@@ -836,21 +682,7 @@
 encoding_error:
     /* Only report the first error */
     if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) {
-        if ((ctxt == NULL) || (ctxt->input == NULL) ||
-            (ctxt->input->end - ctxt->input->cur < 4)) {
-            __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR,
-                         "Input is not proper UTF-8, indicate encoding !\n",
-                         NULL, NULL);
-        } else {
-            char buffer[150];
-
-            snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
-                            ctxt->input->cur[0], ctxt->input->cur[1],
-                            ctxt->input->cur[2], ctxt->input->cur[3]);
-            __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR,
-                         "Input is not proper UTF-8, indicate encoding !\n%s",
-                         BAD_CAST buffer, NULL);
-        }
+        xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL);
         ctxt->input->flags |= XML_INPUT_ENCODING_ERROR;
     }
     ctxt->input->cur++;
@@ -923,8 +755,8 @@
                      * TODO: Null bytes should be handled by callers,
                      * but this can be tricky.
                      */
-                    xmlErrEncodingInt(ctxt, XML_ERR_INVALID_CHAR,
-                            "Char 0x0 out of allowed range\n", c);
+                    xmlFatalErr(ctxt, XML_ERR_INVALID_CHAR,
+                            "Char 0x0 out of allowed range\n");
                 }
             } else {
                 *len = 1;
@@ -986,20 +818,7 @@
 encoding_error:
     /* Only report the first error */
     if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) {
-        if (ctxt->input->end - ctxt->input->cur < 4) {
-            __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR,
-                         "Input is not proper UTF-8, indicate encoding !\n",
-                         NULL, NULL);
-        } else {
-            char buffer[150];
-
-            snprintf(&buffer[0], 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
-                            ctxt->input->cur[0], ctxt->input->cur[1],
-                            ctxt->input->cur[2], ctxt->input->cur[3]);
-            __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR,
-                         "Input is not proper UTF-8, indicate encoding !\n%s",
-                         BAD_CAST buffer, NULL);
-        }
+        xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL);
         ctxt->input->flags |= XML_INPUT_ENCODING_ERROR;
     }
     *len = 1;
@@ -1073,9 +892,10 @@
 	else if (val < 0x10000) { *out++= (val >> 12) | 0xE0;  bits=  6;}
 	else if (val < 0x110000)  { *out++= (val >> 18) | 0xF0;  bits=  12; }
 	else {
-	    xmlErrEncodingInt(NULL, XML_ERR_INVALID_CHAR,
-		    "Internal error, xmlCopyCharMultiByte 0x%X out of bound\n",
-			      val);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+            fprintf(stderr, "xmlCopyCharMultiByte: codepoint out of range\n");
+            abort();
+#endif
 	    return(0);
 	}
 	for ( ; bits >= 0; bits-= 6)
@@ -1169,7 +989,8 @@
                 break;
             out[i] = 0;
             xmlCharEncCloseFunc(handler);
-            res = xmlOpenCharEncodingHandler((char *) out + start, &handler);
+            res = xmlOpenCharEncodingHandler((char *) out + start,
+                                             /* output */ 0, &handler);
             if (res != 0)
                 return(res);
             *hout = handler;
@@ -1227,14 +1048,9 @@
     }
 
     if (res != 0) {
-        if (res == XML_ERR_UNSUPPORTED_ENCODING) {
-            const char *name = xmlGetCharEncodingName(enc);
+        const char *name = xmlGetCharEncodingName(enc);
 
-            __xmlErrEncoding(ctxt, res, "encoding not supported: %s\n",
-                             BAD_CAST (name ? name : "<null>"), NULL);
-        } else {
-            xmlFatalErr(ctxt, res, NULL);
-        }
+        xmlFatalErr(ctxt, res, (name ? name : "<null>"));
         return(-1);
     }
 
@@ -1249,6 +1065,32 @@
 
 /**
  * xmlSwitchEncodingName:
+ * @ctxt:  the parser context, only for error reporting
+ * @input:  the input strea,
+ * @encoding:  the encoding name
+ *
+ * Returns 0 in case of success, -1 otherwise
+ */
+static int
+xmlSwitchInputEncodingName(xmlParserCtxtPtr ctxt, xmlParserInputPtr input,
+                           const char *encoding) {
+    xmlCharEncodingHandlerPtr handler;
+    int res;
+
+    if (encoding == NULL)
+        return(-1);
+
+    res = xmlOpenCharEncodingHandler(encoding, /* output */ 0, &handler);
+    if (res != 0) {
+        xmlFatalErr(ctxt, res, encoding);
+        return(-1);
+    }
+
+    return(xmlSwitchInputEncoding(ctxt, input, handler));
+}
+
+/**
+ * xmlSwitchEncodingName:
  * @ctxt:  the parser context
  * @encoding:  the encoding name
  *
@@ -1264,25 +1106,12 @@
  */
 int
 xmlSwitchEncodingName(xmlParserCtxtPtr ctxt, const char *encoding) {
-    xmlCharEncodingHandlerPtr handler;
-    int res;
-
-    res = xmlOpenCharEncodingHandler(encoding, &handler);
-    if (res != 0) {
-        if (res == XML_ERR_UNSUPPORTED_ENCODING)
-            __xmlErrEncoding(ctxt, res, "Unsupported encoding: %s\n",
-                             (const xmlChar *) encoding, NULL);
-        else
-            xmlFatalErr(ctxt, res, NULL);
-        return(-1);
-    }
-
-    return(xmlSwitchInputEncoding(ctxt, ctxt->input, handler));
+    return(xmlSwitchInputEncodingName(ctxt, ctxt->input, encoding));
 }
 
 /**
  * xmlSwitchInputEncoding:
- * @ctxt:  the parser context
+ * @ctxt:  the parser context, only for error reporting
  * @input:  the input stream
  * @handler:  the encoding handler
  *
@@ -1340,8 +1169,15 @@
      * Is there already some content down the pipe to convert ?
      */
     if (xmlBufIsEmpty(in->buffer) == 0) {
+        xmlBufPtr buf;
         size_t processed;
 
+        buf = xmlBufCreate();
+        if (buf == NULL) {
+            xmlCtxtErrMemory(ctxt);
+            return(-1);
+        }
+
         /*
          * Shrink the current input buffer.
          * Move it as the raw buffer and create a new input buffer
@@ -1350,21 +1186,15 @@
         xmlBufShrink(in->buffer, processed);
         input->consumed += processed;
         in->raw = in->buffer;
-        in->buffer = xmlBufCreate();
-        if (in->buffer == NULL) {
-            xmlErrMemory(ctxt, NULL);
-            return(-1);
-        }
+        in->buffer = buf;
         in->rawconsumed = processed;
 
         nbchars = xmlCharEncInput(in);
         xmlBufResetInput(in->buffer, input);
         if (nbchars == XML_ENC_ERR_MEMORY) {
-            xmlErrMemory(ctxt, NULL);
+            xmlCtxtErrMemory(ctxt);
         } else if (nbchars < 0) {
-            xmlErrInternal(ctxt,
-                           "switching encoding: encoder error\n",
-                           NULL);
+            xmlCtxtErrIO(ctxt, in->error, NULL);
             xmlHaltParser(ctxt);
             return (-1);
         }
@@ -1558,7 +1388,7 @@
                 xmlFree(encoding);
                 encoding = xmlStrdup(BAD_CAST autoEnc);
                 if (encoding == NULL)
-                    xmlErrMemory(ctxt, NULL);
+                    xmlCtxtErrMemory(ctxt);
             }
         }
     }
@@ -1585,7 +1415,6 @@
     if (input == NULL) return;
 
     if (input->filename != NULL) xmlFree((char *) input->filename);
-    if (input->directory != NULL) xmlFree((char *) input->directory);
     if (input->version != NULL) xmlFree((char *) input->version);
     if ((input->free != NULL) && (input->base != NULL))
         input->free((xmlChar *) input->base);
@@ -1608,7 +1437,7 @@
 
     input = (xmlParserInputPtr) xmlMalloc(sizeof(xmlParserInput));
     if (input == NULL) {
-        xmlErrMemory(ctxt,  "couldn't allocate a new input stream\n");
+        xmlCtxtErrMemory(ctxt);
 	return(NULL);
     }
     memset(input, 0, sizeof(xmlParserInput));
@@ -1622,7 +1451,7 @@
      */
     if (ctxt != NULL) {
         if (input->id >= INT_MAX) {
-            xmlErrMemory(ctxt, "Input ID overflow\n");
+            xmlCtxtErrMemory(ctxt);
             return(NULL);
         }
         input->id = ctxt->input_id++;
@@ -1632,37 +1461,338 @@
 }
 
 /**
+ * xmlNewInputURL:
+ * @ctxt:  parser context
+ * @url:  filename or URL
+ * @publicId:  publid ID from doctype (optional)
+ * @encoding:  character encoding (optional)
+ * @flags:  unused, pass 0
+ *
+ * Creates a new parser input from the filesystem, the network or
+ * a user-defined resource loader.
+ *
+ * @url is a filename or URL. If if contains the substring "://",
+ * it is assumed to be a Legacy Extended IRI. Otherwise, it is
+ * treated as a filesystem path.
+ *
+ * @publicId is an optional XML public ID, typically from a doctype
+ * declaration. It is used for catalog lookups.
+ *
+ * If @encoding is specified, it will override any encodings found
+ * in XML declarations, text declarations, BOMs, etc. Pass NULL
+ * for auto-detection.
+ *
+ * The following resource loaders will be called if they were
+ * registered (in order of precedence):
+ *
+ * - the global external entity loader set with
+ *   xmlSetExternalEntityLoader
+ * - the per-thread xmlParserInputBufferCreateFilenameFunc set with
+ *   xmlParserInputBufferCreateFilenameDefault
+ * - the default loader which will return
+ *   - the result from a matching global input callback set with
+ *     xmlRegisterInputCallbacks
+ *   - a HTTP resource if support is compiled in.
+ *   - a file opened from the filesystem, with automatic detection
+ *     of compressed files if support is compiled in.
+ *
+ * The returned input can be passed to xmlCtxtParseDocument or
+ * htmlCtxtParseDocument.
+ *
+ * This function should not be invoked from user-defined resource
+ * loaders to avoid infinite loops.
+ *
+ * Returns a new parser input.
+ */
+xmlParserInputPtr
+xmlNewInputURL(xmlParserCtxtPtr ctxt, const char *url, const char *publicId,
+               const char *encoding, int flags ATTRIBUTE_UNUSED) {
+    xmlParserInputPtr input;
+
+    if ((ctxt == NULL) || (url == NULL))
+	return(NULL);
+
+    input = xmlLoadExternalEntity(url, publicId, ctxt);
+    if (input == NULL)
+        return(NULL);
+
+    if (encoding != NULL)
+        xmlSwitchInputEncodingName(ctxt, input, encoding);
+
+    return(input);
+}
+
+/**
+ * xmlNewInputInternal:
+ * @ctxt:  parser context
+ * @buf:  parser input buffer
+ * @filename:  filename or URL
+ * @encoding:  character encoding (optional)
+ *
+ * Internal helper function.
+ *
+ * Returns a new parser input.
+ */
+static xmlParserInputPtr
+xmlNewInputInternal(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr buf,
+                    const char *filename, const char *encoding) {
+    xmlParserInputPtr input;
+
+    input = xmlNewInputStream(ctxt);
+    if (input == NULL) {
+	xmlFreeParserInputBuffer(buf);
+	return(NULL);
+    }
+
+    input->buf = buf;
+    xmlBufResetInput(input->buf->buffer, input);
+
+    if (filename != NULL) {
+        input->filename = xmlMemStrdup(filename);
+        if (input->filename == NULL) {
+            xmlCtxtErrMemory(ctxt);
+            xmlFreeInputStream(input);
+            return(NULL);
+        }
+    }
+
+    if (encoding != NULL)
+        xmlSwitchInputEncodingName(ctxt, input, encoding);
+
+    return(input);
+}
+
+/**
+ * xmlNewInputMemory:
+ * @ctxt:  parser context
+ * @url:  base URL (optional)
+ * @mem:  pointer to char array
+ * @size:  size of array
+ * @encoding:  character encoding (optional)
+ * @flags:  optimization hints
+ *
+ * Creates a new parser input to read from a memory area.
+ *
+ * @url is used as base to resolve external entities and for
+ * error reporting.
+ *
+ * If the XML_INPUT_BUF_STATIC flag is set, the memory area must
+ * stay unchanged until parsing has finished. This can avoid
+ * temporary copies.
+ *
+ * If the XML_INPUT_BUF_ZERO_TERMINATED flag is set, the memory
+ * area must contain a zero byte after the buffer at position @size.
+ * This can avoid temporary copies.
+ *
+ * Returns a new parser input.
+ */
+xmlParserInputPtr
+xmlNewInputMemory(xmlParserCtxtPtr ctxt, const char *url,
+                  const void *mem, size_t size,
+                  const char *encoding, int flags) {
+    xmlParserInputBufferPtr buf;
+
+    if ((ctxt == NULL) || (mem == NULL))
+	return(NULL);
+
+    buf = xmlNewInputBufferMemory(mem, size, flags, XML_CHAR_ENCODING_NONE);
+    if (buf == NULL) {
+	xmlCtxtErrMemory(ctxt);
+        return(NULL);
+    }
+
+    return(xmlNewInputInternal(ctxt, buf, url, encoding));
+}
+
+/**
+ * xmlNewInputString:
+ * @ctxt:  parser context
+ * @url:  base URL (optional)
+ * @str:  zero-terminated string
+ * @encoding:  character encoding (optional)
+ * @flags:  optimization hints
+ *
+ * Creates a new parser input to read from a zero-terminated string.
+ *
+ * @url is used as base to resolve external entities and for
+ * error reporting.
+ *
+ * If the XML_INPUT_BUF_STATIC flag is set, the string must
+ * stay unchanged until parsing has finished. This can avoid
+ * temporary copies.
+ *
+ * Returns a new parser input.
+ */
+xmlParserInputPtr
+xmlNewInputString(xmlParserCtxtPtr ctxt, const char *url,
+                  const char *str, const char *encoding, int flags) {
+    xmlParserInputBufferPtr buf;
+
+    if ((ctxt == NULL) || (str == NULL))
+	return(NULL);
+
+    buf = xmlNewInputBufferString(str, flags);
+    if (buf == NULL) {
+	xmlCtxtErrMemory(ctxt);
+        return(NULL);
+    }
+
+    return(xmlNewInputInternal(ctxt, buf, url, encoding));
+}
+
+/**
+ * xmlNewInputFd:
+ * @ctxt:  parser context
+ * @url:  base URL (optional)
+ * @fd:  file descriptor
+ * @encoding:  character encoding (optional)
+ * @flags:  unused, pass 0
+ *
+ * Creates a new parser input to read from a zero-terminated string.
+ *
+ * @url is used as base to resolve external entities and for
+ * error reporting.
+ *
+ * @fd is closed after parsing has finished.
+ *
+ * Returns a new parser input.
+ */
+xmlParserInputPtr
+xmlNewInputFd(xmlParserCtxtPtr ctxt, const char *url,
+              int fd, const char *encoding, int flags ATTRIBUTE_UNUSED) {
+    xmlParserInputBufferPtr buf;
+
+    if ((ctxt == NULL) || (fd < 0))
+	return(NULL);
+
+    buf = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
+    if (buf == NULL) {
+	xmlCtxtErrMemory(ctxt);
+        return(NULL);
+    }
+
+    return(xmlNewInputInternal(ctxt, buf, url, encoding));
+}
+
+/**
+ * xmlNewInputIO:
+ * @ctxt:  parser context
+ * @url:  base URL (optional)
+ * @ioRead:  read callback
+ * @ioClose:  close callback (optional)
+ * @ioCtxt:  IO context
+ * @encoding:  character encoding (optional)
+ * @flags:  unused, pass 0
+ *
+ * Creates a new parser input to read from input callbacks and
+ * cintext.
+ *
+ * @url is used as base to resolve external entities and for
+ * error reporting.
+ *
+ * @ioRead is called to read new data into a provided buffer.
+ * It must return the number of bytes written into the buffer
+ * ot a negative xmlParserErrors code on failure.
+ *
+ * @ioClose is called after parsing has finished.
+ *
+ * @ioCtxt is an opaque pointer passed to the callbacks.
+ *
+ * Returns a new parser input.
+ */
+xmlParserInputPtr
+xmlNewInputIO(xmlParserCtxtPtr ctxt, const char *url,
+              xmlInputReadCallback ioRead, xmlInputCloseCallback ioClose,
+              void *ioCtxt,
+              const char *encoding, int flags ATTRIBUTE_UNUSED) {
+    xmlParserInputBufferPtr buf;
+
+    if ((ctxt == NULL) || (ioRead == NULL))
+	return(NULL);
+
+    buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
+    if (buf == NULL) {
+        xmlCtxtErrMemory(ctxt);
+        if (ioClose != NULL)
+            ioClose(ioCtxt);
+        return(NULL);
+    }
+
+    buf->context = ioCtxt;
+    buf->readcallback = ioRead;
+    buf->closecallback = ioClose;
+
+    return(xmlNewInputInternal(ctxt, buf, url, encoding));
+}
+
+/**
+ * xmlNewInputPush:
+ * @ctxt:  parser context
+ * @url:  base URL (optional)
+ * @chunk:  pointer to char array
+ * @size:  size of array
+ * @encoding:  character encoding (optional)
+ *
+ * Creates a new parser input for a push parser.
+ *
+ * Returns a new parser input.
+ */
+xmlParserInputPtr
+xmlNewInputPush(xmlParserCtxtPtr ctxt, const char *url,
+                const char *chunk, int size, const char *encoding) {
+    xmlParserInputBufferPtr buf;
+    xmlParserInputPtr input;
+
+    buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
+    if (buf == NULL) {
+        xmlCtxtErrMemory(ctxt);
+        return(NULL);
+    }
+
+    input = xmlNewInputInternal(ctxt, buf, url, encoding);
+    if (input == NULL)
+	return(NULL);
+
+    input->flags |= XML_INPUT_PROGRESSIVE;
+
+    if ((size > 0) && (chunk != NULL)) {
+        int res;
+
+	res = xmlParserInputBufferPush(input->buf, size, chunk);
+        xmlBufResetInput(input->buf->buffer, input);
+        if (res < 0) {
+            xmlCtxtErrIO(ctxt, input->buf->error, NULL);
+            xmlFreeInputStream(input);
+            return(NULL);
+        }
+    }
+
+    return(input);
+}
+
+/**
  * xmlNewIOInputStream:
  * @ctxt:  an XML parser context
  * @input:  an I/O Input
  * @enc:  the charset encoding if known
  *
+ * DEPRECATED: Use xmlNewInputURL, xmlNewInputMemory, etc.
+ *
  * Create a new input stream structure encapsulating the @input into
  * a stream suitable for the parser.
  *
  * Returns the new input stream or NULL
  */
 xmlParserInputPtr
-xmlNewIOInputStream(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr input,
+xmlNewIOInputStream(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr buf,
 	            xmlCharEncoding enc) {
-    xmlParserInputPtr inputStream;
+    const char *encoding;
 
-    if (input == NULL) return(NULL);
-    if (xmlParserDebugEntities)
-	xmlGenericError(xmlGenericErrorContext, "new input from I/O\n");
-    inputStream = xmlNewInputStream(ctxt);
-    if (inputStream == NULL) {
-	return(NULL);
-    }
-    inputStream->filename = NULL;
-    inputStream->buf = input;
-    xmlBufResetInput(inputStream->buf->buffer, inputStream);
+    if (buf == NULL)
+        return(NULL);
 
-    if (enc != XML_CHAR_ENCODING_NONE) {
-        xmlSwitchEncoding(ctxt, enc);
-    }
-
-    return(inputStream);
+    encoding = xmlGetCharEncodingName(enc);
+    return(xmlNewInputInternal(ctxt, buf, NULL, encoding));
 }
 
 /**
@@ -1677,61 +1807,29 @@
  * Returns the new input stream or NULL
  */
 xmlParserInputPtr
-xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
+xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) {
     xmlParserInputPtr input;
 
-    if (entity == NULL) {
-        xmlErrInternal(ctxt, "xmlNewEntityInputStream entity = NULL\n",
-	               NULL);
+    if ((ctxt == NULL) || (ent == NULL))
 	return(NULL);
+
+    if (ent->content != NULL) {
+        input = xmlNewInputString(ctxt, NULL, (const char *) ent->content,
+                                  NULL, XML_INPUT_BUF_STATIC);
+    } else if (ent->URI != NULL) {
+        input = xmlLoadExternalEntity((char *) ent->URI,
+                                      (char *) ent->ExternalID, ctxt);
+    } else {
+        input = xmlNewInputMemory(ctxt, NULL, "", 0, NULL,
+                                  XML_INPUT_BUF_STATIC |
+                                  XML_INPUT_BUF_ZERO_TERMINATED);
     }
-    if (xmlParserDebugEntities)
-	xmlGenericError(xmlGenericErrorContext,
-		"new input from entity: %s\n", entity->name);
-    if (entity->content == NULL) {
-	switch (entity->etype) {
-            case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
-	        xmlErrInternal(ctxt, "Cannot parse entity %s\n",
-		               entity->name);
-                break;
-            case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
-            case XML_EXTERNAL_PARAMETER_ENTITY:
-		input = xmlLoadExternalEntity((char *) entity->URI,
-		       (char *) entity->ExternalID, ctxt);
-                if (input != NULL)
-                    input->entity = entity;
-                return(input);
-            case XML_INTERNAL_GENERAL_ENTITY:
-	        xmlErrInternal(ctxt,
-		      "Internal entity %s without content !\n",
-		               entity->name);
-                break;
-            case XML_INTERNAL_PARAMETER_ENTITY:
-	        xmlErrInternal(ctxt,
-		      "Internal parameter entity %s without content !\n",
-		               entity->name);
-                break;
-            case XML_INTERNAL_PREDEFINED_ENTITY:
-	        xmlErrInternal(ctxt,
-		      "Predefined entity %s without content !\n",
-		               entity->name);
-                break;
-	}
-	return(NULL);
-    }
-    input = xmlNewInputStream(ctxt);
-    if (input == NULL) {
-	return(NULL);
-    }
-    if (entity->URI != NULL)
-	input->filename = (char *) xmlStrdup((xmlChar *) entity->URI);
-    input->base = entity->content;
-    if (entity->length == 0)
-        entity->length = xmlStrlen(entity->content);
-    input->cur = entity->content;
-    input->length = entity->length;
-    input->end = &entity->content[input->length];
-    input->entity = entity;
+
+    if (input == NULL)
+        return(NULL);
+
+    input->entity = ent;
+
     return(input);
 }
 
@@ -1740,36 +1838,162 @@
  * @ctxt:  an XML parser context
  * @buffer:  an memory buffer
  *
+ * DEPRECATED: Use xmlNewInputString.
+ *
  * Create a new input stream based on a memory buffer.
+ *
  * Returns the new input stream
  */
 xmlParserInputPtr
 xmlNewStringInputStream(xmlParserCtxtPtr ctxt, const xmlChar *buffer) {
-    xmlParserInputPtr input;
-    xmlParserInputBufferPtr buf;
+    return(xmlNewInputString(ctxt, NULL, (const char *) buffer, NULL, 0));
+}
 
-    if (buffer == NULL) {
-        xmlErrInternal(ctxt, "xmlNewStringInputStream string = NULL\n",
-	               NULL);
-	return(NULL);
+
+/****************************************************************
+ *								*
+ *		External entities loading			*
+ *								*
+ ****************************************************************/
+
+#ifdef LIBXML_CATALOG_ENABLED
+
+/**
+ * xmlResolveResourceFromCatalog:
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * Resolves the URL and ID against the appropriate catalog.
+ * This function is used by xmlDefaultExternalEntityLoader and
+ * xmlNoNetExternalEntityLoader.
+ *
+ * Returns a new allocated URL, or NULL.
+ */
+static xmlChar *
+xmlResolveResourceFromCatalog(const char *URL, const char *ID,
+                              xmlParserCtxtPtr ctxt) {
+    xmlChar *resource = NULL;
+    xmlCatalogAllow pref;
+
+    /*
+     * If the resource doesn't exists as a file,
+     * try to load it from the resource pointed in the catalogs
+     */
+    pref = xmlCatalogGetDefaults();
+
+    if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
+	/*
+	 * Do a local lookup
+	 */
+	if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
+	    ((pref == XML_CATA_ALLOW_ALL) ||
+	     (pref == XML_CATA_ALLOW_DOCUMENT))) {
+	    resource = xmlCatalogLocalResolve(ctxt->catalogs,
+					      (const xmlChar *)ID,
+					      (const xmlChar *)URL);
+        }
+	/*
+	 * Try a global lookup
+	 */
+	if ((resource == NULL) &&
+	    ((pref == XML_CATA_ALLOW_ALL) ||
+	     (pref == XML_CATA_ALLOW_GLOBAL))) {
+	    resource = xmlCatalogResolve((const xmlChar *)ID,
+					 (const xmlChar *)URL);
+	}
+	if ((resource == NULL) && (URL != NULL))
+	    resource = xmlStrdup((const xmlChar *) URL);
+
+	/*
+	 * TODO: do an URI lookup on the reference
+	 */
+	if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
+	    xmlChar *tmp = NULL;
+
+	    if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
+		((pref == XML_CATA_ALLOW_ALL) ||
+		 (pref == XML_CATA_ALLOW_DOCUMENT))) {
+		tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
+	    }
+	    if ((tmp == NULL) &&
+		((pref == XML_CATA_ALLOW_ALL) ||
+	         (pref == XML_CATA_ALLOW_GLOBAL))) {
+		tmp = xmlCatalogResolveURI(resource);
+	    }
+
+	    if (tmp != NULL) {
+		xmlFree(resource);
+		resource = tmp;
+	    }
+	}
     }
-    if (xmlParserDebugEntities)
-	xmlGenericError(xmlGenericErrorContext,
-		"new fixed input: %.30s\n", buffer);
-    buf = xmlParserInputBufferCreateString(buffer);
-    if (buf == NULL) {
-	xmlErrMemory(ctxt, NULL);
-        return(NULL);
+
+    return resource;
+}
+
+#endif
+
+/**
+ * xmlCheckHTTPInput:
+ * @ctxt: an XML parser context
+ * @ret: an XML parser input
+ *
+ * DEPRECATED: Internal function, don't use.
+ *
+ * Check an input in case it was created from an HTTP stream, in that
+ * case it will handle encoding and update of the base URL in case of
+ * redirection. It also checks for HTTP errors in which case the input
+ * is cleanly freed up and an appropriate error is raised in context
+ *
+ * Returns the input or NULL in case of HTTP error.
+ */
+xmlParserInputPtr
+xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
+    /* Avoid unused variable warning if features are disabled. */
+    (void) ctxt;
+
+#ifdef LIBXML_HTTP_ENABLED
+    if ((ret != NULL) && (ret->buf != NULL) &&
+        (ret->buf->readcallback == xmlIOHTTPRead) &&
+        (ret->buf->context != NULL)) {
+        const char *encoding;
+        const char *redir;
+        const char *mime;
+        int code;
+
+        code = xmlNanoHTTPReturnCode(ret->buf->context);
+        if (code >= 400) {
+            /* fatal error */
+	    if (ret->filename != NULL)
+                xmlCtxtErrIO(ctxt, XML_IO_LOAD_ERROR, ret->filename);
+	    else
+                xmlCtxtErrIO(ctxt, XML_IO_LOAD_ERROR, "<null>");
+            xmlFreeInputStream(ret);
+            ret = NULL;
+        } else {
+
+            mime = xmlNanoHTTPMimeType(ret->buf->context);
+            if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
+                (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
+                encoding = xmlNanoHTTPEncoding(ret->buf->context);
+                if (encoding != NULL)
+                    xmlSwitchEncodingName(ctxt, encoding);
+#if 0
+            } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
+#endif
+            }
+            redir = xmlNanoHTTPRedir(ret->buf->context);
+            if (redir != NULL) {
+                if (ret->filename != NULL)
+                    xmlFree((xmlChar *) ret->filename);
+                ret->filename =
+                    (char *) xmlStrdup((const xmlChar *) redir);
+            }
+        }
     }
-    input = xmlNewInputStream(ctxt);
-    if (input == NULL) {
-        xmlErrMemory(ctxt,  "couldn't allocate a new input stream\n");
-	xmlFreeParserInputBuffer(buf);
-	return(NULL);
-    }
-    input->buf = buf;
-    xmlBufResetInput(input->buf->buffer, input);
-    return(input);
+#endif
+    return(ret);
 }
 
 /**
@@ -1777,6 +2001,8 @@
  * @ctxt:  an XML parser context
  * @filename:  the filename to use as entity
  *
+ * DEPRECATED: Use xmlNewInputURL.
+ *
  * Create a new input stream based on a file or an URL.
  *
  * Returns the new input stream or NULL in case of error
@@ -1785,22 +2011,16 @@
 xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) {
     xmlParserInputBufferPtr buf;
     xmlParserInputPtr inputStream;
-    char *directory = NULL;
     xmlChar *URI = NULL;
+    int code;
 
-    if (xmlParserDebugEntities)
-	xmlGenericError(xmlGenericErrorContext,
-		"new input from file: %s\n", filename);
-    if (ctxt == NULL) return(NULL);
-    buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
+    if ((ctxt == NULL) || (filename == NULL))
+        return(NULL);
+
+    code = xmlParserInputBufferCreateFilenameSafe(filename,
+                                                  XML_CHAR_ENCODING_NONE, &buf);
     if (buf == NULL) {
-	if (filename == NULL)
-            xmlLoaderErr(ctxt,
-                         "failed to load external entity: NULL filename\n",
-                         NULL);
-	else
-            xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n",
-                         (const char *) filename);
+        xmlCtxtErrIO(ctxt, code, filename);
 	return(NULL);
     }
 
@@ -1819,18 +2039,161 @@
 	URI = xmlStrdup((xmlChar *) filename);
     else
 	URI = xmlStrdup((xmlChar *) inputStream->filename);
-    directory = xmlParserGetDirectory((const char *) URI);
     if (inputStream->filename != NULL) xmlFree((char *)inputStream->filename);
     inputStream->filename = (char *) xmlCanonicPath((const xmlChar *) URI);
     if (URI != NULL) xmlFree((char *) URI);
-    inputStream->directory = directory;
 
     xmlBufResetInput(inputStream->buf->buffer, inputStream);
-    if ((ctxt->directory == NULL) && (directory != NULL))
-        ctxt->directory = (char *) xmlStrdup((const xmlChar *) directory);
+
     return(inputStream);
 }
 
+/**
+ * xmlDefaultExternalEntityLoader:
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * By default we don't load external entities, yet.
+ *
+ * Returns a new allocated xmlParserInputPtr, or NULL.
+ */
+static xmlParserInputPtr
+xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
+                               xmlParserCtxtPtr ctxt)
+{
+    xmlParserInputPtr ret = NULL;
+    xmlChar *resource = NULL;
+
+    if (URL == NULL)
+        return(NULL);
+
+    if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
+        int options = ctxt->options;
+
+	ctxt->options -= XML_PARSE_NONET;
+        ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
+	ctxt->options = options;
+	return(ret);
+    }
+#ifdef LIBXML_CATALOG_ENABLED
+    resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
+#endif
+
+    if (resource == NULL)
+        resource = (xmlChar *) URL;
+
+    ret = xmlNewInputFromFile(ctxt, (const char *) resource);
+    if ((resource != NULL) && (resource != (xmlChar *) URL))
+        xmlFree(resource);
+    return (ret);
+}
+
+/**
+ * xmlNoNetExternalEntityLoader:
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * A specific entity loader disabling network accesses, though still
+ * allowing local catalog accesses for resolution.
+ *
+ * Returns a new allocated xmlParserInputPtr, or NULL.
+ */
+xmlParserInputPtr
+xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
+                             xmlParserCtxtPtr ctxt) {
+    xmlParserInputPtr input = NULL;
+    xmlChar *resource = NULL;
+
+#ifdef LIBXML_CATALOG_ENABLED
+    resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
+#endif
+
+    if (resource == NULL)
+	resource = (xmlChar *) URL;
+
+    if (resource != NULL) {
+        if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
+            (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
+            xmlCtxtErrIO(ctxt, XML_IO_NETWORK_ATTEMPT,
+                         (const char *) resource);
+            /*
+             * Also forward the error directly to the global error
+             * handler, which the XML::LibXML test suite expects.
+             */
+            __xmlIOErr(XML_FROM_IO, XML_IO_NETWORK_ATTEMPT,
+                       (const char *) resource);
+	    if (resource != (xmlChar *) URL)
+		xmlFree(resource);
+	    return(NULL);
+	}
+    }
+    input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
+    if (resource != (xmlChar *) URL)
+	xmlFree(resource);
+    return(input);
+}
+
+/*
+ * This global has to die eventually
+ */
+static xmlExternalEntityLoader
+xmlCurrentExternalEntityLoader = xmlDefaultExternalEntityLoader;
+
+/**
+ * xmlSetExternalEntityLoader:
+ * @f:  the new entity resolver function
+ *
+ * Changes the defaultexternal entity resolver function for the application
+ */
+void
+xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
+    xmlCurrentExternalEntityLoader = f;
+}
+
+/**
+ * xmlGetExternalEntityLoader:
+ *
+ * Get the default external entity resolver function for the application
+ *
+ * Returns the xmlExternalEntityLoader function pointer
+ */
+xmlExternalEntityLoader
+xmlGetExternalEntityLoader(void) {
+    return(xmlCurrentExternalEntityLoader);
+}
+
+/**
+ * xmlLoadExternalEntity:
+ * @URL:  the URL for the entity to load
+ * @ID:  the Public ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * DEPRECATED: Use xmlNewInputURL.
+ *
+ * Returns the xmlParserInputPtr or NULL
+ */
+xmlParserInputPtr
+xmlLoadExternalEntity(const char *URL, const char *ID,
+                      xmlParserCtxtPtr ctxt) {
+    char *canonicFilename;
+    xmlParserInputPtr ret;
+
+    if (URL == NULL)
+        return(NULL);
+
+    canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
+    if (canonicFilename == NULL) {
+        xmlCtxtErrMemory(ctxt);
+        return(NULL);
+    }
+
+    ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
+    xmlFree(canonicFilename);
+    return(ret);
+}
+
 /************************************************************************
  *									*
  *		Commodity functions to handle parser contexts		*
@@ -1857,8 +2220,6 @@
     if (ctxt == NULL)
         return(-1);
 
-    xmlInitParser();
-
     if (ctxt->dict == NULL)
 	ctxt->dict = xmlDictCreate();
     if (ctxt->dict == NULL)
@@ -1905,10 +2266,7 @@
     ctxt->hasExternalSubset = 0;
     ctxt->hasPErefs = 0;
     ctxt->html = 0;
-    ctxt->external = 0;
     ctxt->instate = XML_PARSER_START;
-    ctxt->token = 0;
-    ctxt->directory = NULL;
 
     /* Allocate the Node stack */
     if (ctxt->nodeTab == NULL) {
@@ -1945,11 +2303,23 @@
     ctxt->wellFormed = 1;
     ctxt->nsWellFormed = 1;
     ctxt->valid = 1;
+
+    ctxt->options = XML_PARSE_NODICT;
+
+    /*
+     * Initialize some parser options from deprecated global variables.
+     * Note that the "modern" API taking options arguments or
+     * xmlCtxtSetOptions will ignore these defaults. They're only
+     * relevant if old API functions like xmlParseFile are used.
+     */
     ctxt->loadsubset = xmlLoadExtDtdDefaultValue;
     if (ctxt->loadsubset) {
         ctxt->options |= XML_PARSE_DTDLOAD;
     }
     ctxt->validate = xmlDoValidityCheckingDefaultValue;
+    if (ctxt->validate) {
+        ctxt->options |= XML_PARSE_DTDVALID;
+    }
     ctxt->pedantic = xmlPedanticParserDefaultValue;
     if (ctxt->pedantic) {
         ctxt->options |= XML_PARSE_PEDANTIC;
@@ -1960,23 +2330,18 @@
 	ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace;
 	ctxt->options |= XML_PARSE_NOBLANKS;
     }
+    ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue;
+    if (ctxt->replaceEntities) {
+        ctxt->options |= XML_PARSE_NOENT;
+    }
+    if (xmlGetWarningsDefaultValue == 0)
+        ctxt->options |= XML_PARSE_NOWARNING;
 
     ctxt->vctxt.flags = XML_VCTXT_USE_PCTXT;
     ctxt->vctxt.userData = ctxt;
     ctxt->vctxt.error = xmlParserValidityError;
     ctxt->vctxt.warning = xmlParserValidityWarning;
-    if (ctxt->validate) {
-	if (xmlGetWarningsDefaultValue == 0)
-	    ctxt->vctxt.warning = NULL;
-	else
-	    ctxt->vctxt.warning = xmlParserValidityWarning;
-	ctxt->vctxt.nodeMax = 0;
-        ctxt->options |= XML_PARSE_DTDVALID;
-    }
-    ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue;
-    if (ctxt->replaceEntities) {
-        ctxt->options |= XML_PARSE_NOENT;
-    }
+
     ctxt->record_info = 0;
     ctxt->checkIndex = 0;
     ctxt->inSubset = 0;
@@ -1992,7 +2357,7 @@
     if (ctxt->nsdb == NULL) {
         ctxt->nsdb = xmlParserNsCreate();
         if (ctxt->nsdb == NULL) {
-            xmlErrMemory(ctxt, NULL);
+            xmlCtxtErrMemory(ctxt);
             return(-1);
         }
     }
@@ -2052,7 +2417,6 @@
     if (ctxt->sax != NULL)
 #endif /* LIBXML_SAX1_ENABLED */
         xmlFree(ctxt->sax);
-    if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory);
     if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab);
     if (ctxt->atts != NULL) xmlFree((xmlChar * *)ctxt->atts);
     if (ctxt->dict != NULL) xmlDictFree(ctxt->dict);
@@ -2128,6 +2492,10 @@
  * Allocate and initialize a new SAX parser context. If userData is NULL,
  * the parser context will be passed as user data.
  *
+ * Available since 2.11.0. If you want support older versions,
+ * it's best to invoke xmlNewParserCtxt and set ctxt->sax with
+ * struct assignment.
+ *
  * Returns the xmlParserCtxtPtr or NULL if memory allocation failed.
  */
 
@@ -2136,6 +2504,8 @@
 {
     xmlParserCtxtPtr ctxt;
 
+    xmlInitParser();
+
     ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt));
     if (ctxt == NULL)
 	return(NULL);
@@ -2326,7 +2696,7 @@
                                                      byte_size);
 
             if (tmp_buffer == NULL) {
-		xmlErrMemory(ctxt, "failed to allocate buffer\n");
+		xmlCtxtErrMemory(ctxt);
                 return;
             }
             ctxt->node_seq.buffer = tmp_buffer;
diff --git a/src/pattern.c b/src/pattern.c
index 3a94aca..6cb4898 100644
--- a/src/pattern.c
+++ b/src/pattern.c
@@ -697,10 +697,6 @@
  *									*
  ************************************************************************/
 
-#define TODO								\
-    xmlGenericError(xmlGenericErrorContext,				\
-	    "Unimplemented block at %s:%d\n",				\
-            __FILE__, __LINE__);
 #define CUR (*ctxt->cur)
 #define SKIP(val) ctxt->cur += (val)
 #define NXT(val) ctxt->cur[(val)]
diff --git a/src/runtest.c b/src/runtest.c
index 4053e7d..ba7f16d 100644
--- a/src/runtest.c
+++ b/src/runtest.c
@@ -268,278 +268,8 @@
 }
 
 static void
-channel(void *ctx  ATTRIBUTE_UNUSED, const char *msg, ...) {
-    va_list args;
-    int res;
-
-    if (testErrorsSize >= 32768)
-        return;
-    va_start(args, msg);
-    res = vsnprintf(&testErrors[testErrorsSize],
-                    32768 - testErrorsSize,
-		    msg, args);
-    va_end(args);
-    if (testErrorsSize + res >= 32768) {
-        /* buffer is full */
-	testErrorsSize = 32768;
-	testErrors[testErrorsSize] = 0;
-    } else {
-        testErrorsSize += res;
-    }
-    testErrors[testErrorsSize] = 0;
-}
-
-/**
- * xmlParserPrintFileContextInternal:
- * @input:  an xmlParserInputPtr input
- *
- * Displays current context within the input content for error tracking
- */
-
-static void
-xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
-		xmlGenericErrorFunc chanl, void *data ) {
-    const xmlChar *cur, *base, *start;
-    unsigned int n, col;	/* GCC warns if signed, because compared with sizeof() */
-    xmlChar  content[81]; /* space for 80 chars + line terminator */
-    xmlChar *ctnt;
-
-    if ((input == NULL) || (input->cur == NULL))
-        return;
-
-    cur = input->cur;
-    base = input->base;
-    /* skip backwards over any end-of-lines */
-    while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
-	cur--;
-    }
-    n = 0;
-    /* search backwards for beginning-of-line (to max buff size) */
-    while ((n++ < (sizeof(content)-1)) && (cur > base) &&
-	   (*(cur) != '\n') && (*(cur) != '\r'))
-        cur--;
-    if ((*(cur) == '\n') || (*(cur) == '\r')) {
-        cur++;
-    } else {
-        /* skip over continuation bytes */
-        while ((cur < input->cur) && ((*cur & 0xC0) == 0x80))
-            cur++;
-    }
-    /* calculate the error position in terms of the current position */
-    col = input->cur - cur;
-    /* search forward for end-of-line (to max buff size) */
-    n = 0;
-    start = cur;
-    /* copy selected text to our buffer */
-    while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) {
-        int len = input->end - cur;
-        int c = xmlGetUTF8Char(cur, &len);
-
-        if ((c < 0) || (n + len > sizeof(content)-1))
-            break;
-        cur += len;
-	n += len;
-    }
-    memcpy(content, start, n);
-    content[n] = 0;
-    /* print out the selected text */
-    chanl(data ,"%s\n", content);
-    /* create blank line with problem pointer */
-    n = 0;
-    ctnt = content;
-    /* (leave buffer space for pointer + line terminator) */
-    while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
-	if (*(ctnt) != '\t')
-	    *(ctnt) = ' ';
-	ctnt++;
-    }
-    *ctnt++ = '^';
-    *ctnt = 0;
-    chanl(data ,"%s\n", content);
-}
-
-static void
 testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, const xmlError *err) {
-    char *file = NULL;
-    int line = 0;
-    int code = -1;
-    int domain;
-    void *data = NULL;
-    const char *str;
-    const xmlChar *name = NULL;
-    xmlNodePtr node;
-    xmlErrorLevel level;
-    xmlParserInputPtr input = NULL;
-    xmlParserInputPtr cur = NULL;
-    xmlParserCtxtPtr ctxt = NULL;
-
-    if (err == NULL)
-        return;
-
-    file = err->file;
-    line = err->line;
-    code = err->code;
-    domain = err->domain;
-    level = err->level;
-    node = err->node;
-    if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
-        (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
-	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
-	ctxt = err->ctxt;
-    }
-    str = err->message;
-
-    if (code == XML_ERR_OK)
-        return;
-
-    if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
-        name = node->name;
-
-    /*
-     * Maintain the compatibility with the legacy error handling
-     */
-    if ((ctxt != NULL) && (ctxt->input != NULL)) {
-        input = ctxt->input;
-        if ((input->filename == NULL) &&
-            (ctxt->inputNr > 1)) {
-            cur = input;
-            input = ctxt->inputTab[ctxt->inputNr - 2];
-        }
-        if (input->filename)
-            channel(data, "%s:%d: ", input->filename, input->line);
-        else if ((line != 0) && (domain == XML_FROM_PARSER))
-            channel(data, "Entity: line %d: ", input->line);
-    } else {
-        if (file != NULL)
-            channel(data, "%s:%d: ", file, line);
-        else if ((line != 0) && (domain == XML_FROM_PARSER))
-            channel(data, "Entity: line %d: ", line);
-    }
-    /*
-     * Skip element name when testing schemas to make memory and streaming
-     * output match.
-     */
-    if ((domain != XML_FROM_SCHEMASV) && (name != NULL)) {
-        channel(data, "element %s: ", name);
-    }
-    if (code == XML_ERR_OK)
-        return;
-    switch (domain) {
-        case XML_FROM_PARSER:
-            channel(data, "parser ");
-            break;
-        case XML_FROM_NAMESPACE:
-            channel(data, "namespace ");
-            break;
-        case XML_FROM_DTD:
-        case XML_FROM_VALID:
-            channel(data, "validity ");
-            break;
-        case XML_FROM_HTML:
-            channel(data, "HTML parser ");
-            break;
-        case XML_FROM_MEMORY:
-            channel(data, "memory ");
-            break;
-        case XML_FROM_OUTPUT:
-            channel(data, "output ");
-            break;
-        case XML_FROM_IO:
-            channel(data, "I/O ");
-            break;
-        case XML_FROM_XINCLUDE:
-            channel(data, "XInclude ");
-            break;
-        case XML_FROM_XPATH:
-            channel(data, "XPath ");
-            break;
-        case XML_FROM_XPOINTER:
-            channel(data, "parser ");
-            break;
-        case XML_FROM_REGEXP:
-            channel(data, "regexp ");
-            break;
-        case XML_FROM_MODULE:
-            channel(data, "module ");
-            break;
-        case XML_FROM_SCHEMASV:
-            channel(data, "Schemas validity ");
-            break;
-        case XML_FROM_SCHEMASP:
-            channel(data, "Schemas parser ");
-            break;
-        case XML_FROM_RELAXNGP:
-            channel(data, "Relax-NG parser ");
-            break;
-        case XML_FROM_RELAXNGV:
-            channel(data, "Relax-NG validity ");
-            break;
-        case XML_FROM_CATALOG:
-            channel(data, "Catalog ");
-            break;
-        case XML_FROM_C14N:
-            channel(data, "C14N ");
-            break;
-        case XML_FROM_XSLT:
-            channel(data, "XSLT ");
-            break;
-        default:
-            break;
-    }
-    if (code == XML_ERR_OK)
-        return;
-    switch (level) {
-        case XML_ERR_NONE:
-            channel(data, ": ");
-            break;
-        case XML_ERR_WARNING:
-            channel(data, "warning : ");
-            break;
-        case XML_ERR_ERROR:
-            channel(data, "error : ");
-            break;
-        case XML_ERR_FATAL:
-            channel(data, "error : ");
-            break;
-    }
-    if (code == XML_ERR_OK)
-        return;
-    if (str != NULL) {
-        int len;
-	len = xmlStrlen((const xmlChar *)str);
-	if ((len > 0) && (str[len - 1] != '\n'))
-	    channel(data, "%s\n", str);
-	else
-	    channel(data, "%s", str);
-    } else {
-        channel(data, "%s\n", "out of memory error");
-    }
-    if (code == XML_ERR_OK)
-        return;
-
-    if (ctxt != NULL) {
-        xmlParserPrintFileContextInternal(input, channel, data);
-        if (cur != NULL) {
-            if (cur->filename)
-                channel(data, "%s:%d: \n", cur->filename, cur->line);
-            else if ((line != 0) && (domain == XML_FROM_PARSER))
-                channel(data, "Entity: line %d: \n", cur->line);
-            xmlParserPrintFileContextInternal(cur, channel, data);
-        }
-    }
-    if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
-        (err->int1 < 100) &&
-	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
-	xmlChar buf[150];
-	int i;
-
-	channel(data, "%s\n", err->str1);
-	for (i=0;i < err->int1;i++)
-	     buf[i] = ' ';
-	buf[i++] = '^';
-	buf[i] = 0;
-	channel(data, "%s\n", buf);
-    }
+    xmlFormatError(err, testErrorHandler, NULL);
 }
 
 static void
@@ -555,7 +285,6 @@
     xmlInitParser();
     xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
     xmlSetExternalEntityLoader(testExternalEntityLoader);
-    xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
 #ifdef LIBXML_SCHEMAS_ENABLED
     xmlSchemaInitTypes();
     xmlRelaxNGInitTypes();
@@ -1051,6 +780,16 @@
     xmlEntityPtr ent;
     const xmlChar *nullstr = BAD_CAST "(null)";
 
+    ent = xmlNewEntity(NULL, name, type, publicId, systemId, content);
+    if (systemId != NULL)
+        ent->URI = xmlBuildURI(systemId, (const xmlChar *) ctxt->filename);
+
+    if ((type == XML_INTERNAL_PARAMETER_ENTITY) ||
+        (type == XML_EXTERNAL_PARAMETER_ENTITY))
+        xmlHashAddEntry(ctxt->parameterEntities, name, ent);
+    else
+        xmlHashAddEntry(ctxt->generalEntities, name, ent);
+
     /* not all libraries handle printing null pointers nicely */
     if (publicId == NULL)
         publicId = nullstr;
@@ -1063,16 +802,6 @@
 	return;
     fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
             name, type, publicId, systemId, content);
-
-    ent = xmlNewEntity(NULL, name, type, publicId, systemId, content);
-    if (systemId != NULL)
-        ent->URI = xmlBuildURI(systemId, (const xmlChar *) ctxt->filename);
-
-    if ((type == XML_INTERNAL_PARAMETER_ENTITY) ||
-        (type == XML_EXTERNAL_PARAMETER_ENTITY))
-        xmlHashAddEntry(ctxt->parameterEntities, name, ent);
-    else
-        xmlHashAddEntry(ctxt->generalEntities, name, ent);
 }
 
 /**
@@ -1767,10 +1496,6 @@
 	return(-1);
     }
 
-    /* for SAX we really want the callbacks though the context handlers */
-    xmlSetStructuredErrorFunc(NULL, NULL);
-    xmlSetGenericErrorFunc(NULL, testErrorHandler);
-
 #ifdef LIBXML_HTML_ENABLED
     if (options & XML_PARSE_HTML) {
         htmlParserCtxtPtr ctxt;
@@ -1847,10 +1572,6 @@
         free(temp);
     }
 
-    /* switch back to structured error handling */
-    xmlSetGenericErrorFunc(NULL, NULL);
-    xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
-
     return(ret);
 }
 
@@ -1921,6 +1642,7 @@
         unlink(temp);
         free(temp);
     }
+
     return(res);
 }
 
@@ -1966,6 +1688,7 @@
     else
 #endif
     ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename);
+    xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
     xmlCtxtUseOptions(ctxt, options);
     cur += chunkSize;
     chunkSize = 1024;
@@ -2185,6 +1908,7 @@
     else
 #endif
     ctxt = xmlCreatePushParserCtxt(&bndSAX, NULL, base, 1, filename);
+    xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
     xmlCtxtUseOptions(ctxt, options);
     cur = 1;
     consumed = 0;
@@ -2363,7 +2087,7 @@
 	return(-1);
     }
 
-    doc = xmlReadMemory(base, size, filename, NULL, 0);
+    doc = xmlReadMemory(base, size, filename, NULL, XML_PARSE_NOWARNING);
     unloadMem(base);
     if (doc == NULL) {
         return(1);
@@ -2405,7 +2129,7 @@
     /*
      * base of the test, parse with the old API
      */
-    doc = xmlReadFile(filename, NULL, options);
+    doc = xmlReadFile(filename, NULL, options | XML_PARSE_NOWARNING);
     if (doc == NULL)
         return(1);
     temp = resultFilename(filename, temp_directory, ".res");
@@ -2422,7 +2146,7 @@
     /*
      * Parse the saved result to make sure the round trip is okay
      */
-    doc = xmlReadFile(filename, NULL, options);
+    doc = xmlReadFile(filename, NULL, options | XML_PARSE_NOWARNING);
     if (doc == NULL)
         return(1);
     xmlSaveFile(temp, doc);
@@ -2451,6 +2175,7 @@
 static int
 errParseTest(const char *filename, const char *result, const char *err,
              int options) {
+    xmlParserCtxtPtr ctxt;
     xmlDocPtr doc;
     const char *base = NULL;
     int size, res = 0;
@@ -2458,20 +2183,32 @@
     nb_tests++;
 #ifdef LIBXML_HTML_ENABLED
     if (options & XML_PARSE_HTML) {
-        doc = htmlReadFile(filename, NULL, options);
-    } else
-#endif
-#ifdef LIBXML_XINCLUDE_ENABLED
-    if (options & XML_PARSE_XINCLUDE) {
-	doc = xmlReadFile(filename, NULL, options);
-	if (xmlXIncludeProcessFlags(doc, options) < 0) {
-	    xmlFreeDoc(doc);
-            doc = NULL;
-        }
+        ctxt = htmlNewParserCtxt();
+        xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
+        doc = htmlCtxtReadFile(ctxt, filename, NULL, options);
+        htmlFreeParserCtxt(ctxt);
     } else
 #endif
     {
-	doc = xmlReadFile(filename, NULL, options);
+        ctxt = xmlNewParserCtxt();
+        xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
+	doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
+        xmlFreeParserCtxt(ctxt);
+#ifdef LIBXML_XINCLUDE_ENABLED
+        if (options & XML_PARSE_XINCLUDE) {
+            xmlXIncludeCtxtPtr xinc = NULL;
+
+            xinc = xmlXIncludeNewContext(doc);
+            xmlXIncludeSetErrorHandler(xinc, testStructuredErrorHandler, NULL);
+            xmlXIncludeSetFlags(xinc, options);
+            if (xmlXIncludeProcessNode(xinc, (xmlNodePtr) doc) < 0) {
+                testErrorHandler(NULL, "%s : failed to parse\n", filename);
+                xmlFreeDoc(doc);
+                doc = NULL;
+            }
+            xmlXIncludeFreeContext(xinc);
+        }
+#endif
     }
     if (result) {
 	if (doc == NULL) {
@@ -2524,6 +2261,7 @@
 static int
 fdParseTest(const char *filename, const char *result, const char *err,
              int options) {
+    xmlParserCtxtPtr ctxt;
     xmlDocPtr doc;
     const char *base = NULL;
     int size, res = 0, fd;
@@ -2532,11 +2270,17 @@
     fd = open(filename, RD_FLAGS);
 #ifdef LIBXML_HTML_ENABLED
     if (options & XML_PARSE_HTML) {
-        doc = htmlReadFd(fd, filename, NULL, options);
+        ctxt = htmlNewParserCtxt();
+        xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
+        doc = htmlCtxtReadFd(ctxt, fd, filename, NULL, options);
+        htmlFreeParserCtxt(ctxt);
     } else
 #endif
     {
-	doc = xmlReadFd(fd, filename, NULL, options);
+        ctxt = xmlNewParserCtxt();
+        xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
+	doc = xmlCtxtReadFd(ctxt, fd, filename, NULL, options);
+        xmlFreeParserCtxt(ctxt);
     }
     close(fd);
     if (result) {
@@ -2708,6 +2452,8 @@
     int ret;
 
     reader = xmlReaderForFile(filename, NULL, options);
+    xmlTextReaderSetStructuredErrorHandler(reader, testStructuredErrorHandler,
+                                           NULL);
     ret = streamProcessTest(filename, result, err, reader, NULL, options);
     xmlFreeTextReader(reader);
     return(ret);
@@ -2730,7 +2476,7 @@
     xmlTextReaderPtr reader;
     int ret;
 
-    doc = xmlReadFile(filename, NULL, options);
+    doc = xmlReadFile(filename, NULL, options | XML_PARSE_NOWARNING);
     if (doc == NULL) {
         fprintf(stderr, "Failed to parse %s\n", filename);
 	return(-1);
@@ -2768,6 +2514,8 @@
 	return(-1);
     }
     reader = xmlReaderForMemory(base, size, filename, NULL, options);
+    xmlTextReaderSetStructuredErrorHandler(reader, testStructuredErrorHandler,
+                                           NULL);
     ret = streamProcessTest(filename, result, err, reader, NULL, options);
     free((char *)base);
     xmlFreeTextReader(reader);
@@ -2787,26 +2535,20 @@
 static xmlDocPtr xpathDocument;
 
 static void
-ignoreGenericError(void *ctx ATTRIBUTE_UNUSED,
-        const char *msg ATTRIBUTE_UNUSED, ...) {
-}
-
-static void
 testXPath(const char *str, int xptr, int expr) {
     xmlXPathObjectPtr res;
     xmlXPathContextPtr ctxt;
 
-    /* Don't print generic errors to stderr. */
-    xmlSetGenericErrorFunc(NULL, ignoreGenericError);
-
     nb_tests++;
 #if defined(LIBXML_XPTR_ENABLED)
     if (xptr) {
 	ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
+        xmlXPathSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
 	res = xmlXPtrEval(BAD_CAST str, ctxt);
     } else {
 #endif
 	ctxt = xmlXPathNewContext(xpathDocument);
+        xmlXPathSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
 	ctxt->node = xmlDocGetRootElement(xpathDocument);
 	if (expr)
 	    res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
@@ -2827,9 +2569,6 @@
     xmlXPathDebugDumpObject(xpathOutput, res, 0);
     xmlXPathFreeObject(res);
     xmlXPathFreeContext(ctxt);
-
-    /* Reset generic error handler. */
-    xmlSetGenericErrorFunc(NULL, NULL);
 }
 
 /**
@@ -2864,7 +2603,7 @@
 
     input = fopen(filename, "rb");
     if (input == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
+        fprintf(stderr,
 		"Cannot open %s for reading\n", filename);
         free(temp);
 	return(-1);
@@ -3039,13 +2778,16 @@
              const char *result,
              const char *err,
              int options) {
-
+    xmlParserCtxtPtr ctxt;
     int res = 0;
     int ret = 0;
     char *temp;
 
-    xpathDocument = xmlReadFile(filename, NULL,
-                                options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
+    ctxt = xmlNewParserCtxt();
+    xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
+    xpathDocument = xmlCtxtReadFile(ctxt, filename, NULL,
+            options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
+    xmlFreeParserCtxt(ctxt);
     if (xpathDocument == NULL) {
         fprintf(stderr, "Failed to load %s\n", filename);
 	return(-1);
@@ -3464,8 +3206,12 @@
         testErrorsSize = parseErrorsSize;
         testErrors[parseErrorsSize] = 0;
 
+        if (schemas == NULL)
+            goto done;
+
         ctxt = xmlSchemaNewValidCtxt(schemas);
-        xmlSchemaSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
+        xmlSchemaSetValidStructuredErrors(ctxt, testStructuredErrorHandler,
+                                          NULL);
 
         schemasOutput = fopen(temp, "wb");
         if (schemasOutput == NULL) {
@@ -3497,19 +3243,23 @@
                    filename);
         }
         fclose(schemasOutput);
+
         if (result) {
             if (compareFiles(temp, result)) {
                 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
                 ret = 1;
             }
         }
+
+        xmlSchemaFreeValidCtxt(ctxt);
+
+done:
         if (compareFileMem(err, testErrors, testErrorsSize)) {
             fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
             ret = 1;
         }
 
         unlink(temp);
-        xmlSchemaFreeValidCtxt(ctxt);
     }
 
     free(temp);
@@ -3548,7 +3298,7 @@
 
     /* first compile the schemas if possible */
     ctxt = xmlSchemaNewParserCtxt(filename);
-    xmlSchemaSetParserErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
+    xmlSchemaSetParserStructuredErrors(ctxt, testStructuredErrorHandler, NULL);
     schemas = xmlSchemaParse(ctxt);
     xmlSchemaFreeParserCtxt(ctxt);
     parseErrorsSize = testErrorsSize;
@@ -3602,13 +3352,12 @@
 	    fprintf(stderr, "don't know how to process %s\n", instance);
 	    continue;
 	}
-	if (schemas != NULL) {
-	    nb_tests++;
-	    ret = schemasOneTest(filename, instance, result, err,
-                                 options, schemas);
-	    if (ret != 0)
-		res = ret;
-	}
+
+        nb_tests++;
+        ret = schemasOneTest(filename, instance, result, err,
+                             options, schemas);
+        if (ret != 0)
+            res = ret;
     }
     globfree(&globbuf);
     xmlSchemaFree(schemas);
@@ -3653,7 +3402,7 @@
     }
 
     ctxt = xmlRelaxNGNewValidCtxt(schemas);
-    xmlRelaxNGSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
+    xmlRelaxNGSetValidStructuredErrors(ctxt, testStructuredErrorHandler, NULL);
     ret = xmlRelaxNGValidateDoc(ctxt, doc);
     if (ret == 0) {
 	testErrorHandler(NULL, "%s validates\n", filename);
@@ -3712,7 +3461,8 @@
 
     /* first compile the schemas if possible */
     ctxt = xmlRelaxNGNewParserCtxt(filename);
-    xmlRelaxNGSetParserErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
+    xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler,
+                                        NULL);
     schemas = xmlRelaxNGParse(ctxt);
     xmlRelaxNGFreeParserCtxt(ctxt);
     if (schemas == NULL)
@@ -3766,7 +3516,7 @@
         if (compareFileMem(err, testErrors, testErrorsSize)) {
             fprintf(stderr, "Error for %s on %s failed\n", instance,
                     filename);
-            res = 1;
+            ret = 1;
         }
     }
     globfree(&globbuf);
@@ -3852,6 +3602,8 @@
 	    continue;
 	}
 	reader = xmlReaderForFile(instance, NULL, options);
+        xmlTextReaderSetStructuredErrorHandler(reader,
+                testStructuredErrorHandler, NULL);
 	if (reader == NULL) {
 	    fprintf(stderr, "Failed to build reader for %s\n", instance);
 	}
@@ -4251,7 +4003,8 @@
      * build an XML tree from a the file; we need to add default
      * attributes and resolve all character and entities references
      */
-    doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
+    doc = xmlReadFile(xml_filename, NULL,
+            XML_PARSE_DTDATTR | XML_PARSE_NOENT | XML_PARSE_NOWARNING);
     if (doc == NULL) {
 	fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
 	return(-1);
@@ -4615,13 +4368,19 @@
     char expression[5000];
     int len, ret, res = 0;
 
+    /*
+     * TODO: Custom error handler for regexp
+     */
+    xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
+
     nb_tests++;
 
     input = fopen(filename, "rb");
     if (input == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
+        fprintf(stderr,
 		"Cannot open %s for reading\n", filename);
-	return(-1);
+	ret = -1;
+        goto done;
     }
     temp = resultFilename(filename, "", ".res");
     if (temp == NULL) {
@@ -4632,7 +4391,8 @@
     if (output == NULL) {
 	fprintf(stderr, "failed to open output file %s\n", temp);
         free(temp);
-	return(-1);
+	ret = -1;
+        goto done;
     }
     while (fgets(expression, 4500, input) != NULL) {
 	len = strlen(expression);
@@ -4690,6 +4450,9 @@
         res = 1;
     }
 
+done:
+    xmlSetStructuredErrorFunc(NULL, NULL);
+
     return(res);
 }
 
@@ -4737,7 +4500,7 @@
 
     input = fopen(filename, "rb");
     if (input == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
+        fprintf(stderr,
 		"Cannot open %s for reading\n", filename);
 	return(-1);
     }
@@ -4755,14 +4518,14 @@
 
     am = xmlNewAutomata();
     if (am == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
+        fprintf(stderr,
 		"Cannot create automata\n");
 	fclose(input);
 	return(-1);
     }
     states[0] = xmlAutomataGetInitState(am);
     if (states[0] == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
+        fprintf(stderr,
 		"Cannot get start state\n");
 	xmlFreeAutomata(am);
 	fclose(input);
@@ -4786,7 +4549,7 @@
 
 		from = scanNumber(&ptr);
 		if (*ptr != ' ') {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Bad line %s\n", expr);
 		    break;
 		}
@@ -4795,7 +4558,7 @@
 		ptr++;
 		to = scanNumber(&ptr);
 		if (*ptr != ' ') {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Bad line %s\n", expr);
 		    break;
 		}
@@ -4810,7 +4573,7 @@
 
 		from = scanNumber(&ptr);
 		if (*ptr != ' ') {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Bad line %s\n", expr);
 		    break;
 		}
@@ -4827,7 +4590,7 @@
 
 		state = scanNumber(&ptr);
 		if (states[state] == NULL) {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Bad state %d : %s\n", state, expr);
 		    break;
 		}
@@ -4839,7 +4602,7 @@
 
 		from = scanNumber(&ptr);
 		if (*ptr != ' ') {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Bad line %s\n", expr);
 		    break;
 		}
@@ -4848,7 +4611,7 @@
 		ptr++;
 		to = scanNumber(&ptr);
 		if (*ptr != ' ') {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Bad line %s\n", expr);
 		    break;
 		}
@@ -4857,14 +4620,14 @@
 		ptr++;
 		min = scanNumber(&ptr);
 		if (*ptr != ' ') {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Bad line %s\n", expr);
 		    break;
 		}
 		ptr++;
 		max = scanNumber(&ptr);
 		if (*ptr != ' ') {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Bad line %s\n", expr);
 		    break;
 		}
@@ -4877,7 +4640,7 @@
 		xmlFreeAutomata(am);
 		am = NULL;
 		if (regexp == NULL) {
-		    xmlGenericError(xmlGenericErrorContext,
+		    fprintf(stderr,
 			    "Failed to compile the automata");
 		    break;
 		}
@@ -4905,7 +4668,7 @@
 		    exec = xmlRegNewExecCtxt(regexp, NULL, NULL);
 		ret = xmlRegExecPushString(exec, BAD_CAST expr, NULL);
 	    } else {
-		xmlGenericError(xmlGenericErrorContext,
+		fprintf(stderr,
 			"Unexpected line %s\n", expr);
 	    }
 	}
diff --git a/src/runxmlconf.c b/src/runxmlconf.c
index b5c3fd8..bee8bdb 100644
--- a/src/runxmlconf.c
+++ b/src/runxmlconf.c
@@ -163,7 +163,6 @@
     */
     if (ctxtXPath->cache != NULL)
 	xmlXPathContextSetCache(ctxtXPath, 0, -1, 0);
-    xmlSetStructuredErrorFunc(NULL, testErrorHandler);
 }
 
 /************************************************************************
@@ -184,6 +183,7 @@
 	         id, filename);
         return(0);
     }
+    xmlCtxtSetErrorHandler(ctxt, testErrorHandler, NULL);
     doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
     if (doc == NULL) {
         test_log("test %s : %s invalid document turned not well-formed too\n",
@@ -214,6 +214,7 @@
 	         id, filename);
         return(0);
     }
+    xmlCtxtSetErrorHandler(ctxt, testErrorHandler, NULL);
     doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
     if (doc == NULL) {
         test_log("test %s : %s failed to parse a valid document\n",
@@ -236,14 +237,17 @@
 
 static int
 xmlconfTestNotNSWF(const char *id, const char *filename, int options) {
+    xmlParserCtxtPtr ctxt;
     xmlDocPtr doc;
     int ret = 1;
 
+    ctxt = xmlNewParserCtxt();
+    xmlCtxtSetErrorHandler(ctxt, testErrorHandler, NULL);
     /*
      * In case of Namespace errors, libxml2 will still parse the document
      * but log a Namespace error.
      */
-    doc = xmlReadFile(filename, NULL, options);
+    doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
     if (doc == NULL) {
         test_log("test %s : %s failed to parse the XML\n",
 	         id, filename);
@@ -261,15 +265,19 @@
 	}
 	xmlFreeDoc(doc);
     }
+    xmlFreeParserCtxt(ctxt);
     return(ret);
 }
 
 static int
 xmlconfTestNotWF(const char *id, const char *filename, int options) {
+    xmlParserCtxtPtr ctxt;
     xmlDocPtr doc;
     int ret = 1;
 
-    doc = xmlReadFile(filename, NULL, options);
+    ctxt = xmlNewParserCtxt();
+    xmlCtxtSetErrorHandler(ctxt, testErrorHandler, NULL);
+    doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
     if (doc != NULL) {
         test_log("test %s : %s failed to detect not well formedness\n",
 	         id, filename);
@@ -277,6 +285,7 @@
 	xmlFreeDoc(doc);
 	ret = 0;
     }
+    xmlFreeParserCtxt(ctxt);
     return(ret);
 }
 
diff --git a/src/testchar.c b/src/testchar.c
index 8895d8d..13887cd 100644
--- a/src/testchar.c
+++ b/src/testchar.c
@@ -310,9 +310,9 @@
         c = testCurrentChar(ctxt, &len);
         if (c < 0)
             continue;
-	if ((i == 0) || (i >= 0x80)) {
+	if (i >= 0x80) {
 	    /* we must see an error there */
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 	        fprintf(stderr,
 		    "Failed to detect invalid char for Byte 0x%02X\n", i);
 		return(1);
@@ -349,7 +349,7 @@
 
 	    /* if first bit of first char is set, then second bit must too */
 	    if ((i & 0x80) && ((i & 0x40) == 0)) {
-		if (lastError != XML_ERR_INVALID_CHAR) {
+		if (lastError != XML_ERR_INVALID_ENCODING) {
 		    fprintf(stderr,
 		    "Failed to detect invalid char for Bytes 0x%02X 0x%02X\n",
 		            i, j);
@@ -362,7 +362,7 @@
 	     * bits must be 10
 	     */
 	    else if ((i & 0x80) && ((j & 0xC0) != 0x80)) {
-		if (lastError != XML_ERR_INVALID_CHAR) {
+		if (lastError != XML_ERR_INVALID_ENCODING) {
 		    fprintf(stderr,
 		"Failed to detect invalid char for Bytes 0x%02X 0x%02X: %d\n",
 		            i, j, c);
@@ -375,7 +375,7 @@
 	     * than 0x80, i.e. one of bits 5 to 1 of i must be set
 	     */
 	    else if ((i & 0x80) && ((i & 0x1E) == 0)) {
-		if (lastError != XML_ERR_INVALID_CHAR) {
+		if (lastError != XML_ERR_INVALID_ENCODING) {
 		    fprintf(stderr,
 		"Failed to detect invalid char for Bytes 0x%02X 0x%02X: %d\n",
 		            i, j, c);
@@ -388,7 +388,7 @@
 	     * at least 3 bytes, but we give only 2 !
 	     */
 	    else if ((i & 0xE0) == 0xE0) {
-		if (lastError != XML_ERR_INVALID_CHAR) {
+		if (lastError != XML_ERR_INVALID_ENCODING) {
 		    fprintf(stderr,
 		"Failed to detect invalid char for Bytes 0x%02X 0x%02X 0x00\n",
 		            i, j);
@@ -446,7 +446,7 @@
 	 * at least 4 bytes, but we give only 3 !
 	 */
 	if ((i & 0xF0) == 0xF0) {
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 		fprintf(stderr,
 	"Failed to detect invalid char for Bytes 0x%02X 0x%02X 0x%02X 0x%02X\n",
 			i, j, K, data[3]);
@@ -458,7 +458,7 @@
 	 * The second and the third bytes must start with 10
 	 */
 	else if (((j & 0xC0) != 0x80) || ((K & 0xC0) != 0x80)) {
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 		fprintf(stderr,
 	"Failed to detect invalid char for Bytes 0x%02X 0x%02X 0x%02X\n",
 			i, j, K);
@@ -472,7 +472,7 @@
 	 * the 6th byte of data[1] must be set
 	 */
 	else if (((i & 0xF) == 0) && ((j & 0x20) == 0)) {
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 		fprintf(stderr,
 	    "Failed to detect invalid char for Bytes 0x%02X 0x%02X 0x%02X\n",
 			i, j, K);
@@ -484,7 +484,7 @@
 	 * There are values that are not allowed in UTF-8
 	 */
 	else if ((value > 0xD7FF) && (value <0xE000)) {
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 		fprintf(stderr,
 	"Failed to detect invalid char 0x%04X for Bytes 0x%02X 0x%02X 0x%02X\n",
 			value, i, j, K);
@@ -548,7 +548,7 @@
 	 * at least 5 bytes, but we give only 4 !
 	 */
 	if ((i & 0xF8) == 0xF8) {
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 		fprintf(stderr,
   "Failed to detect invalid char for Bytes 0x%02X 0x%02X 0x%02X 0x%02X\n",
 			i, j, K, data[3]);
@@ -561,7 +561,7 @@
 	 */
 	else if (((j & 0xC0) != 0x80) || ((K & 0xC0) != 0x80) ||
 	         ((L & 0xC0) != 0x80)) {
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 		fprintf(stderr,
 	"Failed to detect invalid char for Bytes 0x%02X 0x%02X 0x%02X 0x%02X\n",
 			i, j, K, L);
@@ -575,7 +575,7 @@
 	 * the 6 or 5th byte of j must be set
 	 */
 	else if (((i & 0x7) == 0) && ((j & 0x30) == 0)) {
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 		fprintf(stderr,
 	"Failed to detect invalid char for Bytes 0x%02X 0x%02X 0x%02X 0x%02X\n",
 			i, j, K, L);
@@ -588,7 +588,7 @@
 	 */
 	else if (((value > 0xD7FF) && (value < 0xE000)) ||
 		 (value > 0x10FFFF)) {
-	    if (lastError != XML_ERR_INVALID_CHAR) {
+	    if (lastError != XML_ERR_INVALID_ENCODING) {
 		fprintf(stderr,
 "Failed to detect invalid char 0x%04X for Bytes 0x%02X 0x%02X 0x%02X 0x%02X\n",
 			value, i, j, K, L);
@@ -648,8 +648,8 @@
         fprintf(stderr, "Failed to allocate parser context\n");
 	return(1);
     }
-    buf = xmlParserInputBufferCreateMem(data, sizeof(data),
-                                        XML_CHAR_ENCODING_NONE);
+    buf = xmlParserInputBufferCreateStatic(data, sizeof(data),
+                                           XML_CHAR_ENCODING_NONE);
     if (buf == NULL) {
         fprintf(stderr, "Failed to allocate input buffer\n");
 	test_ret = 1;
diff --git a/src/testdict.c b/src/testdict.c
index ffbbc94..94f18c2 100644
--- a/src/testdict.c
+++ b/src/testdict.c
@@ -7,9 +7,14 @@
 /**** dictionary tests ****/
 
 #ifdef __clang__
-  #define ATTRIBUTE_NO_SANITIZE_INTEGER \
-    __attribute__ ((no_sanitize("unsigned-integer-overflow"))) \
-    __attribute__ ((no_sanitize("unsigned-shift-base")))
+  #if __clang_major__ >= 12
+    #define ATTRIBUTE_NO_SANITIZE_INTEGER \
+      __attribute__ ((no_sanitize("unsigned-integer-overflow"))) \
+      __attribute__ ((no_sanitize("unsigned-shift-base")))
+  #else
+    #define ATTRIBUTE_NO_SANITIZE_INTEGER \
+      __attribute__ ((no_sanitize("unsigned-integer-overflow")))
+  #endif
 #else
   #define ATTRIBUTE_NO_SANITIZE_INTEGER
 #endif
diff --git a/src/testlimits.c b/src/testlimits.c
index 78d62fb..7144b9a 100644
--- a/src/testlimits.c
+++ b/src/testlimits.c
@@ -389,279 +389,11 @@
     return(ret);
 }
 
-/*
- * Trapping the error messages at the generic level to grab the equivalent of
- * stderr messages on CLI tools.
- */
-static char testErrors[32769];
-static int testErrorsSize = 0;
-
-static void
-channel(void *ctx  ATTRIBUTE_UNUSED, const char *msg, ...) {
-    va_list args;
-    int res;
-
-    if (testErrorsSize >= 32768)
-        return;
-    va_start(args, msg);
-    res = vsnprintf(&testErrors[testErrorsSize],
-                    32768 - testErrorsSize,
-		    msg, args);
-    va_end(args);
-    if (testErrorsSize + res >= 32768) {
-        /* buffer is full */
-	testErrorsSize = 32768;
-	testErrors[testErrorsSize] = 0;
-    } else {
-        testErrorsSize += res;
-    }
-    testErrors[testErrorsSize] = 0;
-}
-
-/**
- * xmlParserPrintFileContext:
- * @input:  an xmlParserInputPtr input
- *
- * Displays current context within the input content for error tracking
- */
-
-static void
-xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
-		xmlGenericErrorFunc chanl, void *data ) {
-    const xmlChar *cur, *base;
-    unsigned int n, col;	/* GCC warns if signed, because compared with sizeof() */
-    xmlChar  content[81]; /* space for 80 chars + line terminator */
-    xmlChar *ctnt;
-
-    if (input == NULL) return;
-    cur = input->cur;
-    base = input->base;
-    /* skip backwards over any end-of-lines */
-    while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
-	cur--;
-    }
-    n = 0;
-    /* search backwards for beginning-of-line (to max buff size) */
-    while ((n++ < (sizeof(content)-1)) && (cur > base) &&
-   (*(cur) != '\n') && (*(cur) != '\r'))
-        cur--;
-    if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
-    /* calculate the error position in terms of the current position */
-    col = input->cur - cur;
-    /* search forward for end-of-line (to max buff size) */
-    n = 0;
-    ctnt = content;
-    /* copy selected text to our buffer */
-    while ((*cur != 0) && (*(cur) != '\n') &&
-   (*(cur) != '\r') && (n < sizeof(content)-1)) {
-		*ctnt++ = *cur++;
-	n++;
-    }
-    *ctnt = 0;
-    /* print out the selected text */
-    chanl(data ,"%s\n", content);
-    /* create blank line with problem pointer */
-    n = 0;
-    ctnt = content;
-    /* (leave buffer space for pointer + line terminator) */
-    while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
-	if (*(ctnt) != '\t')
-	    *(ctnt) = ' ';
-	ctnt++;
-    }
-    *ctnt++ = '^';
-    *ctnt = 0;
-    chanl(data ,"%s\n", content);
-}
-
-static void
-testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, const xmlError *err) {
-    char *file = NULL;
-    int line = 0;
-    int code = -1;
-    int domain;
-    void *data = NULL;
-    const char *str;
-    const xmlChar *name = NULL;
-    xmlNodePtr node;
-    xmlErrorLevel level;
-    xmlParserInputPtr input = NULL;
-    xmlParserInputPtr cur = NULL;
-    xmlParserCtxtPtr ctxt = NULL;
-
-    if (err == NULL)
-        return;
-
-    file = err->file;
-    line = err->line;
-    code = err->code;
-    domain = err->domain;
-    level = err->level;
-    node = err->node;
-    if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
-        (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
-	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
-	ctxt = err->ctxt;
-    }
-    str = err->message;
-
-    if (code == XML_ERR_OK)
-        return;
-
-    if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
-        name = node->name;
-
-    /*
-     * Maintain the compatibility with the legacy error handling
-     */
-    if (ctxt != NULL) {
-        input = ctxt->input;
-        if ((input != NULL) && (input->filename == NULL) &&
-            (ctxt->inputNr > 1)) {
-            cur = input;
-            input = ctxt->inputTab[ctxt->inputNr - 2];
-        }
-        if (input != NULL) {
-            if (input->filename)
-                channel(data, "%s:%d: ", input->filename, input->line);
-            else if ((line != 0) && (domain == XML_FROM_PARSER))
-                channel(data, "Entity: line %d: ", input->line);
-        }
-    } else {
-        if (file != NULL)
-            channel(data, "%s:%d: ", file, line);
-        else if ((line != 0) && (domain == XML_FROM_PARSER))
-            channel(data, "Entity: line %d: ", line);
-    }
-    if (name != NULL) {
-        channel(data, "element %s: ", name);
-    }
-    if (code == XML_ERR_OK)
-        return;
-    switch (domain) {
-        case XML_FROM_PARSER:
-            channel(data, "parser ");
-            break;
-        case XML_FROM_NAMESPACE:
-            channel(data, "namespace ");
-            break;
-        case XML_FROM_DTD:
-        case XML_FROM_VALID:
-            channel(data, "validity ");
-            break;
-        case XML_FROM_HTML:
-            channel(data, "HTML parser ");
-            break;
-        case XML_FROM_MEMORY:
-            channel(data, "memory ");
-            break;
-        case XML_FROM_OUTPUT:
-            channel(data, "output ");
-            break;
-        case XML_FROM_IO:
-            channel(data, "I/O ");
-            break;
-        case XML_FROM_XINCLUDE:
-            channel(data, "XInclude ");
-            break;
-        case XML_FROM_XPATH:
-            channel(data, "XPath ");
-            break;
-        case XML_FROM_XPOINTER:
-            channel(data, "parser ");
-            break;
-        case XML_FROM_REGEXP:
-            channel(data, "regexp ");
-            break;
-        case XML_FROM_MODULE:
-            channel(data, "module ");
-            break;
-        case XML_FROM_SCHEMASV:
-            channel(data, "Schemas validity ");
-            break;
-        case XML_FROM_SCHEMASP:
-            channel(data, "Schemas parser ");
-            break;
-        case XML_FROM_RELAXNGP:
-            channel(data, "Relax-NG parser ");
-            break;
-        case XML_FROM_RELAXNGV:
-            channel(data, "Relax-NG validity ");
-            break;
-        case XML_FROM_CATALOG:
-            channel(data, "Catalog ");
-            break;
-        case XML_FROM_C14N:
-            channel(data, "C14N ");
-            break;
-        case XML_FROM_XSLT:
-            channel(data, "XSLT ");
-            break;
-        default:
-            break;
-    }
-    if (code == XML_ERR_OK)
-        return;
-    switch (level) {
-        case XML_ERR_NONE:
-            channel(data, ": ");
-            break;
-        case XML_ERR_WARNING:
-            channel(data, "warning : ");
-            break;
-        case XML_ERR_ERROR:
-            channel(data, "error : ");
-            break;
-        case XML_ERR_FATAL:
-            channel(data, "error : ");
-            break;
-    }
-    if (code == XML_ERR_OK)
-        return;
-    if (str != NULL) {
-        int len;
-	len = xmlStrlen((const xmlChar *)str);
-	if ((len > 0) && (str[len - 1] != '\n'))
-	    channel(data, "%s\n", str);
-	else
-	    channel(data, "%s", str);
-    } else {
-        channel(data, "%s\n", "out of memory error");
-    }
-    if (code == XML_ERR_OK)
-        return;
-
-    if (ctxt != NULL) {
-        xmlParserPrintFileContextInternal(input, channel, data);
-        if (cur != NULL) {
-            if (cur->filename)
-                channel(data, "%s:%d: \n", cur->filename, cur->line);
-            else if ((line != 0) && (domain == XML_FROM_PARSER))
-                channel(data, "Entity: line %d: \n", cur->line);
-            xmlParserPrintFileContextInternal(cur, channel, data);
-        }
-    }
-    if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
-        (err->int1 < 100) &&
-	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
-	xmlChar buf[150];
-	int i;
-
-	channel(data, "%s\n", err->str1);
-	for (i=0;i < err->int1;i++)
-	     buf[i] = ' ';
-	buf[i++] = '^';
-	buf[i] = 0;
-	channel(data, "%s\n", buf);
-    }
-}
-
 static void
 initializeLibxml2(void) {
     xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
     xmlInitParser();
     xmlSetExternalEntityLoader(testExternalEntityLoader);
-    xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
     /*
      * register the new I/O handlers
      */
@@ -1261,7 +993,7 @@
         fprintf(stderr, "Failed to create parser context\n");
 	return(1);
     }
-    doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
+    doc = xmlCtxtReadFile(ctxt, filename, NULL, options | XML_PARSE_NOERROR);
 
     if (doc != NULL) {
         fprintf(stderr, "SAX parsing generated a document !\n");
@@ -1308,7 +1040,7 @@
     nb_tests++;
 
     maxlen = limit;
-    reader = xmlReaderForFile(filename , NULL, options);
+    reader = xmlReaderForFile(filename , NULL, options | XML_PARSE_NOERROR);
     if (reader == NULL) {
         fprintf(stderr, "Failed to open '%s' test\n", filename);
 	return(1);
diff --git a/src/testparser.c b/src/testparser.c
index 625ba10..08965b5 100644
--- a/src/testparser.c
+++ b/src/testparser.c
@@ -5,6 +5,85 @@
  */
 
 #include <libxml/parser.h>
+#include <libxml/xmlreader.h>
+#include <libxml/xmlwriter.h>
+
+#include <string.h>
+
+static int
+testStandaloneWithEncoding(void) {
+    xmlDocPtr doc;
+    const char *str =
+        "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
+        "<doc></doc>\n";
+    int err = 0;
+
+    xmlResetLastError();
+
+    doc = xmlReadDoc(BAD_CAST str, NULL, "UTF-8", 0);
+    if (doc == NULL) {
+        fprintf(stderr, "xmlReadDoc failed\n");
+        err = 1;
+    }
+    xmlFreeDoc(doc);
+
+    return err;
+}
+
+static int
+testUnsupportedEncoding(void) {
+    xmlDocPtr doc;
+    const xmlError *error;
+    int err = 0;
+
+    xmlResetLastError();
+
+    doc = xmlReadDoc(BAD_CAST "<doc/>", NULL, "#unsupported",
+                     XML_PARSE_NOWARNING);
+    if (doc == NULL) {
+        fprintf(stderr, "xmlReadDoc failed with unsupported encoding\n");
+        err = 1;
+    }
+    xmlFreeDoc(doc);
+
+    error = xmlGetLastError();
+    if (error->code != XML_ERR_UNSUPPORTED_ENCODING ||
+        error->level != XML_ERR_WARNING ||
+        strcmp(error->message, "Unsupported encoding: #unsupported\n") != 0)
+    {
+        fprintf(stderr, "xmlReadDoc failed to raise correct error\n");
+        err = 1;
+    }
+
+    return err;
+}
+
+#ifdef LIBXML_SAX1_ENABLED
+static int
+testBalancedChunk(void) {
+    xmlNodePtr list;
+    xmlNodePtr elem;
+    int ret;
+    int err = 0;
+
+    ret = xmlParseBalancedChunkMemory(NULL, NULL, NULL, 0,
+            BAD_CAST "start <node xml:lang='en'>abc</node> end", &list);
+
+    if ((ret != XML_ERR_OK) ||
+        (list == NULL) ||
+        ((elem = list->next) == NULL) ||
+        (elem->type != XML_ELEMENT_NODE) ||
+        (elem->nsDef == NULL) ||
+        (!xmlStrEqual(elem->nsDef->href, XML_XML_NAMESPACE))) {
+        fprintf(stderr, "xmlParseBalancedChunkMemory failed\n");
+        err = 1;
+    }
+
+    xmlFreeNodeList(list);
+
+    return(err);
+}
+#endif
 
 #ifdef LIBXML_PUSH_ENABLED
 static int
@@ -66,14 +145,147 @@
 }
 #endif
 
+#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_XINCLUDE_ENABLED)
+typedef struct {
+    char *message;
+    int code;
+} testReaderErrorCtxt;
+
+static void
+testReaderError(void *arg, const char *msg,
+                xmlParserSeverities severity ATTRIBUTE_UNUSED,
+                xmlTextReaderLocatorPtr locator ATTRIBUTE_UNUSED) {
+    testReaderErrorCtxt *ctxt = arg;
+
+    if (ctxt->message != NULL)
+        xmlFree(ctxt->message);
+    ctxt->message = xmlMemStrdup(msg);
+}
+
+static void
+testStructuredReaderError(void *arg, const xmlError *error) {
+    testReaderErrorCtxt *ctxt = arg;
+
+    if (ctxt->message != NULL)
+        xmlFree(ctxt->message);
+    ctxt->message = xmlMemStrdup(error->message);
+    ctxt->code = error->code;
+}
+
+static int
+testReaderXIncludeError(void) {
+    /*
+     * Test whether XInclude errors are reported to the custom error
+     * handler of a reader.
+     */
+    const char *doc =
+        "<doc xmlns:xi='http://www.w3.org/2001/XInclude'>\n"
+        "  <xi:include/>\n"
+        "</doc>\n";
+    xmlTextReader *reader;
+    testReaderErrorCtxt errorCtxt;
+    int err = 0;
+
+    reader = xmlReaderForDoc(BAD_CAST doc, NULL, NULL, XML_PARSE_XINCLUDE);
+    xmlTextReaderSetErrorHandler(reader, testReaderError, &errorCtxt);
+    errorCtxt.message = NULL;
+    errorCtxt.code = 0;
+    while (xmlTextReaderRead(reader) > 0)
+        ;
+
+    if (errorCtxt.message == NULL ||
+        strstr(errorCtxt.message, "href or xpointer") == NULL) {
+        fprintf(stderr, "xmlTextReaderSetErrorHandler failed\n");
+        err = 1;
+    }
+
+    xmlFree(errorCtxt.message);
+    xmlFreeTextReader(reader);
+
+    reader = xmlReaderForDoc(BAD_CAST doc, NULL, NULL, XML_PARSE_XINCLUDE);
+    xmlTextReaderSetStructuredErrorHandler(reader, testStructuredReaderError,
+                                           &errorCtxt);
+    errorCtxt.message = NULL;
+    errorCtxt.code = 0;
+    while (xmlTextReaderRead(reader) > 0)
+        ;
+
+    if (errorCtxt.code != XML_XINCLUDE_NO_HREF ||
+        errorCtxt.message == NULL ||
+        strstr(errorCtxt.message, "href or xpointer") == NULL) {
+        fprintf(stderr, "xmlTextReaderSetStructuredErrorHandler failed\n");
+        err = 1;
+    }
+
+    xmlFree(errorCtxt.message);
+    xmlFreeTextReader(reader);
+
+    return err;
+}
+#endif
+
+#ifdef LIBXML_WRITER_ENABLED
+static int
+testWriterIOWrite(void *ctxt, const char *data, int len) {
+    (void) ctxt;
+    (void) data;
+
+    return len;
+}
+
+static int
+testWriterIOClose(void *ctxt) {
+    (void) ctxt;
+
+    return XML_IO_ENAMETOOLONG;
+}
+
+static int
+testWriterClose(void){
+    xmlOutputBufferPtr out;
+    xmlTextWriterPtr writer;
+    int err = 0;
+    int result;
+
+    out = xmlOutputBufferCreateIO(testWriterIOWrite, testWriterIOClose,
+                                  NULL, NULL);
+    writer = xmlNewTextWriter(out);
+    xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
+    xmlTextWriterStartElement(writer, BAD_CAST "elem");
+    xmlTextWriterEndElement(writer);
+    xmlTextWriterEndDocument(writer);
+    result = xmlTextWriterClose(writer);
+
+    if (result != XML_IO_ENAMETOOLONG) {
+        fprintf(stderr, "xmlTextWriterClose reported wrong error %d\n",
+                result);
+        err = 1;
+    }
+
+    xmlFreeTextWriter(writer);
+    return err;
+}
+#endif
+
 int
 main(void) {
     int err = 0;
 
+    err |= testStandaloneWithEncoding();
+    err |= testUnsupportedEncoding();
+#ifdef LIBXML_SAX1_ENABLED
+    err |= testBalancedChunk();
+#endif
 #ifdef LIBXML_PUSH_ENABLED
     err |= testHugePush();
     err |= testHugeEncodedChunk();
 #endif
+#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_XINCLUDE_ENABLED)
+    err |= testReaderXIncludeError();
+#endif
+#ifdef LIBXML_WRITER_ENABLED
+    err |= testWriterClose();
+#endif
 
     return err;
 }
diff --git a/src/testrecurse.c b/src/testrecurse.c
index 6fdf1fd..0791c1c 100644
--- a/src/testrecurse.c
+++ b/src/testrecurse.c
@@ -359,279 +359,11 @@
     return(ret);
 }
 
-/*
- * Trapping the error messages at the generic level to grab the equivalent of
- * stderr messages on CLI tools.
- */
-static char testErrors[32769];
-static int testErrorsSize = 0;
-
-static void
-channel(void *ctx  ATTRIBUTE_UNUSED, const char *msg, ...) {
-    va_list args;
-    int res;
-
-    if (testErrorsSize >= 32768)
-        return;
-    va_start(args, msg);
-    res = vsnprintf(&testErrors[testErrorsSize],
-                    32768 - testErrorsSize,
-		    msg, args);
-    va_end(args);
-    if (testErrorsSize + res >= 32768) {
-        /* buffer is full */
-	testErrorsSize = 32768;
-	testErrors[testErrorsSize] = 0;
-    } else {
-        testErrorsSize += res;
-    }
-    testErrors[testErrorsSize] = 0;
-}
-
-/**
- * xmlParserPrintFileContext:
- * @input:  an xmlParserInputPtr input
- *
- * Displays current context within the input content for error tracking
- */
-
-static void
-xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
-		xmlGenericErrorFunc chanl, void *data ) {
-    const xmlChar *cur, *base;
-    unsigned int n, col;	/* GCC warns if signed, because compared with sizeof() */
-    xmlChar  content[81]; /* space for 80 chars + line terminator */
-    xmlChar *ctnt;
-
-    if (input == NULL) return;
-    cur = input->cur;
-    base = input->base;
-    /* skip backwards over any end-of-lines */
-    while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
-	cur--;
-    }
-    n = 0;
-    /* search backwards for beginning-of-line (to max buff size) */
-    while ((n++ < (sizeof(content)-1)) && (cur > base) &&
-   (*(cur) != '\n') && (*(cur) != '\r'))
-        cur--;
-    if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
-    /* calculate the error position in terms of the current position */
-    col = input->cur - cur;
-    /* search forward for end-of-line (to max buff size) */
-    n = 0;
-    ctnt = content;
-    /* copy selected text to our buffer */
-    while ((*cur != 0) && (*(cur) != '\n') &&
-   (*(cur) != '\r') && (n < sizeof(content)-1)) {
-		*ctnt++ = *cur++;
-	n++;
-    }
-    *ctnt = 0;
-    /* print out the selected text */
-    chanl(data ,"%s\n", content);
-    /* create blank line with problem pointer */
-    n = 0;
-    ctnt = content;
-    /* (leave buffer space for pointer + line terminator) */
-    while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
-	if (*(ctnt) != '\t')
-	    *(ctnt) = ' ';
-	ctnt++;
-    }
-    *ctnt++ = '^';
-    *ctnt = 0;
-    chanl(data ,"%s\n", content);
-}
-
-static void
-testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, const xmlError *err) {
-    char *file = NULL;
-    int line = 0;
-    int code = -1;
-    int domain;
-    void *data = NULL;
-    const char *str;
-    const xmlChar *name = NULL;
-    xmlNodePtr node;
-    xmlErrorLevel level;
-    xmlParserInputPtr input = NULL;
-    xmlParserInputPtr cur = NULL;
-    xmlParserCtxtPtr ctxt = NULL;
-
-    if (err == NULL)
-        return;
-
-    file = err->file;
-    line = err->line;
-    code = err->code;
-    domain = err->domain;
-    level = err->level;
-    node = err->node;
-    if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
-        (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
-	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
-	ctxt = err->ctxt;
-    }
-    str = err->message;
-
-    if (code == XML_ERR_OK)
-        return;
-
-    if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
-        name = node->name;
-
-    /*
-     * Maintain the compatibility with the legacy error handling
-     */
-    if (ctxt != NULL) {
-        input = ctxt->input;
-        if ((input != NULL) && (input->filename == NULL) &&
-            (ctxt->inputNr > 1)) {
-            cur = input;
-            input = ctxt->inputTab[ctxt->inputNr - 2];
-        }
-        if (input != NULL) {
-            if (input->filename)
-                channel(data, "%s:%d: ", input->filename, input->line);
-            else if ((line != 0) && (domain == XML_FROM_PARSER))
-                channel(data, "Entity: line %d: ", input->line);
-        }
-    } else {
-        if (file != NULL)
-            channel(data, "%s:%d: ", file, line);
-        else if ((line != 0) && (domain == XML_FROM_PARSER))
-            channel(data, "Entity: line %d: ", line);
-    }
-    if (name != NULL) {
-        channel(data, "element %s: ", name);
-    }
-    if (code == XML_ERR_OK)
-        return;
-    switch (domain) {
-        case XML_FROM_PARSER:
-            channel(data, "parser ");
-            break;
-        case XML_FROM_NAMESPACE:
-            channel(data, "namespace ");
-            break;
-        case XML_FROM_DTD:
-        case XML_FROM_VALID:
-            channel(data, "validity ");
-            break;
-        case XML_FROM_HTML:
-            channel(data, "HTML parser ");
-            break;
-        case XML_FROM_MEMORY:
-            channel(data, "memory ");
-            break;
-        case XML_FROM_OUTPUT:
-            channel(data, "output ");
-            break;
-        case XML_FROM_IO:
-            channel(data, "I/O ");
-            break;
-        case XML_FROM_XINCLUDE:
-            channel(data, "XInclude ");
-            break;
-        case XML_FROM_XPATH:
-            channel(data, "XPath ");
-            break;
-        case XML_FROM_XPOINTER:
-            channel(data, "parser ");
-            break;
-        case XML_FROM_REGEXP:
-            channel(data, "regexp ");
-            break;
-        case XML_FROM_MODULE:
-            channel(data, "module ");
-            break;
-        case XML_FROM_SCHEMASV:
-            channel(data, "Schemas validity ");
-            break;
-        case XML_FROM_SCHEMASP:
-            channel(data, "Schemas parser ");
-            break;
-        case XML_FROM_RELAXNGP:
-            channel(data, "Relax-NG parser ");
-            break;
-        case XML_FROM_RELAXNGV:
-            channel(data, "Relax-NG validity ");
-            break;
-        case XML_FROM_CATALOG:
-            channel(data, "Catalog ");
-            break;
-        case XML_FROM_C14N:
-            channel(data, "C14N ");
-            break;
-        case XML_FROM_XSLT:
-            channel(data, "XSLT ");
-            break;
-        default:
-            break;
-    }
-    if (code == XML_ERR_OK)
-        return;
-    switch (level) {
-        case XML_ERR_NONE:
-            channel(data, ": ");
-            break;
-        case XML_ERR_WARNING:
-            channel(data, "warning : ");
-            break;
-        case XML_ERR_ERROR:
-            channel(data, "error : ");
-            break;
-        case XML_ERR_FATAL:
-            channel(data, "error : ");
-            break;
-    }
-    if (code == XML_ERR_OK)
-        return;
-    if (str != NULL) {
-        int len;
-	len = xmlStrlen((const xmlChar *)str);
-	if ((len > 0) && (str[len - 1] != '\n'))
-	    channel(data, "%s\n", str);
-	else
-	    channel(data, "%s", str);
-    } else {
-        channel(data, "%s\n", "out of memory error");
-    }
-    if (code == XML_ERR_OK)
-        return;
-
-    if (ctxt != NULL) {
-        xmlParserPrintFileContextInternal(input, channel, data);
-        if (cur != NULL) {
-            if (cur->filename)
-                channel(data, "%s:%d: \n", cur->filename, cur->line);
-            else if ((line != 0) && (domain == XML_FROM_PARSER))
-                channel(data, "Entity: line %d: \n", cur->line);
-            xmlParserPrintFileContextInternal(cur, channel, data);
-        }
-    }
-    if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
-        (err->int1 < 100) &&
-	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
-	xmlChar buf[150];
-	int i;
-
-	channel(data, "%s\n", err->str1);
-	for (i=0;i < err->int1;i++)
-	     buf[i] = ' ';
-	buf[i++] = '^';
-	buf[i] = 0;
-	channel(data, "%s\n", buf);
-    }
-}
-
 static void
 initializeLibxml2(void) {
     xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
     xmlInitParser();
     xmlSetExternalEntityLoader(testExternalEntityLoader);
-    xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
     /*
      * register the new I/O handlers
      */
@@ -747,7 +479,7 @@
      * without XML_PARSE_NOENT. The validation result doesn't matter
      * anyway.
      */
-    int parserOptions = XML_PARSE_DTDVALID;
+    int parserOptions = XML_PARSE_DTDVALID | XML_PARSE_NOERROR;
 
     nb_tests++;
 
@@ -760,7 +492,7 @@
      * base of the test, parse with the old API
      */
     doc = xmlCtxtReadFile(ctxt, filename, NULL, parserOptions);
-    if ((doc != NULL) || (ctxt->lastError.code != XML_ERR_ENTITY_LOOP)) {
+    if ((doc != NULL) || (ctxt->lastError.code != XML_ERR_RESOURCE_LIMIT)) {
         fprintf(stderr, "Failed to detect recursion in %s\n", filename);
 	xmlFreeParserCtxt(ctxt);
 	xmlFreeDoc(doc);
@@ -1104,8 +836,6 @@
 	    } else {
 		mem = xmlMemUsed();
 		extraMemoryFromResolver = 0;
-		testErrorsSize = 0;
-		testErrors[0] = 0;
 		res = tst->func(globbuf.gl_pathv[i], result, error,
 		                tst->options | XML_PARSE_COMPACT);
 		xmlResetLastError();
@@ -1124,7 +854,6 @@
 			err++;
 		    }
 		}
-		testErrorsSize = 0;
 	    }
 	    if (result)
 		free(result);
@@ -1133,8 +862,6 @@
 	}
 	globfree(&globbuf);
     } else {
-        testErrorsSize = 0;
-	testErrors[0] = 0;
 	extraMemoryFromResolver = 0;
         res = tst->func(NULL, NULL, NULL, tst->options);
 	if (res != 0) {
diff --git a/src/threads.c b/src/threads.c
index 461f4a5..36347c2 100644
--- a/src/threads.c
+++ b/src/threads.c
@@ -30,6 +30,7 @@
 #include "private/dict.h"
 #include "private/enc.h"
 #include "private/globals.h"
+#include "private/io.h"
 #include "private/memory.h"
 #include "private/threads.h"
 #include "private/xpath.h"
@@ -498,9 +499,8 @@
     if (global_init_lock == NULL) {
         cs = malloc(sizeof(CRITICAL_SECTION));
         if (cs == NULL) {
-            xmlGenericError(xmlGenericErrorContext,
-                            "xmlGlobalInitMutexLock: out of memory\n");
-            return;
+            fprintf(stderr, "libxml2: xmlInitParser: out of memory\n");
+            abort();
         }
         InitializeCriticalSection(cs);
 
@@ -583,19 +583,15 @@
             atexit(xmlCleanupParser);
 #endif
 
-        xmlInitMemoryInternal(); /* Should come second */
+        xmlInitRandom(); /* Required by xmlInitGlobalsInternal */
+        xmlInitMemoryInternal();
         xmlInitGlobalsInternal();
-        xmlInitRandom();
         xmlInitDictInternal();
         xmlInitEncodingInternal();
 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
         xmlInitXPathInternal();
 #endif
-
-        xmlRegisterDefaultInputCallbacks();
-#ifdef LIBXML_OUTPUT_ENABLED
-        xmlRegisterDefaultOutputCallbacks();
-#endif /* LIBXML_OUTPUT_ENABLED */
+        xmlInitIOCallbacks();
 
         xmlParserInnerInitialized = 1;
     }
@@ -644,11 +640,6 @@
 
     /* These functions should never call xmlFree. */
 
-    xmlCleanupInputCallbacks();
-#ifdef LIBXML_OUTPUT_ENABLED
-    xmlCleanupOutputCallbacks();
-#endif
-
     xmlCleanupDictInternal();
     xmlCleanupRandom();
     xmlCleanupGlobalsInternal();
diff --git a/src/tree.c b/src/tree.c
index d3194e4..f9cab14 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -1210,6 +1210,16 @@
     xmlEntityPtr ent;
     xmlBufPtr buf;
 
+    /*
+     * This function should only receive valid attribute values that
+     * were checked by the parser, typically by xmlParseAttValueComplex
+     * calling xmlStringDecodeEntities.
+     *
+     * In recovery mode, the parser can produce invalid attribute
+     * values. For now, we ignore any errors silently. If this is fixed,
+     * we could add assertions here to catch parser issues.
+     */
+
     if (value == NULL) return(NULL);
     cur = value;
     end = cur + len;
@@ -1239,16 +1249,6 @@
 		else
 		    tmp = 0;
 		while (tmp != ';') { /* Non input consuming loop */
-                    /*
-                     * If you find an integer overflow here when fuzzing,
-                     * the bug is probably elsewhere. This function should
-                     * only receive entities that were already validated by
-                     * the parser, typically by xmlParseAttValueComplex
-                     * calling xmlStringDecodeEntities.
-                     *
-                     * So it's better *not* to check for overflow to
-                     * potentially discover new bugs.
-                     */
 		    if ((tmp >= '0') && (tmp <= '9'))
 			charval = charval * 16 + (tmp - '0');
 		    else if ((tmp >= 'a') && (tmp <= 'f'))
@@ -1299,7 +1299,7 @@
 		q = cur;
 		while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
 		if ((cur >= end) || (*cur == 0))
-		    goto out;
+		    break;
 		if (cur != q) {
 		    /*
 		     * Predefined entities don't generate nodes
@@ -1353,7 +1353,6 @@
                                     goto out;
                                 }
                             }
-                            ent->owner = 1;
                             ent->flags |= XML_ENT_PARSED;
 			    temp = ent->children;
 			    while (temp) {
@@ -1443,6 +1442,16 @@
     xmlEntityPtr ent;
     xmlBufPtr buf;
 
+    /*
+     * This function should only receive valid attribute values that
+     * were checked by the parser, typically by xmlParseAttValueComplex
+     * calling xmlStringDecodeEntities.
+     *
+     * In recovery mode, the parser can produce invalid attribute
+     * values. For now, we ignore any errors silently. If this is fixed,
+     * we could add assertions here to catch parser issues.
+     */
+
     if (value == NULL) return(NULL);
 
     buf = xmlBufCreateSize(0);
@@ -1467,7 +1476,6 @@
 		cur += 3;
 		tmp = *cur;
 		while (tmp != ';') { /* Non input consuming loop */
-                    /* Don't check for integer overflow, see above. */
 		    if ((tmp >= '0') && (tmp <= '9'))
 			charval = charval * 16 + (tmp - '0');
 		    else if ((tmp >= 'a') && (tmp <= 'f'))
@@ -1509,7 +1517,7 @@
 		q = cur;
 		while ((*cur != 0) && (*cur != ';')) cur++;
 		if (*cur == 0)
-		    goto out;
+		    break;
 		if (cur != q) {
 		    /*
 		     * Predefined entities don't generate nodes
@@ -1566,7 +1574,6 @@
                                     goto out;
                                 }
                             }
-			    ent->owner = 1;
                             ent->flags |= XML_ENT_PARSED;
 			    temp = ent->children;
 			    while (temp) {
@@ -1657,7 +1664,7 @@
     int attr;
 
     if (list == NULL)
-        return (NULL);
+        return xmlStrdup(BAD_CAST "");
     if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
         attr = 1;
     else
@@ -1706,7 +1713,7 @@
                         if (ret == NULL)
                             goto error;
                     }
-                } else {
+                } else if (node->content != NULL) {
                     ret = xmlStrcat(ret, node->content);
                     if (ret == NULL)
                         goto error;
@@ -1727,6 +1734,8 @@
         }
         node = node->next;
     }
+    if (ret == NULL)
+        ret = xmlStrdup(BAD_CAST "");
     return (ret);
 
 error:
@@ -1755,7 +1764,7 @@
     xmlEntityPtr ent;
 
     if (list == NULL)
-        return (NULL);
+        return xmlStrdup(BAD_CAST "");
 
     while (node != NULL) {
         if ((node->type == XML_TEXT_NODE) ||
@@ -1807,6 +1816,8 @@
         }
         node = node->next;
     }
+    if (ret == NULL)
+        ret = xmlStrdup(BAD_CAST "");
     return (ret);
 }
 #endif /* LIBXML_TREE_ENABLED */
@@ -5408,8 +5419,10 @@
 	}
 	if (cur->type == XML_ELEMENT_NODE) {
 	    if (xmlNodeGetAttrValue(cur, BAD_CAST "base", XML_XML_NAMESPACE,
-                                    &base) < 0)
+                                    &base) < 0) {
+                xmlFree(ret);
                 return(-1);
+            }
 	    if (base != NULL) {
 		if (ret != NULL) {
 		    res = xmlBuildURISafe(ret, base, &newbase);
diff --git a/src/uri.c b/src/uri.c
index bfe8a68..1470b5a 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -51,7 +51,6 @@
  *            "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
  *            "u" | "v" | "w" | "x" | "y" | "z"
  */
-
 #define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
 
 /*
@@ -72,7 +71,6 @@
 /*
  * alphanum = alpha | digit
  */
-
 #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
 
 /*
@@ -86,16 +84,15 @@
 /*
  * unwise = "{" | "}" | "|" | "\" | "^" | "`"
  */
-
 #define IS_UNWISE(p)                                                    \
       (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) ||         \
        ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) ||        \
        ((*(p) == ']')) || ((*(p) == '`')))
+
 /*
  * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
  *            "[" | "]"
  */
-
 #define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
         ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
         ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
@@ -104,13 +101,11 @@
 /*
  * unreserved = alphanum | mark
  */
-
 #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
 
 /*
  * Skip to next pointer char, handle escaped sequences
  */
-
 #define NEXT(p) ((*p == '%')? p += 3 : p++)
 
 /*
@@ -122,7 +117,6 @@
  *
  * path          = [ abs_path | opaque_part ]
  */
-
 #define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n))
 
 /************************************************************************
@@ -164,7 +158,7 @@
 /*
  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
  */
-#define ISA_UNRESERVED(p)						\
+#define ISA_STRICTLY_UNRESERVED(p)					\
       ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) ||		\
        ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
 
@@ -177,10 +171,47 @@
 /*
  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
  */
-#define ISA_PCHAR(p)							\
-     (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) ||	\
+#define ISA_PCHAR(u, p)							\
+     (ISA_UNRESERVED(u, p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) ||	\
       ((*(p) == ':')) || ((*(p) == '@')))
 
+/*
+ * From https://www.w3.org/TR/leiri/
+ *
+ * " " / "<" / ">" / '"' / "{" / "}" / "|"
+ * / "\" / "^" / "`" / %x0-1F / %x7F-D7FF
+ * / %xE000-FFFD / %x10000-10FFFF
+ */
+#define ISA_UCSCHAR(p) \
+    ((*(p) <= 0x20) || (*(p) >= 0x7F) || (*(p) == '<') || (*(p) == '>') || \
+     (*(p) == '"')  || (*(p) == '{')  || (*(p) == '}') || (*(p) == '|') || \
+     (*(p) == '\\') || (*(p) == '^')  || (*(p) == '`'))
+
+#define ISA_UNRESERVED(u, p) (xmlIsUnreserved(u, p))
+
+#define XML_URI_ALLOW_UNWISE    1
+#define XML_URI_NO_UNESCAPE     2
+#define XML_URI_ALLOW_UCSCHAR   4
+
+static int
+xmlIsUnreserved(xmlURIPtr uri, const char *cur) {
+    if (uri == NULL)
+        return(0);
+
+    if (ISA_STRICTLY_UNRESERVED(cur))
+        return(1);
+
+    if (uri->cleanup & XML_URI_ALLOW_UNWISE) {
+        if (IS_UNWISE(cur))
+            return(1);
+    } else if (uri->cleanup & XML_URI_ALLOW_UCSCHAR) {
+        if (ISA_UCSCHAR(cur))
+            return(1);
+    }
+
+    return(0);
+}
+
 /**
  * xmlParse3986Scheme:
  * @uri:  pointer to an URI structure
@@ -234,14 +265,13 @@
 
     cur = *str;
 
-    while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
-           (*cur == '[') || (*cur == ']') ||
-           ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
+    while ((ISA_PCHAR(uri, cur)) || (*cur == '/') || (*cur == '?') ||
+           (*cur == '[') || (*cur == ']'))
         NEXT(cur);
     if (uri != NULL) {
         if (uri->fragment != NULL)
             xmlFree(uri->fragment);
-	if (uri->cleanup & 2)
+	if (uri->cleanup & XML_URI_NO_UNESCAPE)
 	    uri->fragment = STRNDUP(*str, cur - *str);
 	else
 	    uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
@@ -270,13 +300,12 @@
 
     cur = *str;
 
-    while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
-           ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
+    while ((ISA_PCHAR(uri, cur)) || (*cur == '/') || (*cur == '?'))
         NEXT(cur);
     if (uri != NULL) {
         if (uri->query != NULL)
             xmlFree(uri->query);
-	if (uri->cleanup & 2)
+	if (uri->cleanup & XML_URI_NO_UNESCAPE)
 	    uri->query = STRNDUP(*str, cur - *str);
 	else
 	    uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
@@ -353,13 +382,13 @@
     const char *cur;
 
     cur = *str;
-    while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) ||
+    while (ISA_UNRESERVED(uri, cur) || ISA_PCT_ENCODED(cur) ||
            ISA_SUB_DELIM(cur) || (*cur == ':'))
 	NEXT(cur);
     if (*cur == '@') {
 	if (uri != NULL) {
 	    if (uri->user != NULL) xmlFree(uri->user);
-	    if (uri->cleanup & 2)
+	    if (uri->cleanup & XML_URI_NO_UNESCAPE)
 		uri->user = STRNDUP(*str, cur - *str);
 	    else
 		uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
@@ -469,7 +498,8 @@
     /*
      * then this should be a hostname which can be empty
      */
-    while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
+    while (ISA_UNRESERVED(uri, cur) ||
+           ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
         NEXT(cur);
 found:
     if (uri != NULL) {
@@ -477,7 +507,7 @@
 	uri->authority = NULL;
 	if (uri->server != NULL) xmlFree(uri->server);
 	if (cur != host) {
-	    if (uri->cleanup & 2)
+	    if (uri->cleanup & XML_URI_NO_UNESCAPE)
 		uri->server = STRNDUP(host, cur - host);
 	    else
 		uri->server = xmlURIUnescapeString(host, cur - host, NULL);
@@ -547,17 +577,17 @@
  * Returns 0 or the error code
  */
 static int
-xmlParse3986Segment(const char **str, char forbid, int empty)
+xmlParse3986Segment(xmlURIPtr uri, const char **str, char forbid, int empty)
 {
     const char *cur;
 
     cur = *str;
-    if (!ISA_PCHAR(cur)) {
+    if (!ISA_PCHAR(uri, cur)) {
         if (empty)
 	    return(0);
 	return(1);
     }
-    while (ISA_PCHAR(cur) && (*cur != forbid))
+    while (ISA_PCHAR(uri, cur) && (*cur != forbid))
         NEXT(cur);
     *str = cur;
     return (0);
@@ -585,13 +615,13 @@
 
     while (*cur == '/') {
         cur++;
-	ret = xmlParse3986Segment(&cur, 0, 1);
+	ret = xmlParse3986Segment(uri, &cur, 0, 1);
 	if (ret != 0) return(ret);
     }
     if (uri != NULL) {
 	if (uri->path != NULL) xmlFree(uri->path);
         if (*str != cur) {
-            if (uri->cleanup & 2)
+            if (uri->cleanup & XML_URI_NO_UNESCAPE)
                 uri->path = STRNDUP(*str, cur - *str);
             else
                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
@@ -628,18 +658,18 @@
     if (*cur != '/')
         return(1);
     cur++;
-    ret = xmlParse3986Segment(&cur, 0, 0);
+    ret = xmlParse3986Segment(uri, &cur, 0, 0);
     if (ret == 0) {
 	while (*cur == '/') {
 	    cur++;
-	    ret = xmlParse3986Segment(&cur, 0, 1);
+	    ret = xmlParse3986Segment(uri, &cur, 0, 1);
 	    if (ret != 0) return(ret);
 	}
     }
     if (uri != NULL) {
 	if (uri->path != NULL) xmlFree(uri->path);
         if (cur != *str) {
-            if (uri->cleanup & 2)
+            if (uri->cleanup & XML_URI_NO_UNESCAPE)
                 uri->path = STRNDUP(*str, cur - *str);
             else
                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
@@ -673,17 +703,17 @@
 
     cur = *str;
 
-    ret = xmlParse3986Segment(&cur, 0, 0);
+    ret = xmlParse3986Segment(uri, &cur, 0, 0);
     if (ret != 0) return(ret);
     while (*cur == '/') {
         cur++;
-	ret = xmlParse3986Segment(&cur, 0, 1);
+	ret = xmlParse3986Segment(uri, &cur, 0, 1);
 	if (ret != 0) return(ret);
     }
     if (uri != NULL) {
 	if (uri->path != NULL) xmlFree(uri->path);
         if (cur != *str) {
-            if (uri->cleanup & 2)
+            if (uri->cleanup & XML_URI_NO_UNESCAPE)
                 uri->path = STRNDUP(*str, cur - *str);
             else
                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
@@ -717,17 +747,17 @@
 
     cur = *str;
 
-    ret = xmlParse3986Segment(&cur, ':', 0);
+    ret = xmlParse3986Segment(uri, &cur, ':', 0);
     if (ret != 0) return(ret);
     while (*cur == '/') {
         cur++;
-	ret = xmlParse3986Segment(&cur, 0, 1);
+	ret = xmlParse3986Segment(uri, &cur, 0, 1);
 	if (ret != 0) return(ret);
     }
     if (uri != NULL) {
 	if (uri->path != NULL) xmlFree(uri->path);
         if (cur != *str) {
-            if (uri->cleanup & 2)
+            if (uri->cleanup & XML_URI_NO_UNESCAPE)
                 uri->path = STRNDUP(*str, cur - *str);
             else
                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
@@ -780,7 +810,7 @@
     } else if (*cur == '/') {
         ret = xmlParse3986PathAbsolute(uri, &cur);
 	if (ret != 0) return(ret);
-    } else if (ISA_PCHAR(cur)) {
+    } else if (ISA_PCHAR(uri, cur)) {
         ret = xmlParse3986PathRootless(uri, &cur);
 	if (ret != 0) return(ret);
     } else {
@@ -823,7 +853,7 @@
     } else if (*str == '/') {
 	ret = xmlParse3986PathAbsolute(uri, &str);
 	if (ret != 0) return(ret);
-    } else if (ISA_PCHAR(str)) {
+    } else if (ISA_PCHAR(uri, str)) {
         ret = xmlParse3986PathNoScheme(uri, &str);
 	if (ret != 0) return(ret);
     } else {
@@ -1023,7 +1053,7 @@
     uri = xmlCreateURI();
     if (uri != NULL) {
         if (raw) {
-	    uri->cleanup |= 2;
+	    uri->cleanup |= XML_URI_NO_UNESCAPE;
 	}
 	ret = xmlParseURIReference(uri, str);
         if (ret) {
@@ -1430,6 +1460,120 @@
  *									*
  ************************************************************************/
 
+static int
+xmlIsPathSeparator(int c, int isFile) {
+    (void) isFile;
+
+    if (c == '/')
+        return(1);
+
+#ifdef _WIN32
+    if (isFile && (c == '\\'))
+        return(1);
+#endif
+
+    return(0);
+}
+
+/**
+ * xmlNormalizePath:
+ * @path:  pointer to the path string
+ * @isFile:  true for filesystem paths, false for URIs
+ *
+ * Normalize a filesystem path or URI.
+ *
+ * Returns 0 or an error code
+ */
+static int
+xmlNormalizePath(char *path, int isFile) {
+    char *cur, *out;
+    int numSeg = 0;
+
+    if (path == NULL)
+	return(-1);
+
+    cur = path;
+    out = path;
+
+    if (*cur == 0)
+        return(0);
+
+    if (xmlIsPathSeparator(*cur, isFile)) {
+        cur++;
+        *out++ = '/';
+    }
+
+    while (*cur != 0) {
+        /*
+         * At this point, out is either empty or ends with a separator.
+         * Collapse multiple separators first.
+         */
+        while (xmlIsPathSeparator(*cur, isFile)) {
+#ifdef _WIN32
+            /* Allow two separators at start of path */
+            if ((isFile) && (out == path + 1))
+                *out++ = '/';
+#endif
+            cur++;
+        }
+
+        if (*cur == '.') {
+            if (cur[1] == 0) {
+                /* Ignore "." at end of path */
+                break;
+            } else if (xmlIsPathSeparator(cur[1], isFile)) {
+                /* Skip "./" */
+                cur += 2;
+                continue;
+            } else if ((cur[1] == '.') &&
+                       ((cur[2] == 0) || xmlIsPathSeparator(cur[2], isFile))) {
+                if (numSeg > 0) {
+                    /* Handle ".." by removing last segment */
+                    do {
+                        out--;
+                    } while ((out > path) &&
+                             !xmlIsPathSeparator(out[-1], isFile));
+                    numSeg--;
+
+                    if (cur[2] == 0)
+                        break;
+                    cur += 3;
+                    continue;
+                } else if (out[0] == '/') {
+                    /* Ignore extraneous ".." in absolute paths */
+                    if (cur[2] == 0)
+                        break;
+                    cur += 3;
+                    continue;
+                } else {
+                    /* Keep "../" at start of relative path */
+                    numSeg--;
+                }
+            }
+        }
+
+        /* Copy segment */
+        while ((*cur != 0) && !xmlIsPathSeparator(*cur, isFile)) {
+            *out++ = *cur++;
+        }
+
+        /* Copy separator */
+        if (*cur != 0) {
+            cur++;
+            *out++ = '/';
+        }
+
+        numSeg++;
+    }
+
+    /* Keep "." if output is empty and it's a file */
+    if ((isFile) && (out <= path))
+        *out++ = '.';
+    *out = 0;
+
+    return(0);
+}
+
 /**
  * xmlNormalizeURIPath:
  * @path:  pointer to the path string
@@ -1443,180 +1587,7 @@
  */
 int
 xmlNormalizeURIPath(char *path) {
-    char *cur, *out;
-
-    if (path == NULL)
-	return(-1);
-
-    /* Skip all initial "/" chars.  We want to get to the beginning of the
-     * first non-empty segment.
-     */
-    cur = path;
-    while (cur[0] == '/')
-      ++cur;
-    if (cur[0] == '\0')
-      return(0);
-
-    /* Keep everything we've seen so far.  */
-    out = cur;
-
-    /*
-     * Analyze each segment in sequence for cases (c) and (d).
-     */
-    while (cur[0] != '\0') {
-	/*
-	 * c) All occurrences of "./", where "." is a complete path segment,
-	 *    are removed from the buffer string.
-	 */
-	if ((cur[0] == '.') && (cur[1] == '/')) {
-	    cur += 2;
-	    /* '//' normalization should be done at this point too */
-	    while (cur[0] == '/')
-		cur++;
-	    continue;
-	}
-
-	/*
-	 * d) If the buffer string ends with "." as a complete path segment,
-	 *    that "." is removed.
-	 */
-	if ((cur[0] == '.') && (cur[1] == '\0'))
-	    break;
-
-	/* Otherwise keep the segment.  */
-	while (cur[0] != '/') {
-            if (cur[0] == '\0')
-              goto done_cd;
-	    (out++)[0] = (cur++)[0];
-	}
-	/* normalize // */
-	while ((cur[0] == '/') && (cur[1] == '/'))
-	    cur++;
-
-        (out++)[0] = (cur++)[0];
-    }
- done_cd:
-    out[0] = '\0';
-
-    /* Reset to the beginning of the first segment for the next sequence.  */
-    cur = path;
-    while (cur[0] == '/')
-      ++cur;
-    if (cur[0] == '\0')
-	return(0);
-
-    /*
-     * Analyze each segment in sequence for cases (e) and (f).
-     *
-     * e) All occurrences of "<segment>/../", where <segment> is a
-     *    complete path segment not equal to "..", are removed from the
-     *    buffer string.  Removal of these path segments is performed
-     *    iteratively, removing the leftmost matching pattern on each
-     *    iteration, until no matching pattern remains.
-     *
-     * f) If the buffer string ends with "<segment>/..", where <segment>
-     *    is a complete path segment not equal to "..", that
-     *    "<segment>/.." is removed.
-     *
-     * To satisfy the "iterative" clause in (e), we need to collapse the
-     * string every time we find something that needs to be removed.  Thus,
-     * we don't need to keep two pointers into the string: we only need a
-     * "current position" pointer.
-     */
-    while (1) {
-        char *segp, *tmp;
-
-        /* At the beginning of each iteration of this loop, "cur" points to
-         * the first character of the segment we want to examine.
-         */
-
-        /* Find the end of the current segment.  */
-        segp = cur;
-        while ((segp[0] != '/') && (segp[0] != '\0'))
-          ++segp;
-
-        /* If this is the last segment, we're done (we need at least two
-         * segments to meet the criteria for the (e) and (f) cases).
-         */
-        if (segp[0] == '\0')
-          break;
-
-        /* If the first segment is "..", or if the next segment _isn't_ "..",
-         * keep this segment and try the next one.
-         */
-        ++segp;
-        if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
-            || ((segp[0] != '.') || (segp[1] != '.')
-                || ((segp[2] != '/') && (segp[2] != '\0')))) {
-          cur = segp;
-          continue;
-        }
-
-        /* If we get here, remove this segment and the next one and back up
-         * to the previous segment (if there is one), to implement the
-         * "iteratively" clause.  It's pretty much impossible to back up
-         * while maintaining two pointers into the buffer, so just compact
-         * the whole buffer now.
-         */
-
-        /* If this is the end of the buffer, we're done.  */
-        if (segp[2] == '\0') {
-          cur[0] = '\0';
-          break;
-        }
-        /* Valgrind complained, strcpy(cur, segp + 3); */
-        /* string will overlap, do not use strcpy */
-        tmp = cur;
-        segp += 3;
-        while ((*tmp++ = *segp++) != 0)
-          ;
-
-        /* If there are no previous segments, then keep going from here.  */
-        segp = cur;
-        while ((segp > path) && ((--segp)[0] == '/'))
-          ;
-        if (segp == path)
-          continue;
-
-        /* "segp" is pointing to the end of a previous segment; find it's
-         * start.  We need to back up to the previous segment and start
-         * over with that to handle things like "foo/bar/../..".  If we
-         * don't do this, then on the first pass we'll remove the "bar/..",
-         * but be pointing at the second ".." so we won't realize we can also
-         * remove the "foo/..".
-         */
-        cur = segp;
-        while ((cur > path) && (cur[-1] != '/'))
-          --cur;
-    }
-    out[0] = '\0';
-
-    /*
-     * g) If the resulting buffer string still begins with one or more
-     *    complete path segments of "..", then the reference is
-     *    considered to be in error. Implementations may handle this
-     *    error by retaining these components in the resolved path (i.e.,
-     *    treating them as part of the final URI), by removing them from
-     *    the resolved path (i.e., discarding relative levels above the
-     *    root), or by avoiding traversal of the reference.
-     *
-     * We discard them from the final path.
-     */
-    if (path[0] == '/') {
-      cur = path;
-      while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
-             && ((cur[3] == '/') || (cur[3] == '\0')))
-	cur += 3;
-
-      if (cur != path) {
-	out = path;
-	while (cur[0] != '\0')
-          (out++)[0] = (cur++)[0];
-	out[0] = 0;
-      }
-    }
-
-    return(0);
+    return(xmlNormalizePath(path, 0));
 }
 
 static int is_hex(char c) {
@@ -1694,8 +1665,9 @@
  * @str:  string to escape
  * @list: exception list string of chars not to escape
  *
- * This routine escapes a string to hex, ignoring reserved characters
- * (a-z, A-Z, 0-9, "@-_.!~*'()") and the characters in the exception list.
+ * This routine escapes a string to hex, ignoring unreserved characters
+ * a-z, A-Z, 0-9, "-._~", a few sub-delims "!*'()", the gen-delim "@"
+ * (why?) and the characters in the exception list.
  *
  * Returns a new escaped string or NULL in case of error.
  */
@@ -1786,7 +1758,7 @@
 	/*
 	 * Allow escaping errors in the unescaped form
 	 */
-        uri->cleanup = 1;
+        uri->cleanup = XML_URI_ALLOW_UNWISE;
         ret2 = xmlParseURIReference(uri, (const char *)str);
         if (ret2) {
             xmlFreeURI(uri);
@@ -1895,8 +1867,129 @@
  *									*
  ************************************************************************/
 
+static int
+xmlIsAbsolutePath(const xmlChar *path) {
+    int c = path[0];
+
+    if (xmlIsPathSeparator(c, 1))
+        return(1);
+
+#ifdef _WIN32
+    if ((((c >= 'A') && (c <= 'Z')) ||
+         ((c >= 'a') && (c <= 'z'))) &&
+        (path[1] == ':'))
+        return(1);
+#endif
+
+    return(0);
+}
+
 /**
- * xmlBuildURISafe:
+ * xmlResolvePath:
+ * @ref:  the filesystem path
+ * @base:  the base value
+ * @out:  pointer to result URI
+ *
+ * Resolves a filesystem path from a base path.
+ *
+ * Returns 0 on success, -1 if a memory allocation failed or an error
+ * code if URI or base are invalid.
+ */
+static int
+xmlResolvePath(const xmlChar *escRef, const xmlChar *base, xmlChar **out) {
+    const xmlChar *fragment;
+    xmlChar *tmp = NULL;
+    xmlChar *ref = NULL;
+    xmlChar *result = NULL;
+    int ret = -1;
+    int i;
+
+    if (out == NULL)
+        return(1);
+    *out = NULL;
+
+    if ((escRef == NULL) || (escRef[0] == 0)) {
+        if ((base == NULL) || (base[0] == 0))
+            return(1);
+        ref = xmlStrdup(base);
+        if (ref == NULL)
+            goto err_memory;
+        *out = ref;
+        return(0);
+    }
+
+    /*
+     * If a URI is resolved, we can assume it is a valid URI and not
+     * a filesystem path. This means we have to unescape the part
+     * before the fragment.
+     */
+    fragment = xmlStrchr(escRef, '#');
+    if (fragment != NULL) {
+        tmp = xmlStrndup(escRef, fragment - escRef);
+        if (tmp == NULL)
+            goto err_memory;
+        escRef = tmp;
+    }
+
+    ref = (xmlChar *) xmlURIUnescapeString((char *) escRef, -1, NULL);
+    if (ref == NULL)
+        goto err_memory;
+
+    if ((base == NULL) || (base[0] == 0))
+        goto done;
+
+    if (xmlIsAbsolutePath(ref))
+        goto done;
+
+    /*
+     * Remove last segment from base
+     */
+    i = xmlStrlen(base);
+    while ((i > 0) && !xmlIsPathSeparator(base[i-1], 1))
+        i--;
+
+    /*
+     * Concatenate base and ref
+     */
+    if (i > 0) {
+        int refLen = xmlStrlen(ref);
+
+        result = xmlMalloc(i + refLen + 1);
+        if (result == NULL)
+            goto err_memory;
+
+        memcpy(result, base, i);
+        memcpy(result + i, ref, refLen + 1);
+    }
+
+    /*
+     * Normalize
+     */
+    xmlNormalizePath((char *) result, 1);
+
+done:
+    if (result == NULL) {
+        result = ref;
+        ref = NULL;
+    }
+
+    if (fragment != NULL) {
+        result = xmlStrcat(result, fragment);
+        if (result == NULL)
+            goto err_memory;
+    }
+
+    *out = result;
+    ret = 0;
+
+err_memory:
+    xmlFree(tmp);
+    xmlFree(ref);
+    return(ret);
+}
+
+/**
+ * xmlBulidURISafe:
  * @URI:  the URI instance found in the document
  * @base:  the base value
  * @valPtr:  pointer to result URI
@@ -1944,6 +2037,16 @@
             ret = -1;
 	goto done;
     }
+
+    /*
+     * If base has no scheme or authority, it is assumed to be a
+     * filesystem path.
+     */
+    if (xmlStrstr(base, BAD_CAST "://") == NULL) {
+        xmlFreeURI(ref);
+        return(xmlResolvePath(URI, base, valPtr));
+    }
+
     ret = xmlParseURISafe((const char *) base, &bas);
     if (ret < 0)
         goto done;
@@ -2535,157 +2638,41 @@
  * xmlCanonicPath:
  * @path:  the resource locator in a filesystem notation
  *
- * Constructs a canonic path from the specified path.
+ * Prepares a path.
  *
- * Returns a new canonic path, or a duplicate of the path parameter if the
- * construction fails. The caller is responsible for freeing the memory occupied
+ * If the path contains the substring "://", it is considered a
+ * Legacy Extended IRI. Characters which aren't allowed in URIs are
+ * escaped.
+ *
+ * Otherwise, the path is considered a filesystem path which is
+ * copied without modification.
+ *
+ * The caller is responsible for freeing the memory occupied
  * by the returned string. If there is insufficient memory available, or the
  * argument is NULL, the function returns NULL.
  */
-#define IS_WINDOWS_PATH(p)					\
-	((p != NULL) &&						\
-	 (((p[0] >= 'a') && (p[0] <= 'z')) ||			\
-	  ((p[0] >= 'A') && (p[0] <= 'Z'))) &&			\
-	 (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
 xmlChar *
 xmlCanonicPath(const xmlChar *path)
 {
-/*
- * For Windows implementations, additional work needs to be done to
- * replace backslashes in pathnames with "forward slashes"
- */
-#if defined(_WIN32)
-    int len = 0;
-    char *p = NULL;
-#endif
-    xmlURIPtr uri;
     xmlChar *ret;
-    const xmlChar *absuri;
-    int res;
 
     if (path == NULL)
 	return(NULL);
 
-#if defined(_WIN32)
-    /*
-     * We must not change the backslashes to slashes if the the path
-     * starts with \\?\
-     * Those paths can be up to 32k characters long.
-     * Was added specifically for OpenOffice, those paths can't be converted
-     * to URIs anyway.
-     */
-    if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
-        (path[3] == '\\') )
-	return xmlStrdup((const xmlChar *) path);
-#endif
-
-	/* sanitize filename starting with // so it can be used as URI */
-    if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/'))
-        path++;
-
-    res = xmlParseURISafe((const char *) path, &uri);
-    if (res < 0)
-        return(NULL);
-    if (uri != NULL) {
-        xmlFreeURI(uri);
-	return xmlStrdup(path);
-    }
-
     /* Check if this is an "absolute uri" */
-    absuri = xmlStrstr(path, BAD_CAST "://");
-    if (absuri != NULL) {
-        int l, j;
-	unsigned char c;
-	xmlChar *escURI;
-
-        /*
-	 * this looks like an URI where some parts have not been
-	 * escaped leading to a parsing problem.  Check that the first
-	 * part matches a protocol.
-	 */
-	l = absuri - path;
-	/* Bypass if first part (part before the '://') is > 20 chars */
-	if ((l <= 0) || (l > 20))
-	    goto path_processing;
-	/* Bypass if any non-alpha characters are present in first part */
-	for (j = 0;j < l;j++) {
-	    c = path[j];
-	    if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))))
-	        goto path_processing;
-	}
-
-	/* Escape all except the characters specified in the supplied path */
-        escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;=");
-	if (escURI == NULL)
-            return(NULL);
-        /* Try parsing the escaped path */
-        res = xmlParseURISafe((const char *) escURI, &uri);
-        if (res < 0) {
-            xmlFree(escURI);
-            return(NULL);
-        }
-        /* If successful, return the escaped string */
-        if (uri != NULL) {
-            xmlFreeURI(uri);
-            return escURI;
-        }
-        xmlFree(escURI);
-    }
-
-path_processing:
-/* For Windows implementations, replace backslashes with 'forward slashes' */
-#if defined(_WIN32)
-    /*
-     * Create a URI structure
-     */
-    uri = xmlCreateURI();
-    if (uri == NULL) {		/* Guard against 'out of memory' */
-        return(NULL);
-    }
-
-    len = xmlStrlen(path);
-    if ((len > 2) && IS_WINDOWS_PATH(path)) {
-        /* make the scheme 'file' */
-	uri->scheme = (char *) xmlStrdup(BAD_CAST "file");
-	if (uri->scheme == NULL) {
-	    xmlFreeURI(uri);
-	    return(NULL);
-	}
-	/* allocate space for leading '/' + path + string terminator */
-	uri->path = xmlMallocAtomic(len + 2);
-	if (uri->path == NULL) {
-	    xmlFreeURI(uri);	/* Guard against 'out of memory' */
-	    return(NULL);
-	}
-	/* Put in leading '/' plus path */
-	uri->path[0] = '/';
-	p = uri->path + 1;
-	strncpy(p, (char *) path, len + 1);
+    if (xmlStrstr(path, BAD_CAST "://") != NULL) {
+	/*
+         * Escape all characters except reserved, unreserved and the
+         * percent sign.
+         *
+         * xmlURIEscapeStr already keeps unreserved characters, so we
+         * pass gen-delims, sub-delims and "%" to ignore.
+         */
+        ret = xmlURIEscapeStr(path, BAD_CAST ":/?#[]@!$&()*+,;='%");
     } else {
-	uri->path = (char *) xmlStrdup(path);
-	if (uri->path == NULL) {
-	    xmlFreeURI(uri);
-	    return(NULL);
-	}
-	p = uri->path;
-    }
-    /* Now change all occurrences of '\' to '/' */
-    while (*p != '\0') {
-	if (*p == '\\')
-	    *p = '/';
-	p++;
+        ret = xmlStrdup((const xmlChar *) path);
     }
 
-    if (uri->scheme == NULL) {
-	ret = xmlStrdup((const xmlChar *) uri->path);
-    } else {
-	ret = xmlSaveUri(uri);
-    }
-
-    xmlFreeURI(uri);
-#else
-    ret = xmlStrdup((const xmlChar *) path);
-#endif
     return(ret);
 }
 
@@ -2703,46 +2690,5 @@
 xmlChar *
 xmlPathToURI(const xmlChar *path)
 {
-    xmlURIPtr uri;
-    xmlURI temp;
-    xmlChar *ret, *cal;
-    int res;
-
-    if (path == NULL)
-        return(NULL);
-
-    res = xmlParseURISafe((const char *) path, &uri);
-    if (res < 0)
-        return(NULL);
-    if (uri != NULL) {
-        xmlFreeURI(uri);
-	return xmlStrdup(path);
-    }
-
-    cal = xmlCanonicPath(path);
-    if (cal == NULL)
-        return(NULL);
-#if defined(_WIN32)
-    /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?)
-       If 'cal' is a valid URI already then we are done here, as continuing would make
-       it invalid. */
-    if ((uri = xmlParseURI((const char *) cal)) != NULL) {
-	xmlFreeURI(uri);
-	return cal;
-    }
-    /* 'cal' can contain a relative path with backslashes. If that is processed
-       by xmlSaveURI, they will be escaped and the external entity loader machinery
-       will fail. So convert them to slashes. Misuse 'ret' for walking. */
-    ret = cal;
-    while (*ret != '\0') {
-	if (*ret == '\\')
-	    *ret = '/';
-	ret++;
-    }
-#endif
-    memset(&temp, 0, sizeof(temp));
-    temp.path = (char *) cal;
-    ret = xmlSaveUri(&temp);
-    xmlFree(cal);
-    return(ret);
+    return(xmlCanonicPath(path));
 }
diff --git a/src/valid.c b/src/valid.c
index e791a2b..ada36a6 100644
--- a/src/valid.c
+++ b/src/valid.c
@@ -21,18 +21,16 @@
 #include <libxml/parserInternals.h>
 #include <libxml/xmlerror.h>
 #include <libxml/list.h>
+#include <libxml/xmlsave.h>
 
 #include "private/error.h"
 #include "private/parser.h"
+#include "private/regexp.h"
+#include "private/save.h"
+#include "private/tree.h"
 
 static xmlElementPtr
-xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
-                      int create);
-
-#define TODO								\
-    xmlGenericError(xmlGenericErrorContext,				\
-	    "Unimplemented block at %s:%d\n",				\
-            __FILE__, __LINE__);
+xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name);
 
 #ifdef LIBXML_VALID_ENABLED
 static int
@@ -53,31 +51,54 @@
  * Handle an out of memory error
  */
 static void
-xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
+xmlVErrMemory(xmlValidCtxtPtr ctxt)
 {
-    xmlGenericErrorFunc channel = NULL;
-    xmlParserCtxtPtr pctxt = NULL;
-    void *data = NULL;
-
     if (ctxt != NULL) {
-        channel = ctxt->error;
-        data = ctxt->userData;
-	/* Look up flag to detect if it is part of a parsing
-	   context */
-	if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
-	    pctxt = ctxt->userData;
-	}
+        if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
+            xmlCtxtErrMemory(ctxt->userData);
+        } else {
+            xmlRaiseMemoryError(NULL, ctxt->error, ctxt->userData,
+                                XML_FROM_VALID, NULL);
+        }
+    } else {
+        xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_VALID, NULL);
     }
-    if (extra)
-        __xmlRaiseError(NULL, channel, data,
-                        pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
-                        XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
-                        "Memory allocation failed : %s\n", extra);
-    else
-        __xmlRaiseError(NULL, channel, data,
-                        pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
-                        XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
-                        "Memory allocation failed\n");
+}
+
+static void
+xmlDoErrValid(xmlValidCtxtPtr ctxt, xmlNodePtr node,
+              xmlParserErrors code, int level,
+              const xmlChar *str1, const xmlChar *str2, const xmlChar *str3,
+              int int1,
+              const char *msg, ...) {
+    xmlParserCtxtPtr pctxt = NULL;
+    va_list ap;
+
+    if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT))
+        pctxt = ctxt->userData;
+
+    va_start(ap, msg);
+    if (pctxt != NULL) {
+        xmlCtxtVErr(pctxt, node, XML_FROM_VALID, code, level,
+                    str1, str2, str3, int1, msg, ap);
+    } else {
+        xmlGenericErrorFunc channel = NULL;
+        void *data = NULL;
+        int res;
+
+        if (ctxt != NULL) {
+            channel = ctxt->error;
+            data = ctxt->userData;
+        }
+        res = xmlVRaiseError(NULL, channel, data, NULL, node,
+                             XML_FROM_VALID, code, level, NULL, 0,
+                             (const char *) str1, (const char *) str2,
+                             (const char *) str2, int1, 0,
+                             msg, ap);
+        if (res < 0)
+            xmlVErrMemory(ctxt);
+    }
+    va_end(ap);
 }
 
 /**
@@ -92,29 +113,8 @@
 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
             const char *msg, const char *extra)
 {
-    xmlGenericErrorFunc channel = NULL;
-    xmlParserCtxtPtr pctxt = NULL;
-    void *data = NULL;
-
-    if (ctxt != NULL) {
-        channel = ctxt->error;
-        data = ctxt->userData;
-	/* Look up flag to detect if it is part of a parsing
-	   context */
-	if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
-	    pctxt = ctxt->userData;
-	}
-    }
-    if (extra)
-        __xmlRaiseError(NULL, channel, data,
-                        pctxt, NULL, XML_FROM_VALID, error,
-                        XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
-                        msg, extra);
-    else
-        __xmlRaiseError(NULL, channel, data,
-                        pctxt, NULL, XML_FROM_VALID, error,
-                        XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
-                        "%s", msg);
+    xmlDoErrValid(ctxt, NULL, error, XML_ERR_ERROR, (const xmlChar *) extra,
+                  NULL, NULL, 0, msg, extra);
 }
 
 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
@@ -135,25 +135,8 @@
                 const char *msg, const xmlChar * str1,
                 const xmlChar * str2, const xmlChar * str3)
 {
-    xmlStructuredErrorFunc schannel = NULL;
-    xmlGenericErrorFunc channel = NULL;
-    xmlParserCtxtPtr pctxt = NULL;
-    void *data = NULL;
-
-    if (ctxt != NULL) {
-        channel = ctxt->error;
-        data = ctxt->userData;
-	/* Look up flag to detect if it is part of a parsing
-	   context */
-	if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
-	    pctxt = ctxt->userData;
-	}
-    }
-    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
-                    XML_ERR_ERROR, NULL, 0,
-                    (const char *) str1,
-                    (const char *) str2,
-                    (const char *) str3, 0, 0, msg, str1, str2, str3);
+    xmlDoErrValid(ctxt, node, error, XML_ERR_ERROR, str1, str2, str3, 0,
+                  msg, str1, str2, str3);
 }
 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
 
@@ -175,25 +158,8 @@
                 const char *msg, const xmlChar * str1,
                 int int2, const xmlChar * str3)
 {
-    xmlStructuredErrorFunc schannel = NULL;
-    xmlGenericErrorFunc channel = NULL;
-    xmlParserCtxtPtr pctxt = NULL;
-    void *data = NULL;
-
-    if (ctxt != NULL) {
-        channel = ctxt->error;
-        data = ctxt->userData;
-	/* Look up flag to detect if it is part of a parsing
-	   context */
-	if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
-	    pctxt = ctxt->userData;
-	}
-    }
-    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
-                    XML_ERR_ERROR, NULL, 0,
-                    (const char *) str1,
-                    (const char *) str3,
-                    NULL, int2, 0, msg, str1, int2, str3);
+    xmlDoErrValid(ctxt, node, error, XML_ERR_ERROR, str1, str3, NULL, int2,
+                  msg, str1, int2, str3);
 }
 
 /**
@@ -213,25 +179,8 @@
                 const char *msg, const xmlChar * str1,
                 const xmlChar * str2, const xmlChar * str3)
 {
-    xmlStructuredErrorFunc schannel = NULL;
-    xmlGenericErrorFunc channel = NULL;
-    xmlParserCtxtPtr pctxt = NULL;
-    void *data = NULL;
-
-    if (ctxt != NULL) {
-        channel = ctxt->warning;
-        data = ctxt->userData;
-	/* Look up flag to detect if it is part of a parsing
-	   context */
-	if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
-	    pctxt = ctxt->userData;
-	}
-    }
-    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
-                    XML_ERR_WARNING, NULL, 0,
-                    (const char *) str1,
-                    (const char *) str2,
-                    (const char *) str3, 0, 0, msg, str1, str2, str3);
+    xmlDoErrValid(ctxt, node, error, XML_ERR_WARNING, str1, str2, str3, 0,
+                  msg, str1, str2, str3);
 }
 
 
@@ -260,7 +209,7 @@
 	ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
 		              sizeof(ctxt->vstateTab[0]));
         if (ctxt->vstateTab == NULL) {
-	    xmlVErrMemory(ctxt, "malloc failed");
+	    xmlVErrMemory(ctxt);
 	    return(-1);
 	}
     }
@@ -271,7 +220,7 @@
 	tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
 	             2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
         if (tmp == NULL) {
-	    xmlVErrMemory(ctxt, "realloc failed");
+	    xmlVErrMemory(ctxt);
 	    return(-1);
 	}
 	ctxt->vstateMax *= 2;
@@ -286,6 +235,10 @@
 	if (elemDecl->contModel != NULL) {
 	    ctxt->vstateTab[ctxt->vstateNr].exec =
 		xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
+            if (ctxt->vstateTab[ctxt->vstateNr].exec == NULL) {
+                xmlVErrMemory(ctxt);
+                return(-1);
+            }
 	} else {
 	    ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
 	    xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
@@ -367,7 +320,7 @@
 	ctxt->vstateTab = (xmlValidState *) xmlMalloc(
 		     ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
 	if (ctxt->vstateTab == NULL) {
-	    xmlVErrMemory(ctxt, "malloc failed");
+	    xmlVErrMemory(ctxt);
 	    return(-1);
 	}
     }
@@ -377,7 +330,7 @@
         tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
 	             2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
         if (tmp == NULL) {
-	    xmlVErrMemory(ctxt, "malloc failed");
+	    xmlVErrMemory(ctxt);
 	    return(-1);
 	}
 	ctxt->vstateMax *= 2;
@@ -425,7 +378,7 @@
             (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
                                      sizeof(ctxt->nodeTab[0]));
         if (ctxt->nodeTab == NULL) {
-	    xmlVErrMemory(ctxt, "malloc failed");
+	    xmlVErrMemory(ctxt);
             ctxt->nodeMax = 0;
             return (0);
         }
@@ -435,7 +388,7 @@
         tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
 			      ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
         if (tmp == NULL) {
-	    xmlVErrMemory(ctxt, "realloc failed");
+	    xmlVErrMemory(ctxt);
             return (0);
         }
         ctxt->nodeMax *= 2;
@@ -512,7 +465,7 @@
 
 	    fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
 	    if (fullname == NULL) {
-	        xmlVErrMemory(ctxt, "Building content model");
+	        xmlVErrMemory(ctxt);
 		return(0);
 	    }
 
@@ -644,6 +597,7 @@
  */
 int
 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
+    int ret = 0;
 
     if ((ctxt == NULL) || (elem == NULL))
 	return(0);
@@ -662,16 +616,17 @@
 
     ctxt->am = xmlNewAutomata();
     if (ctxt->am == NULL) {
-	xmlErrValidNode(ctxt, (xmlNodePtr) elem,
-	                XML_ERR_INTERNAL_ERROR,
-	                "Cannot create automata for element %s\n",
-		        elem->name, NULL, NULL);
+        xmlVErrMemory(ctxt);
 	return(0);
     }
     ctxt->state = xmlAutomataGetInitState(ctxt->am);
     xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
     xmlAutomataSetFinalState(ctxt->am, ctxt->state);
     elem->contModel = xmlAutomataCompile(ctxt->am);
+    if (elem->contModel == NULL) {
+        xmlVErrMemory(ctxt);
+        goto done;
+    }
     if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
 	char expr[5000];
 	expr[0] = 0;
@@ -681,15 +636,16 @@
 	       "Content model of %s is not deterministic: %s\n",
 	       elem->name, BAD_CAST expr, NULL);
         ctxt->valid = 0;
-	ctxt->state = NULL;
-	xmlFreeAutomata(ctxt->am);
-	ctxt->am = NULL;
-	return(0);
+	goto done;
     }
+
+    ret = 1;
+
+done:
     ctxt->state = NULL;
     xmlFreeAutomata(ctxt->am);
     ctxt->am = NULL;
-    return(1);
+    return(ret);
 }
 
 #endif /* LIBXML_REGEXP_ENABLED */
@@ -710,10 +666,8 @@
 xmlValidCtxtPtr xmlNewValidCtxt(void) {
     xmlValidCtxtPtr ret;
 
-    if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
-	xmlVErrMemory(NULL, "malloc failed");
+    if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL)
 	return (NULL);
-    }
 
     (void) memset(ret, 0, sizeof (xmlValidCtxt));
 
@@ -782,10 +736,8 @@
 	    return(NULL);
     }
     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
-    if (ret == NULL) {
-	xmlVErrMemory(NULL, "malloc failed");
+    if (ret == NULL)
 	return(NULL);
-    }
     memset(ret, 0, sizeof(xmlElementContent));
     ret->type = type;
     ret->ocur = XML_ELEMENT_CONTENT_ONCE;
@@ -807,9 +759,17 @@
 	        ret->prefix = xmlDictLookup(dict, name, l);
 		ret->name = xmlDictLookup(dict, tmp, -1);
 	    }
+            if (ret->prefix == NULL)
+                goto error;
 	}
+        if (ret->name == NULL)
+            goto error;
     }
     return(ret);
+
+error:
+    xmlFreeDocElementContent(doc, ret);
+    return(NULL);
 }
 
 /**
@@ -847,10 +807,8 @@
         dict = doc->dict;
 
     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
-    if (ret == NULL) {
-	xmlVErrMemory(NULL, "malloc failed");
+    if (ret == NULL)
 	return(NULL);
-    }
     memset(ret, 0, sizeof(xmlElementContent));
     ret->type = cur->type;
     ret->ocur = cur->ocur;
@@ -859,6 +817,8 @@
 	    ret->name = xmlDictLookup(dict, cur->name, -1);
 	else
 	    ret->name = xmlStrdup(cur->name);
+        if (ret->name == NULL)
+            goto error;
     }
 
     if (cur->prefix != NULL) {
@@ -866,20 +826,22 @@
 	    ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
 	else
 	    ret->prefix = xmlStrdup(cur->prefix);
+        if (ret->prefix == NULL)
+            goto error;
     }
-    if (cur->c1 != NULL)
+    if (cur->c1 != NULL) {
         ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
-    if (ret->c1 != NULL)
+        if (ret->c1 == NULL)
+            goto error;
 	ret->c1->parent = ret;
+    }
     if (cur->c2 != NULL) {
         prev = ret;
 	cur = cur->c2;
 	while (cur != NULL) {
 	    tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
-	    if (tmp == NULL) {
-		xmlVErrMemory(NULL, "malloc failed");
-		return(ret);
-	    }
+	    if (tmp == NULL)
+                goto error;
 	    memset(tmp, 0, sizeof(xmlElementContent));
 	    tmp->type = cur->type;
 	    tmp->ocur = cur->ocur;
@@ -890,6 +852,8 @@
 		    tmp->name = xmlDictLookup(dict, cur->name, -1);
 		else
 		    tmp->name = xmlStrdup(cur->name);
+                if (tmp->name == NULL)
+                    goto error;
 	    }
 
 	    if (cur->prefix != NULL) {
@@ -897,16 +861,24 @@
 		    tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
 		else
 		    tmp->prefix = xmlStrdup(cur->prefix);
+                if (tmp->prefix == NULL)
+                    goto error;
 	    }
-	    if (cur->c1 != NULL)
+	    if (cur->c1 != NULL) {
 	        tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
-	    if (tmp->c1 != NULL)
+	        if (tmp->c1 == NULL)
+                    goto error;
 		tmp->c1->parent = tmp;
+            }
 	    prev = tmp;
 	    cur = cur->c2;
 	}
     }
     return(ret);
+
+error:
+    xmlFreeElementContent(ret);
+    return(NULL);
 }
 
 /**
@@ -1003,105 +975,6 @@
 
 #ifdef LIBXML_OUTPUT_ENABLED
 /**
- * xmlDumpElementOccur:
- * @buf:  An XML buffer
- * @cur:  An element table
- *
- * Dump the occurrence operator of an element.
- */
-static void
-xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
-    switch (cur->ocur) {
-        case XML_ELEMENT_CONTENT_ONCE:
-            break;
-        case XML_ELEMENT_CONTENT_OPT:
-            xmlBufferWriteChar(buf, "?");
-            break;
-        case XML_ELEMENT_CONTENT_MULT:
-            xmlBufferWriteChar(buf, "*");
-            break;
-        case XML_ELEMENT_CONTENT_PLUS:
-            xmlBufferWriteChar(buf, "+");
-            break;
-    }
-}
-
-/**
- * xmlDumpElementContent:
- * @buf:  An XML buffer
- * @content:  An element table
- *
- * This will dump the content of the element table as an XML DTD definition
- */
-static void
-xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
-    xmlElementContentPtr cur;
-
-    if (content == NULL) return;
-
-    xmlBufferWriteChar(buf, "(");
-    cur = content;
-
-    do {
-        if (cur == NULL) return;
-
-        switch (cur->type) {
-            case XML_ELEMENT_CONTENT_PCDATA:
-                xmlBufferWriteChar(buf, "#PCDATA");
-                break;
-            case XML_ELEMENT_CONTENT_ELEMENT:
-                if (cur->prefix != NULL) {
-                    xmlBufferWriteCHAR(buf, cur->prefix);
-                    xmlBufferWriteChar(buf, ":");
-                }
-                xmlBufferWriteCHAR(buf, cur->name);
-                break;
-            case XML_ELEMENT_CONTENT_SEQ:
-            case XML_ELEMENT_CONTENT_OR:
-                if ((cur != content) &&
-                    (cur->parent != NULL) &&
-                    ((cur->type != cur->parent->type) ||
-                     (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
-                    xmlBufferWriteChar(buf, "(");
-                cur = cur->c1;
-                continue;
-            default:
-                xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
-                        "Internal: ELEMENT cur corrupted invalid type\n",
-                        NULL);
-        }
-
-        while (cur != content) {
-            xmlElementContentPtr parent = cur->parent;
-
-            if (parent == NULL) return;
-
-            if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
-                 (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
-                ((cur->type != parent->type) ||
-                 (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
-                xmlBufferWriteChar(buf, ")");
-            xmlDumpElementOccur(buf, cur);
-
-            if (cur == parent->c1) {
-                if (parent->type == XML_ELEMENT_CONTENT_SEQ)
-                    xmlBufferWriteChar(buf, " , ");
-                else if (parent->type == XML_ELEMENT_CONTENT_OR)
-                    xmlBufferWriteChar(buf, " | ");
-
-                cur = parent->c2;
-                break;
-            }
-
-            cur = parent;
-        }
-    } while (cur != content);
-
-    xmlBufferWriteChar(buf, ")");
-    xmlDumpElementOccur(buf, content);
-}
-
-/**
  * xmlSprintfElementContent:
  * @buf:  an output buffer
  * @content:  An element table
@@ -1267,7 +1140,8 @@
     xmlElementPtr ret;
     xmlElementTablePtr table;
     xmlAttributePtr oldAttributes = NULL;
-    xmlChar *ns, *uqname;
+    const xmlChar *localName;
+    xmlChar *prefix = NULL;
 
     if (dtd == NULL) {
 	return(NULL);
@@ -1279,7 +1153,7 @@
     switch (type) {
         case XML_ELEMENT_TYPE_EMPTY:
 	    if (content != NULL) {
-		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
+		xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR,
 		        "xmlAddElementDecl: content != NULL for EMPTY\n",
 			NULL);
 		return(NULL);
@@ -1287,7 +1161,7 @@
 	    break;
 	case XML_ELEMENT_TYPE_ANY:
 	    if (content != NULL) {
-		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
+		xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR,
 		        "xmlAddElementDecl: content != NULL for ANY\n",
 			NULL);
 		return(NULL);
@@ -1295,7 +1169,7 @@
 	    break;
 	case XML_ELEMENT_TYPE_MIXED:
 	    if (content == NULL) {
-		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
+		xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR,
 		        "xmlAddElementDecl: content == NULL for MIXED\n",
 			NULL);
 		return(NULL);
@@ -1303,7 +1177,7 @@
 	    break;
 	case XML_ELEMENT_TYPE_ELEMENT:
 	    if (content == NULL) {
-		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
+		xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR,
 		        "xmlAddElementDecl: content == NULL for ELEMENT\n",
 			NULL);
 		return(NULL);
@@ -1319,9 +1193,9 @@
     /*
      * check if name is a QName
      */
-    uqname = xmlSplitQName2(name, &ns);
-    if (uqname != NULL)
-	name = uqname;
+    localName = xmlSplitQName4(name, &prefix);
+    if (localName == NULL)
+        goto mem_error;
 
     /*
      * Create the Element table if needed.
@@ -1333,28 +1207,22 @@
 	if (dtd->doc != NULL)
 	    dict = dtd->doc->dict;
         table = xmlHashCreateDict(0, dict);
+        if (table == NULL)
+            goto mem_error;
 	dtd->elements = (void *) table;
     }
-    if (table == NULL) {
-	xmlVErrMemory(ctxt,
-            "xmlAddElementDecl: Table creation failed!\n");
-	if (uqname != NULL)
-	    xmlFree(uqname);
-	if (ns != NULL)
-	    xmlFree(ns);
-        return(NULL);
-    }
 
     /*
      * lookup old attributes inserted on an undefined element in the
      * internal subset.
      */
     if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
-	ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
+	ret = xmlHashLookup2(dtd->doc->intSubset->elements, localName, prefix);
 	if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
 	    oldAttributes = ret->attributes;
 	    ret->attributes = NULL;
-	    xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
+	    xmlHashRemoveEntry2(dtd->doc->intSubset->elements, localName, prefix,
+                                NULL);
 	    xmlFreeElement(ret);
 	}
     }
@@ -1363,7 +1231,7 @@
      * The element may already be present if one of its attribute
      * was registered first
      */
-    ret = xmlHashLookup2(table, name, ns);
+    ret = xmlHashLookup2(table, localName, prefix);
     if (ret != NULL) {
 	if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
 #ifdef LIBXML_VALID_ENABLED
@@ -1374,61 +1242,42 @@
 	                    "Redefinition of element %s\n",
 			    name, NULL, NULL);
 #endif /* LIBXML_VALID_ENABLED */
-	    if (uqname != NULL)
-		xmlFree(uqname);
-            if (ns != NULL)
-	        xmlFree(ns);
+            if (prefix != NULL)
+	        xmlFree(prefix);
 	    return(NULL);
 	}
-	if (ns != NULL) {
-	    xmlFree(ns);
-	    ns = NULL;
+	if (prefix != NULL) {
+	    xmlFree(prefix);
+	    prefix = NULL;
 	}
     } else {
+        int res;
+
 	ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
-	if (ret == NULL) {
-	    xmlVErrMemory(ctxt, "malloc failed");
-	    if (uqname != NULL)
-		xmlFree(uqname);
-            if (ns != NULL)
-	        xmlFree(ns);
-	    return(NULL);
-	}
+	if (ret == NULL)
+            goto mem_error;
 	memset(ret, 0, sizeof(xmlElement));
 	ret->type = XML_ELEMENT_DECL;
 
 	/*
 	 * fill the structure.
 	 */
-	ret->name = xmlStrdup(name);
+	ret->name = xmlStrdup(localName);
 	if (ret->name == NULL) {
-	    xmlVErrMemory(ctxt, "malloc failed");
-	    if (uqname != NULL)
-		xmlFree(uqname);
-            if (ns != NULL)
-	        xmlFree(ns);
 	    xmlFree(ret);
-	    return(NULL);
+	    goto mem_error;
 	}
-	ret->prefix = ns;
+	ret->prefix = prefix;
+        prefix = NULL;
 
 	/*
 	 * Validity Check:
 	 * Insertion must not fail
 	 */
-	if (xmlHashAddEntry2(table, name, ns, ret)) {
-#ifdef LIBXML_VALID_ENABLED
-	    /*
-	     * The element is already defined in this DTD.
-	     */
-	    xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
-	                    "Redefinition of element %s\n",
-			    name, NULL, NULL);
-#endif /* LIBXML_VALID_ENABLED */
+        res = xmlHashAdd2(table, localName, ret->prefix, ret);
+        if (res <= 0) {
 	    xmlFreeElement(ret);
-	    if (uqname != NULL)
-		xmlFree(uqname);
-	    return(NULL);
+            goto mem_error;
 	}
 	/*
 	 * For new element, may have attributes from earlier
@@ -1446,12 +1295,15 @@
      * and flag it by setting a special parent value
      * so the parser doesn't unallocate it.
      */
-    if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) {
-	ret->content = content;
-	if (content != NULL)
-	    content->parent = (xmlElementContentPtr) 1;
-    } else {
-	ret->content = xmlCopyDocElementContent(dtd->doc, content);
+    if (content != NULL) {
+        if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) {
+            ret->content = content;
+            content->parent = (xmlElementContentPtr) 1;
+        } else if (content != NULL){
+            ret->content = xmlCopyDocElementContent(dtd->doc, content);
+            if (ret->content == NULL)
+                goto mem_error;
+        }
     }
 
     /*
@@ -1466,9 +1318,15 @@
 	ret->prev = dtd->last;
 	dtd->last = (xmlNodePtr) ret;
     }
-    if (uqname != NULL)
-	xmlFree(uqname);
+    if (prefix != NULL)
+	xmlFree(prefix);
     return(ret);
+
+mem_error:
+    xmlVErrMemory(ctxt);
+    if (prefix != NULL)
+        xmlFree(prefix);
+    return(NULL);
 }
 
 static void
@@ -1502,25 +1360,33 @@
     xmlElementPtr cur;
 
     cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
-    if (cur == NULL) {
-	xmlVErrMemory(NULL, "malloc failed");
+    if (cur == NULL)
 	return(NULL);
-    }
     memset(cur, 0, sizeof(xmlElement));
     cur->type = XML_ELEMENT_DECL;
     cur->etype = elem->etype;
-    if (elem->name != NULL)
+    if (elem->name != NULL) {
 	cur->name = xmlStrdup(elem->name);
-    else
-	cur->name = NULL;
-    if (elem->prefix != NULL)
+        if (cur->name == NULL)
+            goto error;
+    }
+    if (elem->prefix != NULL) {
 	cur->prefix = xmlStrdup(elem->prefix);
-    else
-	cur->prefix = NULL;
-    cur->content = xmlCopyElementContent(elem->content);
+        if (cur->prefix == NULL)
+            goto error;
+    }
+    if (elem->content != NULL) {
+        cur->content = xmlCopyElementContent(elem->content);
+        if (cur->content == NULL)
+            goto error;
+    }
     /* TODO : rebuild the attribute list on the copy */
     cur->attributes = NULL;
     return(cur);
+
+error:
+    xmlFreeElement(cur);
+    return(NULL);
 }
 
 /**
@@ -1533,7 +1399,7 @@
  */
 xmlElementTablePtr
 xmlCopyElementTable(xmlElementTablePtr table) {
-    return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
+    return(xmlHashCopySafe(table, xmlCopyElement, xmlFreeElementTableEntry));
 }
 #endif /* LIBXML_TREE_ENABLED */
 
@@ -1543,59 +1409,21 @@
  * @buf:  the XML buffer output
  * @elem:  An element table
  *
+ * DEPRECATED: Use xmlSaveTree.
+ *
  * This will dump the content of the element declaration as an XML
  * DTD definition
  */
 void
 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
+    xmlSaveCtxtPtr save;
+
     if ((buf == NULL) || (elem == NULL))
         return;
-    switch (elem->etype) {
-	case XML_ELEMENT_TYPE_EMPTY:
-	    xmlBufferWriteChar(buf, "<!ELEMENT ");
-	    if (elem->prefix != NULL) {
-		xmlBufferWriteCHAR(buf, elem->prefix);
-		xmlBufferWriteChar(buf, ":");
-	    }
-	    xmlBufferWriteCHAR(buf, elem->name);
-	    xmlBufferWriteChar(buf, " EMPTY>\n");
-	    break;
-	case XML_ELEMENT_TYPE_ANY:
-	    xmlBufferWriteChar(buf, "<!ELEMENT ");
-	    if (elem->prefix != NULL) {
-		xmlBufferWriteCHAR(buf, elem->prefix);
-		xmlBufferWriteChar(buf, ":");
-	    }
-	    xmlBufferWriteCHAR(buf, elem->name);
-	    xmlBufferWriteChar(buf, " ANY>\n");
-	    break;
-	case XML_ELEMENT_TYPE_MIXED:
-	    xmlBufferWriteChar(buf, "<!ELEMENT ");
-	    if (elem->prefix != NULL) {
-		xmlBufferWriteCHAR(buf, elem->prefix);
-		xmlBufferWriteChar(buf, ":");
-	    }
-	    xmlBufferWriteCHAR(buf, elem->name);
-	    xmlBufferWriteChar(buf, " ");
-	    xmlDumpElementContent(buf, elem->content);
-	    xmlBufferWriteChar(buf, ">\n");
-	    break;
-	case XML_ELEMENT_TYPE_ELEMENT:
-	    xmlBufferWriteChar(buf, "<!ELEMENT ");
-	    if (elem->prefix != NULL) {
-		xmlBufferWriteCHAR(buf, elem->prefix);
-		xmlBufferWriteChar(buf, ":");
-	    }
-	    xmlBufferWriteCHAR(buf, elem->name);
-	    xmlBufferWriteChar(buf, " ");
-	    xmlDumpElementContent(buf, elem->content);
-	    xmlBufferWriteChar(buf, ">\n");
-	    break;
-	default:
-	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
-		    "Internal: ELEMENT struct corrupted invalid type\n",
-		    NULL);
-    }
+
+    save = xmlSaveToBuffer(buf, NULL, 0);
+    xmlSaveTree(save, (xmlNodePtr) elem);
+    xmlSaveClose(save);
 }
 
 /**
@@ -1617,6 +1445,8 @@
  * @buf:  the XML buffer output
  * @table:  An element table
  *
+ * DEPRECATED: Don't use.
+ *
  * This will dump the content of the element table as an XML DTD definition
  */
 void
@@ -1641,14 +1471,18 @@
     xmlEnumerationPtr ret;
 
     ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
-    if (ret == NULL) {
-	xmlVErrMemory(NULL, "malloc failed");
+    if (ret == NULL)
         return(NULL);
-    }
     memset(ret, 0, sizeof(xmlEnumeration));
 
-    if (name != NULL)
+    if (name != NULL) {
         ret->name = xmlStrdup(name);
+        if (ret->name == NULL) {
+            xmlFree(ret);
+            return(NULL);
+        }
+    }
+
     return(ret);
 }
 
@@ -1660,12 +1494,14 @@
  */
 void
 xmlFreeEnumeration(xmlEnumerationPtr cur) {
-    if (cur == NULL) return;
+    while (cur != NULL) {
+        xmlEnumerationPtr next = cur->next;
 
-    if (cur->next != NULL) xmlFreeEnumeration(cur->next);
+        xmlFree((xmlChar *) cur->name);
+        xmlFree(cur);
 
-    if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
-    xmlFree(cur);
+        cur = next;
+    }
 }
 
 #ifdef LIBXML_TREE_ENABLED
@@ -1680,42 +1516,31 @@
  */
 xmlEnumerationPtr
 xmlCopyEnumeration(xmlEnumerationPtr cur) {
-    xmlEnumerationPtr ret;
+    xmlEnumerationPtr ret = NULL;
+    xmlEnumerationPtr last = NULL;
 
-    if (cur == NULL) return(NULL);
-    ret = xmlCreateEnumeration((xmlChar *) cur->name);
-    if (ret == NULL) return(NULL);
+    while (cur != NULL) {
+        xmlEnumerationPtr copy = xmlCreateEnumeration(cur->name);
 
-    if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
-    else ret->next = NULL;
+        if (copy == NULL) {
+            xmlFreeEnumeration(ret);
+            return(NULL);
+        }
+
+        if (ret == NULL) {
+            ret = last = copy;
+        } else {
+            last->next = copy;
+            last = copy;
+        }
+
+        cur = cur->next;
+    }
 
     return(ret);
 }
 #endif /* LIBXML_TREE_ENABLED */
 
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlDumpEnumeration:
- * @buf:  the XML buffer output
- * @enum:  An enumeration
- *
- * This will dump the content of the enumeration
- */
-static void
-xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
-    if ((buf == NULL) || (cur == NULL))
-        return;
-
-    xmlBufferWriteCHAR(buf, cur->name);
-    if (cur->next == NULL)
-	xmlBufferWriteChar(buf, ")");
-    else {
-	xmlBufferWriteChar(buf, " | ");
-	xmlDumpEnumeration(buf, cur->next);
-    }
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
 #ifdef LIBXML_VALID_ENABLED
 /**
  * xmlScanIDAttributeDecl:
@@ -1814,10 +1639,11 @@
                     const xmlChar *name, const xmlChar *ns,
 		    xmlAttributeType type, xmlAttributeDefault def,
 		    const xmlChar *defaultValue, xmlEnumerationPtr tree) {
-    xmlAttributePtr ret;
+    xmlAttributePtr ret = NULL;
     xmlAttributeTablePtr table;
     xmlElementPtr elemDef;
     xmlDictPtr dict = NULL;
+    int res;
 
     if (dtd == NULL) {
 	xmlFreeEnumeration(tree);
@@ -1899,20 +1725,12 @@
         table = xmlHashCreateDict(0, dict);
 	dtd->attributes = (void *) table;
     }
-    if (table == NULL) {
-	xmlVErrMemory(ctxt,
-            "xmlAddAttributeDecl: Table creation failed!\n");
-	xmlFreeEnumeration(tree);
-        return(NULL);
-    }
-
+    if (table == NULL)
+        goto mem_error;
 
     ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
-    if (ret == NULL) {
-	xmlVErrMemory(ctxt, "malloc failed");
-	xmlFreeEnumeration(tree);
-	return(NULL);
-    }
+    if (ret == NULL)
+        goto mem_error;
     memset(ret, 0, sizeof(xmlAttribute));
     ret->type = XML_ATTRIBUTE_DECL;
 
@@ -1928,34 +1746,49 @@
     ret->doc = dtd->doc;
     if (dict) {
 	ret->name = xmlDictLookup(dict, name, -1);
-	ret->prefix = xmlDictLookup(dict, ns, -1);
 	ret->elem = xmlDictLookup(dict, elem, -1);
     } else {
 	ret->name = xmlStrdup(name);
-	ret->prefix = xmlStrdup(ns);
 	ret->elem = xmlStrdup(elem);
     }
+    if ((ret->name == NULL) || (ret->elem == NULL))
+        goto mem_error;
+    if (ns != NULL) {
+        if (dict)
+            ret->prefix = xmlDictLookup(dict, ns, -1);
+        else
+            ret->prefix = xmlStrdup(ns);
+        if (ret->prefix == NULL)
+            goto mem_error;
+    }
     ret->def = def;
     ret->tree = tree;
+    tree = NULL;
     if (defaultValue != NULL) {
         if (dict)
 	    ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
 	else
 	    ret->defaultValue = xmlStrdup(defaultValue);
+        if (ret->defaultValue == NULL)
+            xmlVErrMemory(ctxt);
     }
 
     /*
      * Validity Check:
      * Search the DTD for previous declarations of the ATTLIST
      */
-    if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
+    res = xmlHashAdd3(table, ret->name, ret->prefix, ret->elem, ret);
+    if (res <= 0) {
+        if (res < 0)
+            goto mem_error;
 #ifdef LIBXML_VALID_ENABLED
-	/*
-	 * The attribute is already defined in this DTD.
-	 */
-	xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
-		 "Attribute %s of element %s: already defined\n",
-		 name, elem, NULL);
+        /*
+         * The attribute is already defined in this DTD.
+         */
+        xmlErrValidWarning(ctxt, (xmlNodePtr) dtd,
+                XML_DTD_ATTRIBUTE_REDEFINED,
+                "Attribute %s of element %s: already defined\n",
+                name, elem, NULL);
 #endif /* LIBXML_VALID_ENABLED */
 	xmlFreeAttribute(ret);
 	return(NULL);
@@ -1965,12 +1798,12 @@
      * Validity Check:
      * Multiple ID per element
      */
-    elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem, 1);
+    elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem);
     if (elemDef != NULL) {
 
 #ifdef LIBXML_VALID_ENABLED
         if ((type == XML_ATTRIBUTE_ID) &&
-	    (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
+	    (xmlScanIDAttributeDecl(ctxt, elemDef, 1) != 0)) {
 	    xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
 	   "Element %s has too may ID attributes defined : %s\n",
 		   elem, name, NULL);
@@ -2021,6 +1854,12 @@
 	dtd->last = (xmlNodePtr) ret;
     }
     return(ret);
+
+mem_error:
+    xmlVErrMemory(ctxt);
+    xmlFreeEnumeration(tree);
+    xmlFreeAttribute(ret);
+    return(NULL);
 }
 
 static void
@@ -2054,24 +1893,42 @@
     xmlAttributePtr cur;
 
     cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
-    if (cur == NULL) {
-	xmlVErrMemory(NULL, "malloc failed");
+    if (cur == NULL)
 	return(NULL);
-    }
     memset(cur, 0, sizeof(xmlAttribute));
     cur->type = XML_ATTRIBUTE_DECL;
     cur->atype = attr->atype;
     cur->def = attr->def;
-    cur->tree = xmlCopyEnumeration(attr->tree);
-    if (attr->elem != NULL)
+    if (attr->tree != NULL) {
+        cur->tree = xmlCopyEnumeration(attr->tree);
+        if (cur->tree == NULL)
+            goto error;
+    }
+    if (attr->elem != NULL) {
 	cur->elem = xmlStrdup(attr->elem);
-    if (attr->name != NULL)
+        if (cur->elem == NULL)
+            goto error;
+    }
+    if (attr->name != NULL) {
 	cur->name = xmlStrdup(attr->name);
-    if (attr->prefix != NULL)
+        if (cur->name == NULL)
+            goto error;
+    }
+    if (attr->prefix != NULL) {
 	cur->prefix = xmlStrdup(attr->prefix);
-    if (attr->defaultValue != NULL)
+        if (cur->prefix == NULL)
+            goto error;
+    }
+    if (attr->defaultValue != NULL) {
 	cur->defaultValue = xmlStrdup(attr->defaultValue);
+        if (cur->defaultValue == NULL)
+            goto error;
+    }
     return(cur);
+
+error:
+    xmlFreeAttribute(cur);
+    return(NULL);
 }
 
 /**
@@ -2084,7 +1941,8 @@
  */
 xmlAttributeTablePtr
 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
-    return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
+    return(xmlHashCopySafe(table, xmlCopyAttribute,
+                           xmlFreeAttributeTableEntry));
 }
 #endif /* LIBXML_TREE_ENABLED */
 
@@ -2094,81 +1952,21 @@
  * @buf:  the XML buffer output
  * @attr:  An attribute declaration
  *
+ * DEPRECATED: Use xmlSaveTree.
+ *
  * This will dump the content of the attribute declaration as an XML
  * DTD definition
  */
 void
 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
+    xmlSaveCtxtPtr save;
+
     if ((buf == NULL) || (attr == NULL))
         return;
-    xmlBufferWriteChar(buf, "<!ATTLIST ");
-    xmlBufferWriteCHAR(buf, attr->elem);
-    xmlBufferWriteChar(buf, " ");
-    if (attr->prefix != NULL) {
-	xmlBufferWriteCHAR(buf, attr->prefix);
-	xmlBufferWriteChar(buf, ":");
-    }
-    xmlBufferWriteCHAR(buf, attr->name);
-    switch (attr->atype) {
-	case XML_ATTRIBUTE_CDATA:
-	    xmlBufferWriteChar(buf, " CDATA");
-	    break;
-	case XML_ATTRIBUTE_ID:
-	    xmlBufferWriteChar(buf, " ID");
-	    break;
-	case XML_ATTRIBUTE_IDREF:
-	    xmlBufferWriteChar(buf, " IDREF");
-	    break;
-	case XML_ATTRIBUTE_IDREFS:
-	    xmlBufferWriteChar(buf, " IDREFS");
-	    break;
-	case XML_ATTRIBUTE_ENTITY:
-	    xmlBufferWriteChar(buf, " ENTITY");
-	    break;
-	case XML_ATTRIBUTE_ENTITIES:
-	    xmlBufferWriteChar(buf, " ENTITIES");
-	    break;
-	case XML_ATTRIBUTE_NMTOKEN:
-	    xmlBufferWriteChar(buf, " NMTOKEN");
-	    break;
-	case XML_ATTRIBUTE_NMTOKENS:
-	    xmlBufferWriteChar(buf, " NMTOKENS");
-	    break;
-	case XML_ATTRIBUTE_ENUMERATION:
-	    xmlBufferWriteChar(buf, " (");
-	    xmlDumpEnumeration(buf, attr->tree);
-	    break;
-	case XML_ATTRIBUTE_NOTATION:
-	    xmlBufferWriteChar(buf, " NOTATION (");
-	    xmlDumpEnumeration(buf, attr->tree);
-	    break;
-	default:
-	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
-		    "Internal: ATTRIBUTE struct corrupted invalid type\n",
-		    NULL);
-    }
-    switch (attr->def) {
-	case XML_ATTRIBUTE_NONE:
-	    break;
-	case XML_ATTRIBUTE_REQUIRED:
-	    xmlBufferWriteChar(buf, " #REQUIRED");
-	    break;
-	case XML_ATTRIBUTE_IMPLIED:
-	    xmlBufferWriteChar(buf, " #IMPLIED");
-	    break;
-	case XML_ATTRIBUTE_FIXED:
-	    xmlBufferWriteChar(buf, " #FIXED");
-	    break;
-	default:
-	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
-		    "Internal: ATTRIBUTE struct corrupted invalid def\n",
-		    NULL);
-    }
-    if (attr->defaultValue != NULL) {
-	xmlBufferWriteChar(buf, " ");
-	xmlBufferWriteQuotedString(buf, attr->defaultValue);
-    }
-    xmlBufferWriteChar(buf, ">\n");
+
+    save = xmlSaveToBuffer(buf, NULL, 0);
+    xmlSaveTree(save, (xmlNodePtr) attr);
+    xmlSaveClose(save);
 }
 
 /**
@@ -2189,6 +1987,8 @@
  * @buf:  the XML buffer output
  * @table:  An attribute table
  *
+ * DEPRECATED: Don't use.
+ *
  * This will dump the content of the attribute table as an XML DTD definition
  */
 void
@@ -2239,8 +2039,9 @@
 xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
 	           const xmlChar *name,
                    const xmlChar *PublicID, const xmlChar *SystemID) {
-    xmlNotationPtr ret;
+    xmlNotationPtr ret = NULL;
     xmlNotationTablePtr table;
+    int res;
 
     if (dtd == NULL) {
 	return(NULL);
@@ -2262,43 +2063,54 @@
 	    dict = dtd->doc->dict;
 
         dtd->notations = table = xmlHashCreateDict(0, dict);
-    }
-    if (table == NULL) {
-	xmlVErrMemory(ctxt,
-		"xmlAddNotationDecl: Table creation failed!\n");
-        return(NULL);
+        if (table == NULL)
+            goto mem_error;
     }
 
     ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
-    if (ret == NULL) {
-	xmlVErrMemory(ctxt, "malloc failed");
-	return(NULL);
-    }
+    if (ret == NULL)
+        goto mem_error;
     memset(ret, 0, sizeof(xmlNotation));
 
     /*
      * fill the structure.
      */
     ret->name = xmlStrdup(name);
-    if (SystemID != NULL)
+    if (ret->name == NULL)
+        goto mem_error;
+    if (SystemID != NULL) {
         ret->SystemID = xmlStrdup(SystemID);
-    if (PublicID != NULL)
+        if (ret->SystemID == NULL)
+            goto mem_error;
+    }
+    if (PublicID != NULL) {
         ret->PublicID = xmlStrdup(PublicID);
+        if (ret->PublicID == NULL)
+            goto mem_error;
+    }
 
     /*
      * Validity Check:
      * Check the DTD for previous declarations of the ATTLIST
      */
-    if (xmlHashAddEntry(table, name, ret)) {
+    res = xmlHashAdd(table, name, ret);
+    if (res <= 0) {
+        if (res < 0)
+            goto mem_error;
 #ifdef LIBXML_VALID_ENABLED
-	xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
-		    "xmlAddNotationDecl: %s already defined\n",
-		    (const char *) name);
+        xmlErrValid(ctxt, XML_DTD_NOTATION_REDEFINED,
+                    "xmlAddNotationDecl: %s already defined\n",
+                    (const char *) name);
 #endif /* LIBXML_VALID_ENABLED */
 	xmlFreeNotation(ret);
 	return(NULL);
     }
     return(ret);
+
+mem_error:
+    xmlVErrMemory(ctxt);
+    xmlFreeNotation(ret);
+    return(NULL);
 }
 
 static void
@@ -2332,23 +2144,29 @@
     xmlNotationPtr cur;
 
     cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
-    if (cur == NULL) {
-	xmlVErrMemory(NULL, "malloc failed");
+    if (cur == NULL)
 	return(NULL);
-    }
-    if (nota->name != NULL)
+    memset(cur, 0, sizeof(*cur));
+    if (nota->name != NULL) {
 	cur->name = xmlStrdup(nota->name);
-    else
-	cur->name = NULL;
-    if (nota->PublicID != NULL)
+        if (cur->name == NULL)
+            goto error;
+    }
+    if (nota->PublicID != NULL) {
 	cur->PublicID = xmlStrdup(nota->PublicID);
-    else
-	cur->PublicID = NULL;
-    if (nota->SystemID != NULL)
+        if (cur->PublicID == NULL)
+            goto error;
+    }
+    if (nota->SystemID != NULL) {
 	cur->SystemID = xmlStrdup(nota->SystemID);
-    else
-	cur->SystemID = NULL;
+        if (cur->SystemID == NULL)
+            goto error;
+    }
     return(cur);
+
+error:
+    xmlFreeNotation(cur);
+    return(NULL);
 }
 
 /**
@@ -2361,7 +2179,7 @@
  */
 xmlNotationTablePtr
 xmlCopyNotationTable(xmlNotationTablePtr table) {
-    return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
+    return(xmlHashCopySafe(table, xmlCopyNotation, xmlFreeNotationTableEntry));
 }
 #endif /* LIBXML_TREE_ENABLED */
 
@@ -2371,39 +2189,20 @@
  * @buf:  the XML buffer output
  * @nota:  A notation declaration
  *
+ * DEPRECATED: Don't use.
+ *
  * This will dump the content the notation declaration as an XML DTD definition
  */
 void
 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
+    xmlSaveCtxtPtr save;
+
     if ((buf == NULL) || (nota == NULL))
         return;
-    xmlBufferWriteChar(buf, "<!NOTATION ");
-    xmlBufferWriteCHAR(buf, nota->name);
-    if (nota->PublicID != NULL) {
-	xmlBufferWriteChar(buf, " PUBLIC ");
-	xmlBufferWriteQuotedString(buf, nota->PublicID);
-	if (nota->SystemID != NULL) {
-	    xmlBufferWriteChar(buf, " ");
-	    xmlBufferWriteQuotedString(buf, nota->SystemID);
-	}
-    } else {
-	xmlBufferWriteChar(buf, " SYSTEM ");
-	xmlBufferWriteQuotedString(buf, nota->SystemID);
-    }
-    xmlBufferWriteChar(buf, " >\n");
-}
 
-/**
- * xmlDumpNotationDeclScan:
- * @nota:  A notation declaration
- * @buf:  the XML buffer output
- *
- * This is called with the hash scan function, and just reverses args
- */
-static void
-xmlDumpNotationDeclScan(void *nota, void *buf,
-                        const xmlChar *name ATTRIBUTE_UNUSED) {
-    xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
+    save = xmlSaveToBuffer(buf, NULL, 0);
+    xmlSaveNotationDecl(save, nota);
+    xmlSaveClose(save);
 }
 
 /**
@@ -2411,13 +2210,20 @@
  * @buf:  the XML buffer output
  * @table:  A notation table
  *
+ * DEPRECATED: Don't use.
+ *
  * This will dump the content of the notation table as an XML DTD definition
  */
 void
 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
+    xmlSaveCtxtPtr save;
+
     if ((buf == NULL) || (table == NULL))
         return;
-    xmlHashScan(table, xmlDumpNotationDeclScan, buf);
+
+    save = xmlSaveToBuffer(buf, NULL, 0);
+    xmlSaveNotationTable(save, table);
+    xmlSaveClose(save);
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
 
@@ -2438,35 +2244,6 @@
 	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
 	    xmlFree((char *)(str));
 
-/**
- * xmlValidNormalizeString:
- * @str: a string
- *
- * Normalize a string in-place.
- */
-static void
-xmlValidNormalizeString(xmlChar *str) {
-    xmlChar *dst;
-    const xmlChar *src;
-
-    if (str == NULL)
-        return;
-    src = str;
-    dst = str;
-
-    while (*src == 0x20) src++;
-    while (*src != 0) {
-	if (*src == 0x20) {
-	    while (*src == 0x20) src++;
-	    if (*src != 0)
-		*dst++ = 0x20;
-	} else {
-	    *dst++ = *src++;
-	}
-    }
-    *dst = 0;
-}
-
 static int
 xmlIsStreaming(xmlValidCtxtPtr ctxt) {
     xmlParserCtxtPtr pctxt;
@@ -2519,7 +2296,6 @@
              int streaming, xmlIDPtr *id) {
     xmlIDPtr ret;
     xmlIDTablePtr table;
-    int res;
 
     if (id != NULL)
         *id = NULL;
@@ -2540,9 +2316,26 @@
     table = (xmlIDTablePtr) doc->ids;
     if (table == NULL)  {
         doc->ids = table = xmlHashCreateDict(0, doc->dict);
+        if (table == NULL)
+            return(-1);
+    } else {
+        ret = xmlHashLookup(table, value);
+        if (ret != NULL) {
+            /*
+             * Update the attribute unless we are parsing in streaming
+             * mode. If the attribute is copied from an entity we want
+             * the ID reference the copy.
+             */
+            if (ret->attr != NULL) {
+                ret->attr->id = NULL;
+                ret->attr = attr;
+                attr->id = ret;
+            }
+            ret->lineno = xmlGetLineNo(attr->parent);
+	    attr->atype = XML_ATTRIBUTE_ID;
+            return(0);
+        }
     }
-    if (table == NULL)
-        return(-1);
 
     ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
     if (ret == NULL)
@@ -2577,15 +2370,14 @@
     }
     ret->lineno = xmlGetLineNo(attr->parent);
 
-    res = xmlHashAdd(table, value, ret);
-    if (res <= 0) {
+    if (xmlHashAddEntry(table, value, ret) < 0) {
 	xmlFreeID(ret);
-	return(res);
+	return(-1);
     }
-    if (attr != NULL) {
-	attr->atype = XML_ATTRIBUTE_ID;
+
+    attr->atype = XML_ATTRIBUTE_ID;
+    if (!streaming)
         attr->id = ret;
-    }
 
     if (id != NULL)
         *id = ret;
@@ -2611,7 +2403,7 @@
 
     res = xmlAddIDSafe(doc, value, attr, xmlIsStreaming(ctxt), &id);
     if (res < 0) {
-        xmlVErrMemory(ctxt, "malloc failed");
+        xmlVErrMemory(ctxt);
     }
 #ifdef LIBXML_VALID_ENABLED
     else if (res == 0) {
@@ -2655,7 +2447,8 @@
  * of HTML documents parsed with the HTML parser, then ID detection is
  * done systematically.
  *
- * Returns 0 or 1 depending on the lookup result
+ * Returns 0 or 1 depending on the lookup result or -1 if a memory allocation
+ * failed.
  */
 int
 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
@@ -2679,27 +2472,26 @@
     } else {
 	xmlAttributePtr attrDecl = NULL;
 
-	xmlChar felem[50], fattr[50];
-	xmlChar *fullelemname, *fullattrname;
+	xmlChar felem[50];
+	xmlChar *fullelemname;
+        const xmlChar *aprefix;
 
 	fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
 	    xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
 	    (xmlChar *)elem->name;
+        if (fullelemname == NULL)
+            return(-1);
 
-	fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
-	    xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
-	    (xmlChar *)attr->name;
+        aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
 
-	if (fullelemname != NULL && fullattrname != NULL) {
-	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
-		                         fullattrname);
+	if (fullelemname != NULL) {
+	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullelemname,
+		                          attr->name, aprefix);
 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
-					     fullattrname);
+		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullelemname,
+					      attr->name, aprefix);
 	}
 
-	if ((fullattrname != fattr) && (fullattrname != attr->name))
-	    xmlFree(fullattrname);
 	if ((fullelemname != felem) && (fullelemname != elem->name))
 	    xmlFree(fullelemname);
 
@@ -2879,7 +2671,7 @@
 xmlRefPtr
 xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
     xmlAttrPtr attr) {
-    xmlRefPtr ret;
+    xmlRefPtr ret = NULL;
     xmlRefTablePtr table;
     xmlListPtr ref_list;
 
@@ -2899,28 +2691,28 @@
     table = (xmlRefTablePtr) doc->refs;
     if (table == NULL) {
         doc->refs = table = xmlHashCreateDict(0, doc->dict);
-    }
-    if (table == NULL) {
-	xmlVErrMemory(ctxt,
-            "xmlAddRef: Table creation failed!\n");
-        return(NULL);
+        if (table == NULL)
+            goto failed;
     }
 
     ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
-    if (ret == NULL) {
-	xmlVErrMemory(ctxt, "malloc failed");
-        return(NULL);
-    }
+    if (ret == NULL)
+        goto failed;
+    memset(ret, 0, sizeof(*ret));
 
     /*
      * fill the structure.
      */
     ret->value = xmlStrdup(value);
+    if (ret->value == NULL)
+        goto failed;
     if (xmlIsStreaming(ctxt)) {
 	/*
 	 * Operating in streaming mode, attr is gonna disappear
 	 */
 	ret->name = xmlStrdup(attr->name);
+        if (ret->name == NULL)
+            goto failed;
 	ret->attr = NULL;
     } else {
 	ret->name = NULL;
@@ -2936,28 +2728,22 @@
      */
 
     if (NULL == (ref_list = xmlHashLookup(table, value))) {
-        if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
-	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
-		    "xmlAddRef: Reference list creation failed!\n",
-		    NULL);
+        int res;
+
+        if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare)))
 	    goto failed;
-        }
-        if (xmlHashAddEntry(table, value, ref_list) < 0) {
+        res = xmlHashAdd(table, value, ref_list);
+        if (res <= 0) {
             xmlListDelete(ref_list);
-	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
-		    "xmlAddRef: Reference list insertion failed!\n",
-		    NULL);
 	    goto failed;
         }
     }
-    if (xmlListAppend(ref_list, ret) != 0) {
-	xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
-		    "xmlAddRef: Reference list insertion failed!\n",
-		    NULL);
+    if (xmlListAppend(ref_list, ret) != 0)
         goto failed;
-    }
     return(ret);
+
 failed:
+    xmlVErrMemory(ctxt);
     if (ret != NULL) {
         if (ret->value != NULL)
 	    xmlFree((char *)ret->value);
@@ -3011,12 +2797,15 @@
         return(0);
     } else {
         xmlAttributePtr attrDecl;
+        const xmlChar *aprefix;
 
         if (elem == NULL) return(0);
-        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
+        aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
+        attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, attr->name,
+                                      aprefix);
         if ((attrDecl == NULL) && (doc->extSubset != NULL))
-            attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
-		                         elem->name, attr->name);
+            attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, attr->name,
+                                          aprefix);
 
 	if ((attrDecl != NULL) &&
 	    (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
@@ -3127,6 +2916,8 @@
  *
  * Search the DTD for the description of this element
  *
+ * NOTE: A NULL return value can also mean that a memory allocation failed.
+ *
  * returns the xmlElementPtr if found or NULL
  */
 
@@ -3149,6 +2940,7 @@
     if (uqname != NULL) xmlFree(uqname);
     return(cur);
 }
+
 /**
  * xmlGetDtdElementDesc2:
  * @dtd:  a pointer to the DtD to search
@@ -3161,66 +2953,63 @@
  */
 
 static xmlElementPtr
-xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
-                      int create) {
+xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name) {
     xmlElementTablePtr table;
-    xmlElementPtr cur;
-    xmlChar *uqname = NULL, *prefix = NULL;
+    xmlElementPtr cur = NULL;
+    const xmlChar *localName;
+    xmlChar *prefix = NULL;
 
     if (dtd == NULL) return(NULL);
+
+    /*
+     * Create the Element table if needed.
+     */
     if (dtd->elements == NULL) {
 	xmlDictPtr dict = NULL;
 
 	if (dtd->doc != NULL)
 	    dict = dtd->doc->dict;
 
-	if (!create)
-	    return(NULL);
-	/*
-	 * Create the Element table if needed.
-	 */
-	table = (xmlElementTablePtr) dtd->elements;
-	if (table == NULL) {
-	    table = xmlHashCreateDict(0, dict);
-	    dtd->elements = (void *) table;
-	}
-	if (table == NULL) {
-	    xmlVErrMemory(ctxt, "element table allocation failed");
-	    return(NULL);
-	}
+	dtd->elements = xmlHashCreateDict(0, dict);
+	if (dtd->elements == NULL)
+            goto mem_error;
     }
     table = (xmlElementTablePtr) dtd->elements;
 
-    uqname = xmlSplitQName2(name, &prefix);
-    if (uqname != NULL)
-        name = uqname;
-    cur = xmlHashLookup2(table, name, prefix);
-    if ((cur == NULL) && (create)) {
+    localName = xmlSplitQName4(name, &prefix);
+    if (localName == NULL)
+        goto mem_error;
+    cur = xmlHashLookup2(table, localName, prefix);
+    if (cur == NULL) {
 	cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
-	if (cur == NULL) {
-	    xmlVErrMemory(ctxt, "malloc failed");
-	    goto error;
-	}
+	if (cur == NULL)
+            goto mem_error;
 	memset(cur, 0, sizeof(xmlElement));
 	cur->type = XML_ELEMENT_DECL;
 
 	/*
 	 * fill the structure.
 	 */
-	cur->name = xmlStrdup(name);
-	cur->prefix = xmlStrdup(prefix);
+	cur->name = xmlStrdup(localName);
+        if (cur->name == NULL)
+            goto mem_error;
+	cur->prefix = prefix;
+        prefix = NULL;
 	cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
 
-	if (xmlHashAddEntry2(table, name, prefix, cur) < 0) {
-	    xmlVErrMemory(ctxt, "adding entry failed");
-            xmlFreeElement(cur);
-            cur = NULL;
-        }
+	if (xmlHashAdd2(table, localName, cur->prefix, cur) <= 0)
+            goto mem_error;
     }
-error:
-    if (prefix != NULL) xmlFree(prefix);
-    if (uqname != NULL) xmlFree(uqname);
+
+    if (prefix != NULL)
+        xmlFree(prefix);
     return(cur);
+
+mem_error:
+    xmlVErrMemory(ctxt);
+    xmlFree(prefix);
+    xmlFreeElement(cur);
+    return(NULL);
 }
 
 /**
@@ -3402,6 +3191,70 @@
 
 #ifdef LIBXML_VALID_ENABLED
 
+/**
+ * xmlValidNormalizeString:
+ * @str: a string
+ *
+ * Normalize a string in-place.
+ */
+static void
+xmlValidNormalizeString(xmlChar *str) {
+    xmlChar *dst;
+    const xmlChar *src;
+
+    if (str == NULL)
+        return;
+    src = str;
+    dst = str;
+
+    while (*src == 0x20) src++;
+    while (*src != 0) {
+	if (*src == 0x20) {
+	    while (*src == 0x20) src++;
+	    if (*src != 0)
+		*dst++ = 0x20;
+	} else {
+	    *dst++ = *src++;
+	}
+    }
+    *dst = 0;
+}
+
+/**
+ * xmlCtxtGetDtdElementDesc:
+ * @ctxt:  validation context
+ * @dtd:  a pointer to the DtD to search
+ * @name:  the element name
+ *
+ * Search the DTD for the description of this element
+ *
+ * returns the xmlElementPtr if found or NULL
+ */
+
+static xmlElementPtr
+xmlCtxtGetDtdElementDesc(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
+                         const xmlChar *name) {
+    xmlElementTablePtr table;
+    xmlElementPtr cur;
+    const xmlChar *localName;
+    xmlChar *prefix;
+
+    if ((dtd == NULL) || (name == NULL)) return(NULL);
+    if (dtd->elements == NULL)
+	return(NULL);
+    table = (xmlElementTablePtr) dtd->elements;
+
+    localName = xmlSplitQName4(name, &prefix);
+    if (localName == NULL) {
+        xmlVErrMemory(ctxt);
+        return(NULL);
+    }
+    cur = xmlHashLookup2(table, localName, prefix);
+    if (prefix != NULL)
+        xmlFree(prefix);
+    return(cur);
+}
+
 static int
 xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
     if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
@@ -3872,8 +3725,10 @@
 	    xmlEntityPtr ent;
 
 	    dup = xmlStrdup(value);
-	    if (dup == NULL)
+	    if (dup == NULL) {
+                xmlVErrMemory(ctxt);
 		return(0);
+            }
 	    cur = dup;
 	    while (*cur != 0) {
 		nam = cur;
@@ -3951,6 +3806,8 @@
 	     xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
     xmlChar *ret;
     xmlAttributePtr attrDecl = NULL;
+    const xmlChar *localName;
+    xmlChar *prefix = NULL;
     int extsubset = 0;
 
     if (doc == NULL) return(NULL);
@@ -3958,38 +3815,47 @@
     if (name == NULL) return(NULL);
     if (value == NULL) return(NULL);
 
-    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
-	xmlChar fn[50];
-	xmlChar *fullname;
+    localName = xmlSplitQName4(name, &prefix);
+    if (localName == NULL)
+        goto mem_error;
 
-	fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
-	if (fullname == NULL)
-	    return(NULL);
-	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
+    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
+	xmlChar buf[50];
+	xmlChar *elemname;
+
+	elemname = xmlBuildQName(elem->name, elem->ns->prefix, buf, 50);
+	if (elemname == NULL)
+	    goto mem_error;
+        if (doc->intSubset != NULL)
+            attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName,
+                                      prefix, elemname);
 	if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
-	    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
+	    attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName,
+                                      prefix, elemname);
 	    if (attrDecl != NULL)
 		extsubset = 1;
 	}
-	if ((fullname != fn) && (fullname != elem->name))
-	    xmlFree(fullname);
+	if ((elemname != buf) && (elemname != elem->name))
+	    xmlFree(elemname);
     }
     if ((attrDecl == NULL) && (doc->intSubset != NULL))
-	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
+	attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName,
+                                  prefix, elem->name);
     if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
-	attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
+	attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName,
+                                  prefix, elem->name);
 	if (attrDecl != NULL)
 	    extsubset = 1;
     }
 
     if (attrDecl == NULL)
-	return(NULL);
+	goto done;
     if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
-	return(NULL);
+	goto done;
 
     ret = xmlStrdup(value);
     if (ret == NULL)
-	return(NULL);
+	goto mem_error;
     xmlValidNormalizeString(ret);
     if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
 	xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
@@ -3997,7 +3863,16 @@
 	       name, elem->name, NULL);
 	ctxt->valid = 0;
     }
+
+    xmlFree(prefix);
     return(ret);
+
+mem_error:
+    xmlVErrMemory(ctxt);
+
+done:
+    xmlFree(prefix);
+    return(NULL);
 }
 
 /**
@@ -4118,10 +3993,10 @@
         int nbId;
 
 	/* the trick is that we parse DtD as their own internal subset */
-        xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
-	                                          attr->elem);
+        xmlElementPtr elem = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset,
+	                                              attr->elem);
 	if (elem != NULL) {
-	    nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
+	    nbId = xmlScanIDAttributeDecl(ctxt, elem, 0);
 	} else {
 	    xmlAttributeTablePtr table;
 
@@ -4143,9 +4018,9 @@
 		   attr->elem, nbId, attr->name);
 	} else if (doc->extSubset != NULL) {
 	    int extId = 0;
-	    elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
+	    elem = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, attr->elem);
 	    if (elem != NULL) {
-		extId = xmlScanIDAttributeDecl(NULL, elem, 0);
+		extId = xmlScanIDAttributeDecl(ctxt, elem, 0);
 	    }
 	    if (extId > 1) {
 		xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
@@ -4262,7 +4137,7 @@
     }
 
     /* VC: Unique Element Type Declaration */
-    tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
+    tst = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset, elem->name);
     if ((tst != NULL ) && (tst != elem) &&
 	((tst->prefix == elem->prefix) ||
 	 (xmlStrEqual(tst->prefix, elem->prefix))) &&
@@ -4272,7 +4147,7 @@
 		       elem->name, NULL, NULL);
 	ret = 0;
     }
-    tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+    tst = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, elem->name);
     if ((tst != NULL ) && (tst != elem) &&
 	((tst->prefix == elem->prefix) ||
 	 (xmlStrEqual(tst->prefix, elem->prefix))) &&
@@ -4320,6 +4195,7 @@
                         xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
 {
     xmlAttributePtr attrDecl =  NULL;
+    const xmlChar *aprefix;
     int val;
     int ret = 1;
 
@@ -4327,42 +4203,31 @@
     if ((elem == NULL) || (elem->name == NULL)) return(0);
     if ((attr == NULL) || (attr->name == NULL)) return(0);
 
+    aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
+
     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
 	xmlChar fn[50];
 	xmlChar *fullname;
 
 	fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
-	if (fullname == NULL)
+	if (fullname == NULL) {
+            xmlVErrMemory(ctxt);
 	    return(0);
-	if (attr->ns != NULL) {
-	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
-		                          attr->name, attr->ns->prefix);
-	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
-					      attr->name, attr->ns->prefix);
-	} else {
-	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
-	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
-					     fullname, attr->name);
-	}
+        }
+        attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
+                                      attr->name, aprefix);
+        if ((attrDecl == NULL) && (doc->extSubset != NULL))
+            attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
+                                          attr->name, aprefix);
 	if ((fullname != fn) && (fullname != elem->name))
 	    xmlFree(fullname);
     }
     if (attrDecl == NULL) {
-	if (attr->ns != NULL) {
-	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
-		                          attr->name, attr->ns->prefix);
-	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
-					      attr->name, attr->ns->prefix);
-	} else {
-	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
-		                         elem->name, attr->name);
-	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
-					     elem->name, attr->name);
-	}
+        attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
+                                      attr->name, aprefix);
+        if ((attrDecl == NULL) && (doc->extSubset != NULL))
+            attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
+                                          attr->name, aprefix);
     }
 
 
@@ -4510,7 +4375,7 @@
 
 	fullname = xmlBuildQName(elem->name, prefix, fn, 50);
 	if (fullname == NULL) {
-	    xmlVErrMemory(ctxt, "Validating namespace");
+	    xmlVErrMemory(ctxt);
 	    return(0);
 	}
 	if (ns->prefix != NULL) {
@@ -4520,11 +4385,11 @@
 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
 					  ns->prefix, BAD_CAST "xmlns");
 	} else {
-	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
-		                         BAD_CAST "xmlns");
+	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
+                                          BAD_CAST "xmlns", NULL);
 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
-			                 BAD_CAST "xmlns");
+		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
+                                              BAD_CAST "xmlns", NULL);
 	}
 	if ((fullname != fn) && (fullname != elem->name))
 	    xmlFree(fullname);
@@ -4537,11 +4402,11 @@
 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
 					      ns->prefix, BAD_CAST "xmlns");
 	} else {
-	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
-		                         elem->name, BAD_CAST "xmlns");
+	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
+                                          BAD_CAST "xmlns", NULL);
 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
-		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
-					     elem->name, BAD_CAST "xmlns");
+		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
+                                              BAD_CAST "xmlns", NULL);
 	}
     }
 
@@ -5190,67 +5055,72 @@
 	ctxt->nodeNr = 0;
 	ctxt->nodeTab = NULL;
 	exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
-	if (exec != NULL) {
-	    cur = child;
-	    while (cur != NULL) {
-		switch (cur->type) {
-		    case XML_ENTITY_REF_NODE:
-			/*
-			 * Push the current node to be able to roll back
-			 * and process within the entity
-			 */
-			if ((cur->children != NULL) &&
-			    (cur->children->children != NULL)) {
-			    nodeVPush(ctxt, cur);
-			    cur = cur->children->children;
-			    continue;
-			}
-			break;
-		    case XML_TEXT_NODE:
-			if (xmlIsBlankNode(cur))
-			    break;
-			ret = 0;
-			goto fail;
-		    case XML_CDATA_SECTION_NODE:
-			/* TODO */
-			ret = 0;
-			goto fail;
-		    case XML_ELEMENT_NODE:
-			if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
-			    xmlChar fn[50];
-			    xmlChar *fullname;
+	if (exec == NULL) {
+            xmlVErrMemory(ctxt);
+            return(-1);
+        }
+        cur = child;
+        while (cur != NULL) {
+            switch (cur->type) {
+                case XML_ENTITY_REF_NODE:
+                    /*
+                     * Push the current node to be able to roll back
+                     * and process within the entity
+                     */
+                    if ((cur->children != NULL) &&
+                        (cur->children->children != NULL)) {
+                        nodeVPush(ctxt, cur);
+                        cur = cur->children->children;
+                        continue;
+                    }
+                    break;
+                case XML_TEXT_NODE:
+                    if (xmlIsBlankNode(cur))
+                        break;
+                    ret = 0;
+                    goto fail;
+                case XML_CDATA_SECTION_NODE:
+                    /* TODO */
+                    ret = 0;
+                    goto fail;
+                case XML_ELEMENT_NODE:
+                    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+                        xmlChar fn[50];
+                        xmlChar *fullname;
 
-			    fullname = xmlBuildQName(cur->name,
-				                     cur->ns->prefix, fn, 50);
-			    if (fullname == NULL) {
-				ret = -1;
-				goto fail;
-			    }
-                            ret = xmlRegExecPushString(exec, fullname, NULL);
-			    if ((fullname != fn) && (fullname != cur->name))
-				xmlFree(fullname);
-			} else {
-			    ret = xmlRegExecPushString(exec, cur->name, NULL);
-			}
-			break;
-		    default:
-			break;
-		}
-		/*
-		 * Switch to next element
-		 */
-		cur = cur->next;
-		while (cur == NULL) {
-		    cur = nodeVPop(ctxt);
-		    if (cur == NULL)
-			break;
-		    cur = cur->next;
-		}
-	    }
-	    ret = xmlRegExecPushString(exec, NULL, NULL);
+                        fullname = xmlBuildQName(cur->name,
+                                                 cur->ns->prefix, fn, 50);
+                        if (fullname == NULL) {
+                            xmlVErrMemory(ctxt);
+                            ret = -1;
+                            goto fail;
+                        }
+                        ret = xmlRegExecPushString(exec, fullname, NULL);
+                        if ((fullname != fn) && (fullname != cur->name))
+                            xmlFree(fullname);
+                    } else {
+                        ret = xmlRegExecPushString(exec, cur->name, NULL);
+                    }
+                    break;
+                default:
+                    break;
+            }
+            if (ret == XML_REGEXP_OUT_OF_MEMORY)
+                xmlVErrMemory(ctxt);
+            /*
+             * Switch to next element
+             */
+            cur = cur->next;
+            while (cur == NULL) {
+                cur = nodeVPop(ctxt);
+                if (cur == NULL)
+                    break;
+                cur = cur->next;
+            }
+        }
+        ret = xmlRegExecPushString(exec, NULL, NULL);
 fail:
-	    xmlRegFreeExecCtxt(exec);
-	}
+        xmlRegFreeExecCtxt(exec);
     }
 #else  /* LIBXML_REGEXP_ENABLED */
     /*
@@ -5260,7 +5130,7 @@
     ctxt->vstateTab = (xmlValidState *) xmlMalloc(
 		 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
     if (ctxt->vstateTab == NULL) {
-	xmlVErrMemory(ctxt, "malloc failed");
+	xmlVErrMemory(ctxt);
 	return(-1);
     }
     /*
@@ -5319,7 +5189,7 @@
 		     */
 		    tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
 		    if (tmp == NULL) {
-			xmlVErrMemory(ctxt, "malloc failed");
+			xmlVErrMemory(ctxt);
 			xmlFreeNodeList(repl);
 			ret = -1;
 			goto done;
@@ -5619,9 +5489,9 @@
      * full QName but in that case being flexible makes sense.
      */
     if (elemDecl == NULL) {
-	elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
+	elemDecl = xmlGetDtdQElementDesc(doc->intSubset, elem->name, NULL);
 	if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
-	    elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+	    elemDecl = xmlGetDtdQElementDesc(doc->extSubset, elem->name, NULL);
 	    if ((elemDecl != NULL) && (extsubset != NULL))
 		*extsubset = 1;
 	}
@@ -5711,6 +5581,10 @@
 		     */
 		    if (state->exec != NULL) {
 			ret = xmlRegExecPushString(state->exec, qname, NULL);
+                        if (ret == XML_REGEXP_OUT_OF_MEMORY) {
+                            xmlVErrMemory(ctxt);
+                            return(0);
+                        }
 			if (ret < 0) {
 			    xmlErrValidNode(ctxt, state->node,
 					    XML_DTD_CONTENT_MODEL,
@@ -6269,7 +6143,7 @@
 
 		fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
 		if (fullname == NULL) {
-		    xmlVErrMemory(ctxt, NULL);
+		    xmlVErrMemory(ctxt);
 		    return(0);
 		}
 		ret = xmlStrEqual(doc->intSubset->name, fullname);
@@ -6323,6 +6197,8 @@
             attr = elem->properties;
             while (attr != NULL) {
                 value = xmlNodeListGetString(doc, attr->children, 0);
+                if (value == NULL)
+                    xmlVErrMemory(ctxt);
                 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
                 if (value != NULL)
                     xmlFree((char *)value);
@@ -6384,7 +6260,7 @@
 
 	dup = xmlStrdup(name);
 	if (dup == NULL) {
-	    ctxt->valid = 0;
+            xmlVErrMemory(ctxt);
 	    return;
 	}
 	cur = dup;
@@ -6419,7 +6295,7 @@
 
 	dup = xmlStrdup(name);
 	if (dup == NULL) {
-	    xmlVErrMemory(ctxt, "IDREFS split");
+	    xmlVErrMemory(ctxt);
 	    ctxt->valid = 0;
 	    return;
 	}
@@ -6500,7 +6376,8 @@
 int
 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
     xmlRefTablePtr table;
-    unsigned int save;
+    xmlParserCtxtPtr pctxt = NULL;
+    xmlParserInputPtr oldInput = NULL;
 
     if (ctxt == NULL)
         return(0);
@@ -6510,10 +6387,6 @@
 	return(0);
     }
 
-    /* trick to get correct line id report */
-    save = ctxt->flags;
-    ctxt->flags &= ~XML_VCTXT_USE_PCTXT;
-
     /*
      * Check all the NOTATION/NOTATIONS attributes
      */
@@ -6523,12 +6396,24 @@
     /*
      * Check all the IDREF/IDREFS attributes definition for validity
      */
+
+    /*
+     * Don't print line numbers.
+     */
+    if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
+        pctxt = ctxt->userData;
+        oldInput = pctxt->input;
+        pctxt->input = NULL;
+    }
+
     table = (xmlRefTablePtr) doc->refs;
     ctxt->doc = doc;
     ctxt->valid = 1;
     xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
 
-    ctxt->flags = save;
+    if (ctxt->flags & XML_VCTXT_USE_PCTXT)
+        pctxt->input = oldInput;
+
     return(ctxt->valid);
 }
 
@@ -6654,12 +6539,13 @@
 	}
 
 	if (doc != NULL)
-	    elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
+	    elem = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset, cur->elem);
 	if ((elem == NULL) && (doc != NULL))
-	    elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
+	    elem = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, cur->elem);
 	if ((elem == NULL) && (cur->parent != NULL) &&
 	    (cur->parent->type == XML_DTD_NODE))
-	    elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
+	    elem = xmlCtxtGetDtdElementDesc(ctxt, (xmlDtdPtr) cur->parent,
+                                            cur->elem);
 	if (elem == NULL) {
 	    xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
 		   "attribute %s: could not find decl for element %s\n",
diff --git a/src/xmlIO.c b/src/xmlIO.c
index 520720b..96c8502 100644
--- a/src/xmlIO.c
+++ b/src/xmlIO.c
@@ -36,22 +36,8 @@
 #include <direct.h>
 #endif
 
-#ifndef S_ISDIR
-#  ifdef _S_ISDIR
-#    define S_ISDIR(x) _S_ISDIR(x)
-#  elif defined(S_IFDIR)
-#    ifdef S_IFMT
-#      define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
-#    elif defined(_S_IFMT)
-#      define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
-#    endif
-#  endif
-#endif
-
 #include <libxml/xmlIO.h>
 #include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include <libxml/parserInternals.h>
 #include <libxml/uri.h>
 #include <libxml/nanohttp.h>
 #include <libxml/nanoftp.h>
@@ -70,6 +56,22 @@
 
 #define MINLEN 4000
 
+#ifndef STDOUT_FILENO
+  #define STDOUT_FILENO 1
+#endif
+
+#ifndef S_ISDIR
+#  ifdef _S_ISDIR
+#    define S_ISDIR(x) _S_ISDIR(x)
+#  elif defined(S_IFDIR)
+#    ifdef S_IFMT
+#      define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#    elif defined(_S_IFMT)
+#      define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
+#    endif
+#  endif
+#endif
+
 /*
  * Input I/O callback sets
  */
@@ -80,11 +82,14 @@
     xmlInputCloseCallback closecallback;
 } xmlInputCallback;
 
-#define MAX_INPUT_CALLBACK 15
+/* This dummy function only marks default IO in the callback table */
+static int
+xmlIODefaultMatch(const char *filename);
+
+#define MAX_INPUT_CALLBACK 10
 
 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
-static int xmlInputCallbackNr = 0;
-static int xmlInputCallbackInitialized = 0;
+static int xmlInputCallbackNr;
 
 #ifdef LIBXML_OUTPUT_ENABLED
 /*
@@ -97,112 +102,18 @@
     xmlOutputCloseCallback closecallback;
 } xmlOutputCallback;
 
-#define MAX_OUTPUT_CALLBACK 15
+#define MAX_OUTPUT_CALLBACK 10
 
 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
-static int xmlOutputCallbackNr = 0;
-static int xmlOutputCallbackInitialized = 0;
+static int xmlOutputCallbackNr;
 #endif /* LIBXML_OUTPUT_ENABLED */
 
 /************************************************************************
  *									*
- *		Tree memory error handler				*
+ *			Error handling					*
  *									*
  ************************************************************************/
 
-static const char* const IOerr[] = {
-    "Unknown IO error",         /* UNKNOWN */
-    "Permission denied",	/* EACCES */
-    "Resource temporarily unavailable",/* EAGAIN */
-    "Bad file descriptor",	/* EBADF */
-    "Bad message",		/* EBADMSG */
-    "Resource busy",		/* EBUSY */
-    "Operation canceled",	/* ECANCELED */
-    "No child processes",	/* ECHILD */
-    "Resource deadlock avoided",/* EDEADLK */
-    "Domain error",		/* EDOM */
-    "File exists",		/* EEXIST */
-    "Bad address",		/* EFAULT */
-    "File too large",		/* EFBIG */
-    "Operation in progress",	/* EINPROGRESS */
-    "Interrupted function call",/* EINTR */
-    "Invalid argument",		/* EINVAL */
-    "Input/output error",	/* EIO */
-    "Is a directory",		/* EISDIR */
-    "Too many open files",	/* EMFILE */
-    "Too many links",		/* EMLINK */
-    "Inappropriate message buffer length",/* EMSGSIZE */
-    "Filename too long",	/* ENAMETOOLONG */
-    "Too many open files in system",/* ENFILE */
-    "No such device",		/* ENODEV */
-    "No such file or directory",/* ENOENT */
-    "Exec format error",	/* ENOEXEC */
-    "No locks available",	/* ENOLCK */
-    "Not enough space",		/* ENOMEM */
-    "No space left on device",	/* ENOSPC */
-    "Function not implemented",	/* ENOSYS */
-    "Not a directory",		/* ENOTDIR */
-    "Directory not empty",	/* ENOTEMPTY */
-    "Not supported",		/* ENOTSUP */
-    "Inappropriate I/O control operation",/* ENOTTY */
-    "No such device or address",/* ENXIO */
-    "Operation not permitted",	/* EPERM */
-    "Broken pipe",		/* EPIPE */
-    "Result too large",		/* ERANGE */
-    "Read-only file system",	/* EROFS */
-    "Invalid seek",		/* ESPIPE */
-    "No such process",		/* ESRCH */
-    "Operation timed out",	/* ETIMEDOUT */
-    "Improper link",		/* EXDEV */
-    "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
-    "encoder error",		/* XML_IO_ENCODER */
-    "flush error",
-    "write error",
-    "no input",
-    "buffer full",
-    "loading error",
-    "not a socket",		/* ENOTSOCK */
-    "already connected",	/* EISCONN */
-    "connection refused",	/* ECONNREFUSED */
-    "unreachable network",	/* ENETUNREACH */
-    "address in use",		/* EADDRINUSE */
-    "already in use",		/* EALREADY */
-    "unknown address family",	/* EAFNOSUPPORT */
-};
-
-#if defined(_WIN32)
-/**
- * __xmlIOWin32UTF8ToWChar:
- * @u8String:  uft-8 string
- *
- * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
- */
-static wchar_t *
-__xmlIOWin32UTF8ToWChar(const char *u8String)
-{
-    wchar_t *wString = NULL;
-
-    if (u8String) {
-        int wLen =
-            MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
-                                -1, NULL, 0);
-        if (wLen) {
-            wString = xmlMalloc(wLen * sizeof(wchar_t));
-            if (wString) {
-                if (MultiByteToWideChar
-                    (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
-                    xmlFree(wString);
-                    wString = NULL;
-                }
-            }
-        }
-    }
-
-    return wString;
-}
-#endif
-
-#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_OUTPUT_ENABLED)
 /**
  * xmlIOErrMemory:
  * @extra:  extra information
@@ -210,11 +121,10 @@
  * Handle an out of memory condition
  */
 static void
-xmlIOErrMemory(const char *extra)
+xmlIOErrMemory(void)
 {
-    __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
+    xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_IO, NULL);
 }
-#endif
 
 /**
  * __xmlIOErr:
@@ -224,13 +134,17 @@
  *
  * Handle an I/O error
  */
-void
+int
 __xmlIOErr(int domain, int code, const char *extra)
 {
-    unsigned int idx;
+    xmlStructuredErrorFunc schannel = NULL;
+    xmlGenericErrorFunc channel = NULL;
+    void *data = NULL;
+    const char *fmt, *arg;
+    int res;
 
     if (code == 0) {
-	if (errno == 0) code = 0;
+	if (errno == 0) code = XML_IO_UNKNOWN;
 #ifdef EACCES
         else if (errno == EACCES) code = XML_IO_EACCES;
 #endif
@@ -386,11 +300,33 @@
 #endif
         else code = XML_IO_UNKNOWN;
     }
-    idx = 0;
-    if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
-    if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
 
-    __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
+    if (xmlStructuredError) {
+        schannel = xmlStructuredError;
+        data = xmlStructuredErrorContext;
+    } else {
+        channel = xmlGenericError;
+        data = xmlGenericErrorContext;
+    }
+
+    if (code == XML_IO_NETWORK_ATTEMPT) {
+        fmt = "Attempt to load network entity %s";
+        arg = extra;
+    } else {
+        fmt = "%s";
+        arg = xmlErrString(code);
+    }
+
+    res = __xmlRaiseError(schannel, channel, data, NULL, NULL,
+                          domain, code, XML_ERR_ERROR, NULL, 0,
+                          extra, NULL, NULL, 0, 0,
+                          fmt, arg);
+    if (res < 0) {
+        xmlIOErrMemory();
+        return(XML_ERR_NO_MEMORY);
+    }
+
+    return(code);
 }
 
 /**
@@ -400,160 +336,12 @@
  *
  * Handle an I/O error
  */
-static void
+static int
 xmlIOErr(int code, const char *extra)
 {
-    __xmlIOErr(XML_FROM_IO, code, extra);
+    return(__xmlIOErr(XML_FROM_IO, code, extra));
 }
 
-/**
- * __xmlLoaderErr:
- * @ctx: the parser context
- * @extra:  extra information
- *
- * Handle a resource access error
- */
-void
-xmlLoaderErr(xmlParserCtxtPtr ctxt, const char *msg, const char *filename)
-{
-    xmlErrorLevel level;
-
-    if (ctxt->validate)
-        level = XML_ERR_ERROR;
-    else
-        level = XML_ERR_WARNING;
-
-    xmlErrParser(ctxt, NULL, XML_FROM_IO, XML_IO_LOAD_ERROR, level,
-                 (const xmlChar *) filename, NULL, NULL, 0,
-		 msg, filename);
-
-}
-
-/************************************************************************
- *									*
- *		Tree memory error handler				*
- *									*
- ************************************************************************/
-/**
- * xmlNormalizeWindowsPath:
- * @path: the input file path
- *
- * This function is obsolete. Please see xmlURIFromPath in uri.c for
- * a better solution.
- *
- * Returns a canonicalized version of the path
- */
-xmlChar *
-xmlNormalizeWindowsPath(const xmlChar *path)
-{
-    return xmlCanonicPath(path);
-}
-
-/**
- * xmlCleanupInputCallbacks:
- *
- * clears the entire input callback table. this includes the
- * compiled-in I/O.
- */
-void
-xmlCleanupInputCallbacks(void)
-{
-    int i;
-
-    if (!xmlInputCallbackInitialized)
-        return;
-
-    for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
-        xmlInputCallbackTable[i].matchcallback = NULL;
-        xmlInputCallbackTable[i].opencallback = NULL;
-        xmlInputCallbackTable[i].readcallback = NULL;
-        xmlInputCallbackTable[i].closecallback = NULL;
-    }
-
-    xmlInputCallbackNr = 0;
-    xmlInputCallbackInitialized = 0;
-}
-
-/**
- * xmlPopInputCallbacks:
- *
- * Clear the top input callback from the input stack. this includes the
- * compiled-in I/O.
- *
- * Returns the number of input callback registered or -1 in case of error.
- */
-int
-xmlPopInputCallbacks(void)
-{
-    if (!xmlInputCallbackInitialized)
-        return(-1);
-
-    if (xmlInputCallbackNr <= 0)
-        return(-1);
-
-    xmlInputCallbackNr--;
-    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
-    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
-    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
-    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
-
-    return(xmlInputCallbackNr);
-}
-
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlCleanupOutputCallbacks:
- *
- * clears the entire output callback table. this includes the
- * compiled-in I/O callbacks.
- */
-void
-xmlCleanupOutputCallbacks(void)
-{
-    int i;
-
-    if (!xmlOutputCallbackInitialized)
-        return;
-
-    for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
-        xmlOutputCallbackTable[i].matchcallback = NULL;
-        xmlOutputCallbackTable[i].opencallback = NULL;
-        xmlOutputCallbackTable[i].writecallback = NULL;
-        xmlOutputCallbackTable[i].closecallback = NULL;
-    }
-
-    xmlOutputCallbackNr = 0;
-    xmlOutputCallbackInitialized = 0;
-}
-
-/**
- * xmlPopOutputCallbacks:
- *
- * Remove the top output callbacks from the output stack. This includes the
- * compiled-in I/O.
- *
- * Returns the number of output callback registered or -1 in case of error.
- */
-int
-xmlPopOutputCallbacks(void)
-{
-    if (!xmlOutputCallbackInitialized)
-        return(-1);
-
-    if (xmlOutputCallbackNr <= 0)
-        return(-1);
-
-    xmlOutputCallbackNr--;
-    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = NULL;
-    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = NULL;
-    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = NULL;
-    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = NULL;
-
-    return(xmlOutputCallbackNr);
-}
-
-#endif /* LIBXML_OUTPUT_ENABLED */
-
 /************************************************************************
  *									*
  *		Standard I/O for file accesses				*
@@ -563,92 +351,65 @@
 #if defined(_WIN32)
 
 /**
- *  xmlWrapOpenUtf8:
- * @path:  the path in utf-8 encoding
- * @mode:  type of access (0 - read, 1 - write)
+ * __xmlIOWin32UTF8ToWChar:
+ * @u8String:  uft-8 string
  *
- * function opens the file specified by @path
- *
+ * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
  */
-static FILE*
-xmlWrapOpenUtf8(const char *path,int mode)
+static wchar_t *
+__xmlIOWin32UTF8ToWChar(const char *u8String)
 {
-    FILE *fd = NULL;
-    wchar_t *wPath;
+    wchar_t *wString = NULL;
+    int i;
 
-    wPath = __xmlIOWin32UTF8ToWChar(path);
-    if(wPath)
-    {
-       fd = _wfopen(wPath, mode ? L"wb" : L"rb");
-       xmlFree(wPath);
-    }
-    /* maybe path in native encoding */
-    if(fd == NULL)
-       fd = fopen(path, mode ? "wb" : "rb");
+    if (u8String) {
+        int wLen =
+            MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
+                                -1, NULL, 0);
+        if (wLen) {
+            wString = xmlMalloc(wLen * sizeof(wchar_t));
+            if (wString) {
+                if (MultiByteToWideChar
+                    (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
+                    xmlFree(wString);
+                    wString = NULL;
+                }
+            }
 
-    return fd;
-}
-
-#ifdef LIBXML_ZLIB_ENABLED
-static gzFile
-xmlWrapGzOpenUtf8(const char *path, const char *mode)
-{
-    gzFile fd;
-    wchar_t *wPath;
-
-    fd = gzopen (path, mode);
-    if (fd)
-        return fd;
-
-    wPath = __xmlIOWin32UTF8ToWChar(path);
-    if(wPath)
-    {
-	int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
-#ifdef _O_BINARY
-        m |= (strstr(mode, "b") ? _O_BINARY : 0);
-#endif
-	d = _wopen(wPath, m);
-	if (d >= 0)
-	    fd = gzdopen(d, mode);
-        xmlFree(wPath);
+            /*
+             * Convert to backward slash
+             */
+            for (i = 0; wString[i] != 0; i++) {
+                if (wString[i] == '/')
+                    wString[i] = '\\';
+            }
+        }
     }
 
-    return fd;
+    return wString;
 }
+
 #endif
 
 /**
- *  xmlWrapStatUtf8:
- * @path:  the path in utf-8 encoding
- * @info:  structure that stores results
+ * xmlNormalizeWindowsPath:
+ * @path: the input file path
  *
- * function obtains information about the file or directory
+ * DEPRECATED: This never really worked.
  *
+ * Returns a copy of path.
  */
-static int
-xmlWrapStatUtf8(const char *path, struct _stat *info) {
-    int retval = -1;
-    wchar_t *wPath;
-
-    wPath = __xmlIOWin32UTF8ToWChar(path);
-    if (wPath) {
-       retval = _wstat(wPath, info);
-       xmlFree(wPath);
-    }
-    /* maybe path in native encoding */
-    if(retval < 0)
-       retval = _stat(path, info);
-    return retval;
+xmlChar *
+xmlNormalizeWindowsPath(const xmlChar *path)
+{
+    return xmlStrdup(path);
 }
 
-#endif
-
 /**
  * xmlCheckFilename:
  * @path:  the path to check
  *
- * function checks to see if @path is a valid source
- * (file, socket...) for XML.
+ * DEPRECATED: Internal function, don't use.
  *
  * if stat is not available on the target machine,
  * returns 1.  if stat fails, returns 0 (if calling
@@ -656,9 +417,8 @@
  * if stat succeeds and the file is a directory,
  * returns 2.  otherwise returns 1.
  */
-
 int
-xmlCheckFilename (const char *path)
+xmlCheckFilename(const char *path)
 {
 #ifdef HAVE_STAT
 #if defined(_WIN32)
@@ -666,34 +426,149 @@
 #else
     struct stat stat_buffer;
 #endif
+    int res;
 #endif
+
     if (path == NULL)
 	return(0);
 
 #ifdef HAVE_STAT
 #if defined(_WIN32)
-    /*
-     * On Windows stat and wstat do not work with long pathname,
-     * which start with '\\?\'
-     */
-    if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
-	(path[3] == '\\') )
-	    return 1;
+    {
+        wchar_t *wpath;
 
-    if (xmlWrapStatUtf8(path, &stat_buffer) == -1)
-        return 0;
+        /*
+         * On Windows stat and wstat do not work with long pathname,
+         * which start with '\\?\'
+         */
+        if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
+            (path[3] == '\\') )
+                return 1;
+
+        wpath = __xmlIOWin32UTF8ToWChar(path);
+        if (wpath == NULL)
+            return(0);
+        res = _wstat(wpath, &stat_buffer);
+        xmlFree(wpath);
+    }
 #else
-    if (stat(path, &stat_buffer) == -1)
-        return 0;
+    res = stat(path, &stat_buffer);
 #endif
+
+    if (res < 0)
+        return 0;
+
 #ifdef S_ISDIR
     if (S_ISDIR(stat_buffer.st_mode))
         return 2;
 #endif
 #endif /* HAVE_STAT */
+
     return 1;
 }
 
+static int
+xmlConvertUriToPath(const char *uri, char **out) {
+    const char *escaped;
+    char *unescaped;
+
+    *out = NULL;
+
+    if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file://localhost/", 17)) {
+	escaped = &uri[16];
+    } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:///", 8)) {
+	escaped = &uri[7];
+    } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:/", 6)) {
+        /* lots of generators seems to lazy to read RFC 1738 */
+	escaped = &uri[5];
+    } else {
+        return(1);
+    }
+
+#ifdef _WIN32
+    /* Ignore slash like in file:///C:/file.txt */
+    escaped += 1;
+#endif
+
+    unescaped = xmlURIUnescapeString(escaped, 0, NULL);
+    if (unescaped == NULL)
+        return(-1);
+
+    *out = unescaped;
+    return(0);
+}
+
+/**
+ * xmlFdOpen:
+ * @filename:  the URI for matching
+ * @out:  pointer to resulting context
+ *
+ * Returns an xmlParserErrors code
+ */
+static int
+xmlFdOpen(const char *filename, int write, int *out) {
+    char *fromUri = NULL;
+    int flags;
+    int fd;
+    int ret;
+
+    *out = -1;
+    if (filename == NULL)
+        return(XML_ERR_ARGUMENT);
+
+    if (xmlConvertUriToPath(filename, &fromUri) < 0)
+        return(XML_ERR_NO_MEMORY);
+
+    if (fromUri != NULL)
+        filename = fromUri;
+
+#if defined(_WIN32)
+    {
+        wchar_t *wpath;
+
+        wpath = __xmlIOWin32UTF8ToWChar(filename);
+        if (wpath == NULL) {
+            xmlFree(fromUri);
+            return(XML_ERR_NO_MEMORY);
+        }
+        if (write)
+            flags = _O_WRONLY | _O_CREAT | _O_TRUNC;
+        else
+            flags = _O_RDONLY;
+	fd = _wopen(wpath, flags | _O_BINARY, 0777);
+        xmlFree(wpath);
+    }
+#else
+    if (write)
+        flags = O_WRONLY | O_CREAT | O_TRUNC;
+    else
+        flags = O_RDONLY;
+    fd = open(filename, flags, 0777);
+#endif /* WIN32 */
+
+    if (fd < 0) {
+        /*
+         * Windows and possibly other platforms return EINVAL
+         * for invalid filenames.
+         */
+        if ((errno == ENOENT) || (errno == EINVAL)) {
+            ret = XML_IO_ENOENT;
+        } else {
+            /*
+             * This error won't be forwarded to the parser context
+             * which will report it a second time.
+             */
+            ret = xmlIOErr(0, filename);
+        }
+    } else {
+        *out = fd;
+        ret = XML_ERR_OK;
+    }
+
+    xmlFree(fromUri);
+    return(ret);
+}
+
 /**
  * xmlFdRead:
  * @context:  the I/O context
@@ -702,14 +577,32 @@
  *
  * Read @len bytes to @buffer from the I/O channel.
  *
- * Returns the number of bytes written
+ * Returns the number of bytes read
  */
 static int
-xmlFdRead (void * context, char * buffer, int len) {
-    int ret;
+xmlFdRead(void *context, char *buffer, int len) {
+    int fd = (int) (ptrdiff_t) context;
+    int ret = 0;
+    int bytes;
 
-    ret = read((int) (ptrdiff_t) context, &buffer[0], len);
-    if (ret < 0) xmlIOErr(0, "read()");
+    while (len > 0) {
+        bytes = read(fd, buffer, len);
+        if (bytes < 0) {
+            /*
+             * If we already got some bytes, return them without
+             * raising an error.
+             */
+            if (ret > 0)
+                break;
+            return(-xmlIOErr(0, "read()"));
+        }
+        if (bytes == 0)
+            break;
+        ret += bytes;
+        buffer += bytes;
+        len -= bytes;
+    }
+
     return(ret);
 }
 
@@ -725,13 +618,20 @@
  * Returns the number of bytes written
  */
 static int
-xmlFdWrite (void * context, const char * buffer, int len) {
+xmlFdWrite(void *context, const char *buffer, int len) {
+    int fd = (int) (ptrdiff_t) context;
     int ret = 0;
+    int bytes;
 
-    if (len > 0) {
-	ret = write((int) (ptrdiff_t) context, &buffer[0], len);
-	if (ret < 0) xmlIOErr(0, "write()");
+    while (len > 0) {
+	bytes = write(fd, buffer, len);
+	if (bytes < 0)
+            return(-xmlIOErr(0, "write()"));
+        ret += bytes;
+        buffer += bytes;
+        len -= bytes;
     }
+
     return(ret);
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
@@ -747,16 +647,19 @@
 static int
 xmlFdClose (void * context) {
     int ret;
+
     ret = close((int) (ptrdiff_t) context);
-    if (ret < 0) xmlIOErr(0, "close()");
-    return(ret);
+    if (ret < 0)
+        return(xmlIOErr(0, "close()"));
+
+    return(XML_ERR_OK);
 }
 
 /**
  * xmlFileMatch:
  * @filename:  the URI for matching
  *
- * input from FILE *
+ * DEPRECATED: Internal function, don't use.
  *
  * Returns 1 if matches, 0 otherwise
  */
@@ -766,158 +669,113 @@
 }
 
 /**
- * xmlFileOpen_real:
+ * xmlFileOpenSafe:
  * @filename:  the URI for matching
+ * @out:  pointer to resulting context
  *
- * input from FILE *, supports compressed input
- * if @filename is " " then the standard input is used
+ * input from FILE *
  *
  * Returns an I/O context or NULL in case of error
  */
-static void *
-xmlFileOpen_real (const char *filename) {
-    const char *path = filename;
+static int
+xmlFileOpenSafe(const char *filename, int write, void **out) {
+    char *fromUri = NULL;
     FILE *fd;
+    int ret = XML_ERR_OK;
 
+    *out = NULL;
     if (filename == NULL)
-        return(NULL);
+        return(XML_ERR_ARGUMENT);
 
-    if (!strcmp(filename, "-")) {
-	fd = stdin;
-	return((void *) fd);
-    }
+    if (xmlConvertUriToPath(filename, &fromUri) < 0)
+        return(XML_ERR_NO_MEMORY);
 
-    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
-#if defined (_WIN32)
-	path = &filename[17];
-#else
-	path = &filename[16];
-#endif
-    } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
-#if defined (_WIN32)
-	path = &filename[8];
-#else
-	path = &filename[7];
-#endif
-    } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
-        /* lots of generators seems to lazy to read RFC 1738 */
-#if defined (_WIN32)
-	path = &filename[6];
-#else
-	path = &filename[5];
-#endif
-    }
-
-    /* Do not check DDNAME on zOS ! */
-#if !defined(__MVS__)
-    if (!xmlCheckFilename(path))
-        return(NULL);
-#endif
+    if (fromUri != NULL)
+        filename = fromUri;
 
 #if defined(_WIN32)
-    fd = xmlWrapOpenUtf8(path, 0);
+    {
+        wchar_t *wpath;
+
+        wpath = __xmlIOWin32UTF8ToWChar(filename);
+        if (wpath == NULL) {
+            xmlFree(fromUri);
+            return(XML_ERR_NO_MEMORY);
+        }
+	fd = _wfopen(wpath, write ? L"wb" : L"rb");
+        xmlFree(wpath);
+    }
 #else
-    fd = fopen(path, "rb");
+    fd = fopen(filename, write ? "wb" : "rb");
 #endif /* WIN32 */
-    if (fd == NULL) xmlIOErr(0, path);
-    return((void *) fd);
+
+    if (fd == NULL) {
+        /*
+         * Windows and possibly other platforms return EINVAL
+         * for invalid filenames.
+         */
+        if ((errno == ENOENT) || (errno == EINVAL)) {
+            ret = XML_IO_ENOENT;
+        } else {
+            /*
+             * This error won't be forwarded to the parser context
+             * which will report it a second time.
+             */
+            ret = xmlIOErr(0, filename);
+        }
+    }
+
+    *out = fd;
+    xmlFree(fromUri);
+    return(ret);
 }
 
 /**
  * xmlFileOpen:
  * @filename:  the URI for matching
  *
- * Wrapper around xmlFileOpen_real that try it with an unescaped
- * version of @filename, if this fails fallback to @filename
+ * DEPRECATED: Internal function, don't use.
  *
- * Returns a handler or NULL in case or failure
+ * Returns an IO context or NULL in case or failure
  */
 void *
-xmlFileOpen (const char *filename) {
-    char *unescaped;
-    void *retval;
+xmlFileOpen(const char *filename) {
+    void *context;
 
-    retval = xmlFileOpen_real(filename);
-    if (retval == NULL) {
-	unescaped = xmlURIUnescapeString(filename, 0, NULL);
-	if (unescaped != NULL) {
-	    retval = xmlFileOpen_real(unescaped);
-	    xmlFree(unescaped);
-	}
-    }
-
-    return retval;
+    xmlFileOpenSafe(filename, 0, &context);
+    return(context);
 }
 
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlFileOpenW:
- * @filename:  the URI for matching
- *
- * output to from FILE *,
- * if @filename is "-" then the standard output is used
- *
- * Returns an I/O context or NULL in case of error
- */
-static void *
-xmlFileOpenW (const char *filename) {
-    const char *path = NULL;
-    FILE *fd;
-
-    if (!strcmp(filename, "-")) {
-	fd = stdout;
-	return((void *) fd);
-    }
-
-    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
-#if defined (_WIN32)
-	path = &filename[17];
-#else
-	path = &filename[16];
-#endif
-    else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
-#if defined (_WIN32)
-	path = &filename[8];
-#else
-	path = &filename[7];
-#endif
-    } else
-	path = filename;
-
-    if (path == NULL)
-	return(NULL);
-
-#if defined(_WIN32)
-    fd = xmlWrapOpenUtf8(path, 1);
-#elif(__MVS__)
-    fd = fopen(path, "w");
-#else
-    fd = fopen(path, "wb");
-#endif /* WIN32 */
-
-    if (fd == NULL) xmlIOErr(0, path);
-    return((void *) fd);
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
 /**
  * xmlFileRead:
  * @context:  the I/O context
  * @buffer:  where to drop data
  * @len:  number of bytes to write
  *
- * Read @len bytes to @buffer from the I/O channel.
+ * DEPRECATED: Internal function, don't use.
  *
- * Returns the number of bytes written or < 0 in case of failure
+ * Returns the number of bytes read or < 0 in case of failure
  */
 int
-xmlFileRead (void * context, char * buffer, int len) {
-    int ret;
+xmlFileRead(void * context, char * buffer, int len) {
+    FILE *file = context;
+    size_t bytes;
+
     if ((context == NULL) || (buffer == NULL))
         return(-1);
-    ret = fread(&buffer[0], 1,  len, (FILE *) context);
-    if (ret < 0) xmlIOErr(0, "fread()");
-    return(ret);
+
+    /*
+     * The C standard doesn't mandate that fread sets errno, only
+     * POSIX does. The Windows documentation isn't really clear.
+     * Set errno to zero which will be reported as unknown error
+     * if fread fails without setting errno.
+     */
+    errno = 0;
+    bytes = fread(buffer, 1, len, file);
+    if ((bytes < (size_t) len) && (ferror(file)))
+        return(-xmlIOErr(0, "fread()"));
+
+    return(len);
 }
 
 #ifdef LIBXML_OUTPUT_ENABLED
@@ -932,51 +790,23 @@
  * Returns the number of bytes written
  */
 static int
-xmlFileWrite (void * context, const char * buffer, int len) {
-    int items;
+xmlFileWrite(void *context, const char *buffer, int len) {
+    FILE *file = context;
+    size_t bytes;
 
     if ((context == NULL) || (buffer == NULL))
         return(-1);
-    items = fwrite(&buffer[0], len, 1, (FILE *) context);
-    if ((items == 0) && (ferror((FILE *) context))) {
-        xmlIOErr(0, "fwrite()");
-	return(-1);
-    }
-    return(items * len);
+
+    errno = 0;
+    bytes = fwrite(buffer, 1, len, file);
+    if (bytes < (size_t) len)
+        return(-xmlIOErr(0, "fwrite()"));
+
+    return(len);
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
 
 /**
- * xmlFileClose:
- * @context:  the I/O context
- *
- * Close an I/O channel
- *
- * Returns 0 or -1 in case of error
- */
-int
-xmlFileClose (void * context) {
-    FILE *fil;
-    int ret;
-
-    if (context == NULL)
-        return(-1);
-    fil = (FILE *) context;
-    if ((fil == stdout) || (fil == stderr)) {
-        ret = fflush(fil);
-	if (ret < 0)
-	    xmlIOErr(0, "fflush()");
-	return(0);
-    }
-    if (fil == stdin)
-	return(0);
-    ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
-    if (ret < 0)
-        xmlIOErr(0, "fclose()");
-    return(ret);
-}
-
-/**
  * xmlFileFlush:
  * @context:  the I/O context
  *
@@ -984,14 +814,41 @@
  */
 static int
 xmlFileFlush (void * context) {
-    int ret;
+    FILE *file = context;
+
+    if (file == NULL)
+        return(-1);
+
+    if (fflush(file) != 0)
+        return(xmlIOErr(0, "fflush()"));
+
+    return(XML_ERR_OK);
+}
+
+/**
+ * xmlFileClose:
+ * @context:  the I/O context
+ *
+ * DEPRECATED: Internal function, don't use.
+ *
+ * Returns 0 or -1 an error code case of error
+ */
+int
+xmlFileClose (void * context) {
+    FILE *file = context;
 
     if (context == NULL)
         return(-1);
-    ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
-    if (ret < 0)
-        xmlIOErr(0, "fflush()");
-    return(ret);
+
+    if (file == stdin)
+        return(0);
+    if ((file == stdout) || (file == stderr))
+        return(xmlFileFlush(file));
+
+    if (fclose(file) != 0)
+        return(xmlIOErr(0, "fclose()"));
+
+    return(0);
 }
 
 #ifdef LIBXML_OUTPUT_ENABLED
@@ -1023,148 +880,6 @@
  *		I/O for compressed file accesses			*
  *									*
  ************************************************************************/
-/**
- * xmlGzfileMatch:
- * @filename:  the URI for matching
- *
- * input from compressed file test
- *
- * Returns 1 if matches, 0 otherwise
- */
-static int
-xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
-    return(1);
-}
-
-/**
- * xmlGzfileOpen_real:
- * @filename:  the URI for matching
- *
- * input from compressed file open
- * if @filename is " " then the standard input is used
- *
- * Returns an I/O context or NULL in case of error
- */
-static void *
-xmlGzfileOpen_real (const char *filename) {
-    const char *path = NULL;
-    gzFile fd;
-
-    if (!strcmp(filename, "-")) {
-        int duped_fd = dup(fileno(stdin));
-        fd = gzdopen(duped_fd, "rb");
-        if (fd == Z_NULL && duped_fd >= 0) {
-            close(duped_fd);  /* gzdOpen() does not close on failure */
-        }
-
-	return((void *) fd);
-    }
-
-    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
-#if defined (_WIN32)
-	path = &filename[17];
-#else
-	path = &filename[16];
-#endif
-    else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
-#if defined (_WIN32)
-	path = &filename[8];
-#else
-	path = &filename[7];
-#endif
-    } else
-	path = filename;
-
-    if (path == NULL)
-	return(NULL);
-    if (!xmlCheckFilename(path))
-        return(NULL);
-
-#if defined(_WIN32)
-    fd = xmlWrapGzOpenUtf8(path, "rb");
-#else
-    fd = gzopen(path, "rb");
-#endif
-    return((void *) fd);
-}
-
-/**
- * xmlGzfileOpen:
- * @filename:  the URI for matching
- *
- * Wrapper around xmlGzfileOpen_real if the open fails, it will
- * try to unescape @filename
- */
-static void *
-xmlGzfileOpen (const char *filename) {
-    char *unescaped;
-    void *retval;
-
-    retval = xmlGzfileOpen_real(filename);
-    if (retval == NULL) {
-	unescaped = xmlURIUnescapeString(filename, 0, NULL);
-	if (unescaped != NULL) {
-	    retval = xmlGzfileOpen_real(unescaped);
-	}
-	xmlFree(unescaped);
-    }
-    return retval;
-}
-
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlGzfileOpenW:
- * @filename:  the URI for matching
- * @compression:  the compression factor (0 - 9 included)
- *
- * input from compressed file open
- * if @filename is " " then the standard input is used
- *
- * Returns an I/O context or NULL in case of error
- */
-static void *
-xmlGzfileOpenW (const char *filename, int compression) {
-    const char *path = NULL;
-    char mode[15];
-    gzFile fd;
-
-    snprintf(mode, sizeof(mode), "wb%d", compression);
-    if (!strcmp(filename, "-")) {
-        int duped_fd = dup(fileno(stdout));
-        fd = gzdopen(duped_fd, "rb");
-        if (fd == Z_NULL && duped_fd >= 0) {
-            close(duped_fd);  /* gzdOpen() does not close on failure */
-        }
-
-	return((void *) fd);
-    }
-
-    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
-#if defined (_WIN32)
-	path = &filename[17];
-#else
-	path = &filename[16];
-#endif
-    else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
-#if defined (_WIN32)
-	path = &filename[8];
-#else
-	path = &filename[7];
-#endif
-    } else
-	path = filename;
-
-    if (path == NULL)
-	return(NULL);
-
-#if defined(_WIN32)
-    fd = xmlWrapGzOpenUtf8(path, mode);
-#else
-    fd = gzopen(path, mode);
-#endif
-    return((void *) fd);
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
 
 /**
  * xmlGzfileRead:
@@ -1222,89 +937,15 @@
 }
 #endif /* LIBXML_ZLIB_ENABLED */
 
-#ifdef LIBXML_LZMA_ENABLED
 /************************************************************************
  *									*
  *		I/O for compressed file accesses			*
  *									*
  ************************************************************************/
+
+#ifdef LIBXML_LZMA_ENABLED
+
 #include "private/xzlib.h"
-/**
- * xmlXzfileMatch:
- * @filename:  the URI for matching
- *
- * input from compressed file test
- *
- * Returns 1 if matches, 0 otherwise
- */
-static int
-xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
-    return(1);
-}
-
-/**
- * xmlXzFileOpen_real:
- * @filename:  the URI for matching
- *
- * input from compressed file open
- * if @filename is " " then the standard input is used
- *
- * Returns an I/O context or NULL in case of error
- */
-static void *
-xmlXzfileOpen_real (const char *filename) {
-    const char *path = NULL;
-    xzFile fd;
-
-    if (!strcmp(filename, "-")) {
-        fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
-	return((void *) fd);
-    }
-
-    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
-	path = &filename[16];
-    } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
-	path = &filename[7];
-    } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
-        /* lots of generators seems to lazy to read RFC 1738 */
-	path = &filename[5];
-    } else
-	path = filename;
-
-    if (path == NULL)
-	return(NULL);
-    if (!xmlCheckFilename(path))
-        return(NULL);
-
-    fd = __libxml2_xzopen(path, "rb");
-    return((void *) fd);
-}
-
-/**
- * xmlXzfileOpen:
- * @filename:  the URI for matching
- *
- * Wrapper around xmlXzfileOpen_real that try it with an unescaped
- * version of @filename, if this fails fallback to @filename
- *
- * Returns a handler or NULL in case or failure
- */
-static void *
-xmlXzfileOpen (const char *filename) {
-    char *unescaped;
-    void *retval;
-
-    retval = xmlXzfileOpen_real(filename);
-    if (retval == NULL) {
-	unescaped = xmlURIUnescapeString(filename, 0, NULL);
-	if (unescaped != NULL) {
-	    retval = xmlXzfileOpen_real(unescaped);
-	}
-	xmlFree(unescaped);
-    }
-
-    return retval;
-}
 
 /**
  * xmlXzfileRead:
@@ -1341,371 +982,19 @@
 }
 #endif /* LIBXML_LZMA_ENABLED */
 
-#ifdef LIBXML_HTTP_ENABLED
 /************************************************************************
  *									*
  *			I/O for HTTP file accesses			*
  *									*
  ************************************************************************/
 
-#ifdef LIBXML_OUTPUT_ENABLED
-typedef struct xmlIOHTTPWriteCtxt_
-{
-    int			compression;
-
-    char *		uri;
-
-    void *		doc_buff;
-
-} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
-
-#ifdef LIBXML_ZLIB_ENABLED
-
-#define DFLT_WBITS		( -15 )
-#define DFLT_MEM_LVL		( 8 )
-#define GZ_MAGIC1		( 0x1f )
-#define GZ_MAGIC2		( 0x8b )
-#define LXML_ZLIB_OS_CODE	( 0x03 )
-#define INIT_HTTP_BUFF_SIZE	( 32768 )
-#define DFLT_ZLIB_RATIO		( 5 )
-
-/*
-**  Data structure and functions to work with sending compressed data
-**  via HTTP.
-*/
-
-typedef struct xmlZMemBuff_
-{
-   unsigned long	size;
-   unsigned long	crc;
-
-   unsigned char *	zbuff;
-   z_stream		zctrl;
-
-} xmlZMemBuff, *xmlZMemBuffPtr;
-
-/**
- * append_reverse_ulong
- * @buff:  Compressed memory buffer
- * @data:  Unsigned long to append
- *
- * Append a unsigned long in reverse byte order to the end of the
- * memory buffer.
- */
-static void
-append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
-
-    int		idx;
-
-    if ( buff == NULL )
-	return;
-
-    /*
-    **  This is plagiarized from putLong in gzio.c (zlib source) where
-    **  the number "4" is hardcoded.  If zlib is ever patched to
-    **  support 64 bit file sizes, this code would need to be patched
-    **  as well.
-    */
-
-    for ( idx = 0; idx < 4; idx++ ) {
-	*buff->zctrl.next_out = ( data & 0xff );
-	data >>= 8;
-	buff->zctrl.next_out++;
-    }
-
-    return;
-}
-
-/**
- *
- * xmlFreeZMemBuff
- * @buff:  The memory buffer context to clear
- *
- * Release all the resources associated with the compressed memory buffer.
- */
-static void
-xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
-
-    if ( buff == NULL )
-	return;
-
-    xmlFree( buff->zbuff );
-    deflateEnd( &buff->zctrl );
-
-    xmlFree( buff );
-    return;
-}
-
-/**
- * xmlCreateZMemBuff
- *@compression:	Compression value to use
- *
- * Create a memory buffer to hold the compressed XML document.  The
- * compressed document in memory will end up being identical to what
- * would be created if gzopen/gzwrite/gzclose were being used to
- * write the document to disk.  The code for the header/trailer data to
- * the compression is plagiarized from the zlib source files.
- */
-static void *
-xmlCreateZMemBuff( int compression ) {
-
-    int			z_err;
-    int			hdr_lgth;
-    xmlZMemBuffPtr	buff = NULL;
-
-    if ( ( compression < 1 ) || ( compression > 9 ) )
-	return ( NULL );
-
-    /*  Create the control and data areas  */
-
-    buff = xmlMalloc( sizeof( xmlZMemBuff ) );
-    if ( buff == NULL ) {
-	xmlIOErrMemory("creating buffer context");
-	return ( NULL );
-    }
-
-    (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
-    buff->size = INIT_HTTP_BUFF_SIZE;
-    buff->zbuff = xmlMalloc( buff->size );
-    if ( buff->zbuff == NULL ) {
-	xmlFreeZMemBuff( buff );
-	xmlIOErrMemory("creating buffer");
-	return ( NULL );
-    }
-
-    z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
-			    DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
-    if ( z_err != Z_OK ) {
-	xmlChar msg[500];
-	xmlFreeZMemBuff( buff );
-	buff = NULL;
-	xmlStrPrintf(msg, 500,
-		    "xmlCreateZMemBuff:  %s %d\n",
-		    "Error initializing compression context.  ZLIB error:",
-		    z_err );
-	xmlIOErr(XML_IO_WRITE, (const char *) msg);
-	return ( NULL );
-    }
-
-    /*  Set the header data.  The CRC will be needed for the trailer  */
-    buff->crc = crc32( 0L, NULL, 0 );
-    hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
-			"%c%c%c%c%c%c%c%c%c%c",
-			GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
-			0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
-    buff->zctrl.next_out  = buff->zbuff + hdr_lgth;
-    buff->zctrl.avail_out = buff->size - hdr_lgth;
-
-    return ( buff );
-}
-
-/**
- * xmlZMemBuffExtend
- * @buff:  Buffer used to compress and consolidate data.
- * @ext_amt:   Number of bytes to extend the buffer.
- *
- * Extend the internal buffer used to store the compressed data by the
- * specified amount.
- *
- * Returns 0 on success or -1 on failure to extend the buffer.  On failure
- * the original buffer still exists at the original size.
- */
-static int
-xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
-
-    int			rc = -1;
-    size_t		new_size;
-    size_t		cur_used;
-
-    unsigned char *	tmp_ptr = NULL;
-
-    if ( buff == NULL )
-	return ( -1 );
-
-    else if ( ext_amt == 0 )
-	return ( 0 );
-
-    cur_used = buff->zctrl.next_out - buff->zbuff;
-    new_size = buff->size + ext_amt;
-
-    tmp_ptr = xmlRealloc( buff->zbuff, new_size );
-    if ( tmp_ptr != NULL ) {
-	rc = 0;
-	buff->size  = new_size;
-	buff->zbuff = tmp_ptr;
-	buff->zctrl.next_out  = tmp_ptr + cur_used;
-	buff->zctrl.avail_out = new_size - cur_used;
-    }
-    else {
-	xmlChar msg[500];
-	xmlStrPrintf(msg, 500,
-		    "xmlZMemBuffExtend:  %s %lu bytes.\n",
-		    "Allocation failure extending output buffer to",
-		    (unsigned long) new_size );
-	xmlIOErr(XML_IO_WRITE, (const char *) msg);
-    }
-
-    return ( rc );
-}
-
-/**
- * xmlZMemBuffAppend
- * @buff:  Buffer used to compress and consolidate data
- * @src:   Uncompressed source content to append to buffer
- * @len:   Length of source data to append to buffer
- *
- * Compress and append data to the internal buffer.  The data buffer
- * will be expanded if needed to store the additional data.
- *
- * Returns the number of bytes appended to the buffer or -1 on error.
- */
-static int
-xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
-
-    int		z_err;
-    size_t	min_accept;
-
-    if ( ( buff == NULL ) || ( src == NULL ) )
-	return ( -1 );
-
-    buff->zctrl.avail_in = len;
-    buff->zctrl.next_in  = (unsigned char *)src;
-    while ( buff->zctrl.avail_in > 0 ) {
-	/*
-	**  Extend the buffer prior to deflate call if a reasonable amount
-	**  of output buffer space is not available.
-	*/
-	min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
-	if ( buff->zctrl.avail_out <= min_accept ) {
-	    if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
-		return ( -1 );
-	}
-
-	z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
-	if ( z_err != Z_OK ) {
-	    xmlChar msg[500];
-	    xmlStrPrintf(msg, 500,
-			"xmlZMemBuffAppend:  %s %d %s - %d",
-			"Compression error while appending",
-			len, "bytes to buffer.  ZLIB error", z_err );
-	    xmlIOErr(XML_IO_WRITE, (const char *) msg);
-	    return ( -1 );
-	}
-    }
-
-    buff->crc = crc32( buff->crc, (unsigned char *)src, len );
-
-    return ( len );
-}
-
-/**
- * xmlZMemBuffGetContent
- * @buff:  Compressed memory content buffer
- * @data_ref:  Pointer reference to point to compressed content
- *
- * Flushes the compression buffers, appends gzip file trailers and
- * returns the compressed content and length of the compressed data.
- * NOTE:  The gzip trailer code here is plagiarized from zlib source.
- *
- * Returns the length of the compressed data or -1 on error.
- */
-static int
-xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
-
-    int		zlgth = -1;
-    int		z_err;
-
-    if ( ( buff == NULL ) || ( data_ref == NULL ) )
-	return ( -1 );
-
-    /*  Need to loop until compression output buffers are flushed  */
-
-    do
-    {
-	z_err = deflate( &buff->zctrl, Z_FINISH );
-	if ( z_err == Z_OK ) {
-	    /*  In this case Z_OK means more buffer space needed  */
-
-	    if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
-		return ( -1 );
-	}
-    }
-    while ( z_err == Z_OK );
-
-    /*  If the compression state is not Z_STREAM_END, some error occurred  */
-
-    if ( z_err == Z_STREAM_END ) {
-
-	/*  Need to append the gzip data trailer  */
-
-	if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
-	    if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
-		return ( -1 );
-	}
-
-	/*
-	**  For whatever reason, the CRC and length data are pushed out
-	**  in reverse byte order.  So a memcpy can't be used here.
-	*/
-
-	append_reverse_ulong( buff, buff->crc );
-	append_reverse_ulong( buff, buff->zctrl.total_in );
-
-	zlgth = buff->zctrl.next_out - buff->zbuff;
-	*data_ref = (char *)buff->zbuff;
-    }
-
-    else {
-	xmlChar msg[500];
-	xmlStrPrintf(msg, 500,
-		    "xmlZMemBuffGetContent:  %s - %d\n",
-		    "Error flushing zlib buffers.  Error code", z_err );
-	xmlIOErr(XML_IO_WRITE, (const char *) msg);
-    }
-
-    return ( zlgth );
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-#endif  /*  LIBXML_ZLIB_ENABLED  */
-
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlFreeHTTPWriteCtxt
- * @ctxt:  Context to cleanup
- *
- * Free allocated memory and reclaim system resources.
- *
- * No return value.
- */
-static void
-xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
-{
-    if ( ctxt->uri != NULL )
-	xmlFree( ctxt->uri );
-
-    if ( ctxt->doc_buff != NULL ) {
-
-#ifdef LIBXML_ZLIB_ENABLED
-	if ( ctxt->compression > 0 ) {
-	    xmlFreeZMemBuff( ctxt->doc_buff );
-	}
-	else
-#endif
-	{
-	    xmlOutputBufferClose( ctxt->doc_buff );
-	}
-    }
-
-    xmlFree( ctxt );
-    return;
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
-
+#ifdef LIBXML_HTTP_ENABLED
 /**
  * xmlIOHTTPMatch:
  * @filename:  the URI for matching
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * check if the URI matches an HTTP one
  *
  * Returns 1 if matches, 0 otherwise
@@ -1721,6 +1010,8 @@
  * xmlIOHTTPOpen:
  * @filename:  the URI for matching
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * open an HTTP I/O channel
  *
  * Returns an I/O context or NULL in case of error
@@ -1736,78 +1027,15 @@
  * @post_uri:  The destination URI for the document
  * @compression:  The compression desired for the document.
  *
- * Open a temporary buffer to collect the document for a subsequent HTTP POST
- * request.  Non-static as is called from the output buffer creation routine.
+ * DEPRECATED: Support for HTTP POST has been removed.
  *
- * Returns an I/O context or NULL in case of error.
+ * Returns NULL.
  */
-
 void *
-xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED)
+xmlIOHTTPOpenW(const char *post_uri ATTRIBUTE_UNUSED,
+               int compression ATTRIBUTE_UNUSED)
 {
-
-    xmlIOHTTPWriteCtxtPtr ctxt = NULL;
-
-    if (post_uri == NULL)
-        return (NULL);
-
-    ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
-    if (ctxt == NULL) {
-	xmlIOErrMemory("creating HTTP output context");
-        return (NULL);
-    }
-
-    (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
-
-    ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
-    if (ctxt->uri == NULL) {
-	xmlIOErrMemory("copying URI");
-        xmlFreeHTTPWriteCtxt(ctxt);
-        return (NULL);
-    }
-
-    /*
-     * **  Since the document length is required for an HTTP post,
-     * **  need to put the document into a buffer.  A memory buffer
-     * **  is being used to avoid pushing the data to disk and back.
-     */
-
-#ifdef LIBXML_ZLIB_ENABLED
-    if ((compression > 0) && (compression <= 9)) {
-
-        ctxt->compression = compression;
-        ctxt->doc_buff = xmlCreateZMemBuff(compression);
-    } else
-#endif
-    {
-        /*  Any character conversions should have been done before this  */
-
-        ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
-    }
-
-    if (ctxt->doc_buff == NULL) {
-        xmlFreeHTTPWriteCtxt(ctxt);
-        ctxt = NULL;
-    }
-
-    return (ctxt);
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlIOHTTPDfltOpenW
- * @post_uri:  The destination URI for this document.
- *
- * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
- * HTTP post command.  This function should generally not be used as
- * the open callback is short circuited in xmlOutputBufferCreateFile.
- *
- * Returns a pointer to the new IO context.
- */
-static void *
-xmlIOHTTPDfltOpenW( const char * post_uri ) {
-    return ( xmlIOHTTPOpenW( post_uri, 0 ) );
+    return(NULL);
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
 
@@ -1817,6 +1045,8 @@
  * @buffer:  where to drop data
  * @len:  number of bytes to write
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Read @len bytes to @buffer from the I/O channel.
  *
  * Returns the number of bytes written
@@ -1827,59 +1057,12 @@
     return(xmlNanoHTTPRead(context, &buffer[0], len));
 }
 
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlIOHTTPWrite
- * @context:  previously opened writing context
- * @buffer:   data to output to temporary buffer
- * @len:      bytes to output
- *
- * Collect data from memory buffer into a temporary file for later
- * processing.
- *
- * Returns number of bytes written.
- */
-
-static int
-xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
-
-    xmlIOHTTPWriteCtxtPtr	ctxt = context;
-
-    if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
-	return ( -1 );
-
-    if ( len > 0 ) {
-
-	/*  Use gzwrite or fwrite as previously setup in the open call  */
-
-#ifdef LIBXML_ZLIB_ENABLED
-	if ( ctxt->compression > 0 )
-	    len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
-
-	else
-#endif
-	    len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
-
-	if ( len < 0 ) {
-	    xmlChar msg[500];
-	    xmlStrPrintf(msg, 500,
-			"xmlIOHTTPWrite:  %s\n%s '%s'.\n",
-			"Error appending to internal buffer.",
-			"Error sending document to URI",
-			ctxt->uri );
-	    xmlIOErr(XML_IO_WRITE, (const char *) msg);
-	}
-    }
-
-    return ( len );
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
-
 /**
  * xmlIOHTTPClose:
  * @context:  the I/O context
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Close an HTTP I/O channel
  *
  * Returns 0
@@ -1889,119 +1072,6 @@
     xmlNanoHTTPClose(context);
     return 0;
 }
-
-#ifdef LIBXML_OUTPUT_ENABLED
-/**
- * xmlIOHTTCloseWrite
- * @context:  The I/O context
- * @http_mthd: The HTTP method to be used when sending the data
- *
- * Close the transmit HTTP I/O channel and actually send the data.
- */
-static int
-xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
-
-    int				close_rc = -1;
-    int				http_rtn = 0;
-    int				content_lgth = 0;
-    xmlIOHTTPWriteCtxtPtr	ctxt = context;
-
-    char *			http_content = NULL;
-    char *			content_encoding = NULL;
-    char *			content_type = (char *) "text/xml";
-    void *			http_ctxt = NULL;
-
-    if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
-	return ( -1 );
-
-    /*  Retrieve the content from the appropriate buffer  */
-
-#ifdef LIBXML_ZLIB_ENABLED
-
-    if ( ctxt->compression > 0 ) {
-	content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
-	content_encoding = (char *) "Content-Encoding: gzip";
-    }
-    else
-#endif
-    {
-	/*  Pull the data out of the memory output buffer  */
-
-	xmlOutputBufferPtr	dctxt = ctxt->doc_buff;
-	http_content = (char *) xmlBufContent(dctxt->buffer);
-	content_lgth = xmlBufUse(dctxt->buffer);
-    }
-
-    if ( http_content == NULL ) {
-	xmlChar msg[500];
-	xmlStrPrintf(msg, 500,
-		     "xmlIOHTTPCloseWrite:  %s '%s' %s '%s'.\n",
-		     "Error retrieving content.\nUnable to",
-		     http_mthd, "data to URI", ctxt->uri );
-	xmlIOErr(XML_IO_WRITE, (const char *) msg);
-    }
-
-    else {
-
-	http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
-					&content_type, content_encoding,
-					content_lgth );
-
-	if ( http_ctxt != NULL ) {
-
-	    http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
-	    if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
-		close_rc = 0;
-	    else {
-                xmlChar msg[500];
-                xmlStrPrintf(msg, 500,
-                      "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
-			    http_mthd, content_lgth,
-			    "bytes to URI", ctxt->uri,
-			    "failed.  HTTP return code:", http_rtn );
-		xmlIOErr(XML_IO_WRITE, (const char *) msg);
-            }
-
-	    xmlNanoHTTPClose( http_ctxt );
-	    xmlFree( content_type );
-	}
-    }
-
-    /*  Final cleanups  */
-
-    xmlFreeHTTPWriteCtxt( ctxt );
-
-    return ( close_rc );
-}
-
-/**
- * xmlIOHTTPClosePut
- *
- * @context:  The I/O context
- *
- * Close the transmit HTTP I/O channel and actually send data using a PUT
- * HTTP method.
- */
-static int
-xmlIOHTTPClosePut( void * ctxt ) {
-    return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
-}
-
-
-/**
- * xmlIOHTTPClosePost
- *
- * @context:  The I/O context
- *
- * Close the transmit HTTP I/O channel and actually send data using a POST
- * HTTP method.
- */
-static int
-xmlIOHTTPClosePost( void * ctxt ) {
-    return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
 #endif /* LIBXML_HTTP_ENABLED */
 
 #ifdef LIBXML_FTP_ENABLED
@@ -2014,6 +1084,8 @@
  * xmlIOFTPMatch:
  * @filename:  the URI for matching
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * check if the URI matches an FTP one
  *
  * Returns 1 if matches, 0 otherwise
@@ -2029,6 +1101,8 @@
  * xmlIOFTPOpen:
  * @filename:  the URI for matching
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * open an FTP I/O channel
  *
  * Returns an I/O context or NULL in case of error
@@ -2044,6 +1118,8 @@
  * @buffer:  where to drop data
  * @len:  number of bytes to write
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Read @len bytes to @buffer from the I/O channel.
  *
  * Returns the number of bytes written
@@ -2058,6 +1134,8 @@
  * xmlIOFTPClose:
  * @context:  the I/O context
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Close an FTP I/O channel
  *
  * Returns 0
@@ -2068,155 +1146,182 @@
 }
 #endif /* LIBXML_FTP_ENABLED */
 
+/************************************************************************
+ *									*
+ *			Input/output buffers				*
+ *									*
+ ************************************************************************/
 
-/**
- * xmlRegisterInputCallbacks:
- * @matchFunc:  the xmlInputMatchCallback
- * @openFunc:  the xmlInputOpenCallback
- * @readFunc:  the xmlInputReadCallback
- * @closeFunc:  the xmlInputCloseCallback
- *
- * Register a new set of I/O callback for handling parser input.
- *
- * Returns the registered handler number or -1 in case of error
- */
-int
-xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
-	xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
-	xmlInputCloseCallback closeFunc) {
-    if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
-	return(-1);
-    }
-    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
-    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
-    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
-    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
-    xmlInputCallbackInitialized = 1;
-    return(xmlInputCallbackNr++);
+static int
+xmlIODefaultMatch(const char *filename ATTRIBUTE_UNUSED) {
+    return(1);
 }
 
-#ifdef LIBXML_OUTPUT_ENABLED
 /**
- * xmlRegisterOutputCallbacks:
- * @matchFunc:  the xmlOutputMatchCallback
- * @openFunc:  the xmlOutputOpenCallback
- * @writeFunc:  the xmlOutputWriteCallback
- * @closeFunc:  the xmlOutputCloseCallback
+ * xmlInputDefaultOpen:
+ * @buf:  input buffer to be filled
+ * @filename:  filename or URI
  *
- * Register a new set of I/O callback for handling output.
- *
- * Returns the registered handler number or -1 in case of error
+ * Returns an xmlParserErrors code.
  */
-int
-xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
-	xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
-	xmlOutputCloseCallback closeFunc) {
-    if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
-	return(-1);
+static int
+xmlInputDefaultOpen(xmlParserInputBufferPtr buf, const char *filename) {
+    int ret;
+    int fd;
+
+#ifdef LIBXML_FTP_ENABLED
+    if (xmlIOFTPMatch(filename)) {
+        buf->context = xmlIOFTPOpen(filename);
+
+        if (buf->context != NULL) {
+            buf->readcallback = xmlIOFTPRead;
+            buf->closecallback = xmlIOFTPClose;
+            return(XML_ERR_OK);
+        }
     }
-    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
-    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
-    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
-    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
-    xmlOutputCallbackInitialized = 1;
-    return(xmlOutputCallbackNr++);
-}
-#endif /* LIBXML_OUTPUT_ENABLED */
-
-/**
- * xmlRegisterDefaultInputCallbacks:
- *
- * Registers the default compiled-in I/O handlers.
- */
-void
-xmlRegisterDefaultInputCallbacks(void) {
-    if (xmlInputCallbackInitialized)
-	return;
-
-    xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
-	                      xmlFileRead, xmlFileClose);
-#ifdef LIBXML_ZLIB_ENABLED
-    xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
-	                      xmlGzfileRead, xmlGzfileClose);
-#endif /* LIBXML_ZLIB_ENABLED */
-#ifdef LIBXML_LZMA_ENABLED
-    xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
-	                      xmlXzfileRead, xmlXzfileClose);
-#endif /* LIBXML_LZMA_ENABLED */
+#endif /* LIBXML_FTP_ENABLED */
 
 #ifdef LIBXML_HTTP_ENABLED
-    xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
-	                      xmlIOHTTPRead, xmlIOHTTPClose);
+    if (xmlIOHTTPMatch(filename)) {
+        buf->context = xmlIOHTTPOpen(filename);
+
+        if (buf->context != NULL) {
+            buf->readcallback = xmlIOHTTPRead;
+            buf->closecallback = xmlIOHTTPClose;
+            return(XML_ERR_OK);
+        }
+    }
 #endif /* LIBXML_HTTP_ENABLED */
 
-#ifdef LIBXML_FTP_ENABLED
-    xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
-	                      xmlIOFTPRead, xmlIOFTPClose);
-#endif /* LIBXML_FTP_ENABLED */
-    xmlInputCallbackInitialized = 1;
+    if (!xmlFileMatch(filename))
+        return(XML_IO_ENOENT);
+
+#ifdef LIBXML_LZMA_ENABLED
+    {
+        xzFile xzStream;
+
+        ret = xmlFdOpen(filename, 0, &fd);
+        if (ret != XML_ERR_OK)
+            return(ret);
+
+        xzStream = __libxml2_xzdopen(filename, fd, "rb");
+
+        if (xzStream == NULL) {
+            close(fd);
+        } else {
+            if (__libxml2_xzcompressed(xzStream) > 0) {
+                buf->context = xzStream;
+                buf->readcallback = xmlXzfileRead;
+                buf->closecallback = xmlXzfileClose;
+                buf->compressed = 1;
+
+                return(XML_ERR_OK);
+            }
+
+            xmlXzfileClose(xzStream);
+        }
+    }
+#endif /* LIBXML_LZMA_ENABLED */
+
+#ifdef LIBXML_ZLIB_ENABLED
+    {
+        gzFile gzStream;
+
+        ret = xmlFdOpen(filename, 0, &fd);
+        if (ret != XML_ERR_OK)
+            return(ret);
+
+        gzStream = gzdopen(fd, "rb");
+
+        if (gzStream == NULL) {
+            close(fd);
+        } else {
+            char buff4[4];
+
+            if ((gzread(gzStream, buff4, 4) > 0) &&
+                (gzdirect(gzStream) == 0)) {
+                gzrewind(gzStream);
+
+                buf->context = gzStream;
+                buf->readcallback = xmlGzfileRead;
+                buf->closecallback = xmlGzfileClose;
+                buf->compressed = 1;
+
+                return(XML_ERR_OK);
+            }
+
+            xmlGzfileClose(gzStream);
+        }
+    }
+#endif /* LIBXML_ZLIB_ENABLED */
+
+    ret = xmlFdOpen(filename, 0, &fd);
+    if (ret != XML_ERR_OK)
+        return(ret);
+
+    buf->context = (void *) (ptrdiff_t) fd;
+    buf->readcallback = xmlFdRead;
+    buf->closecallback = xmlFdClose;
+    return(XML_ERR_OK);
 }
 
 #ifdef LIBXML_OUTPUT_ENABLED
 /**
- * xmlRegisterDefaultOutputCallbacks:
+ * xmlOutputDefaultOpen:
+ * @buf:  input buffer to be filled
+ * @filename:  filename or URI
+ * @compression:  compression level or 0
+ * @is_file_uri:  whether filename is a file URI
  *
- * Registers the default compiled-in I/O handlers.
+ * Returns an xmlParserErrors code.
  */
-void
-xmlRegisterDefaultOutputCallbacks (void) {
-    if (xmlOutputCallbackInitialized)
-	return;
+static int
+xmlOutputDefaultOpen(xmlOutputBufferPtr buf, const char *filename,
+                     int compression) {
+    int fd;
 
-    xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
-	                      xmlFileWrite, xmlFileClose);
+    (void) compression;
 
-#ifdef LIBXML_HTTP_ENABLED
-    xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
-	                       xmlIOHTTPWrite, xmlIOHTTPClosePut);
-#endif
+    if (!strcmp(filename, "-")) {
+        fd = dup(STDOUT_FILENO);
 
-/*********************************
- No way a-priori to distinguish between gzipped files from
- uncompressed ones except opening if existing then closing
- and saving with same compression ratio ... a pain.
+        if (fd < 0)
+            return(xmlIOErr(0, "dup()"));
+    } else {
+        int ret;
+
+        ret = xmlFdOpen(filename, /* write */ 1, &fd);
+        if (ret != XML_ERR_OK)
+            return(ret);
+    }
 
 #ifdef LIBXML_ZLIB_ENABLED
-    xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
-	                       xmlGzfileWrite, xmlGzfileClose);
-#endif
+    if ((compression > 0) && (compression <= 9)) {
+        gzFile gzStream;
+        char mode[15];
 
- Nor FTP PUT ....
-#ifdef LIBXML_FTP_ENABLED
-    xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
-	                       xmlIOFTPWrite, xmlIOFTPClose);
-#endif
- **********************************/
-    xmlOutputCallbackInitialized = 1;
-}
+        snprintf(mode, sizeof(mode), "wb%d", compression);
+        gzStream = gzdopen(fd, mode);
 
-#ifdef LIBXML_HTTP_ENABLED
-/**
- * xmlRegisterHTTPPostCallbacks:
- *
- * By default, libxml submits HTTP output requests using the "PUT" method.
- * Calling this method changes the HTTP output method to use the "POST"
- * method instead.
- *
- */
-void
-xmlRegisterHTTPPostCallbacks( void ) {
+        if (gzStream == NULL) {
+            close(fd);
+            return(xmlIOErr(XML_IO_UNKNOWN, "gzdopen()"));
+        }
 
-    /*  Register defaults if not done previously  */
+        buf->context = gzStream;
+        buf->writecallback = xmlGzfileWrite;
+        buf->closecallback = xmlGzfileClose;
 
-    if ( xmlOutputCallbackInitialized == 0 )
-	xmlRegisterDefaultOutputCallbacks( );
+        return(XML_ERR_OK);
+    }
+#endif /* LIBXML_ZLIB_ENABLED */
 
-    xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
-	                       xmlIOHTTPWrite, xmlIOHTTPClosePost);
-    return;
+    buf->context = (void *) (ptrdiff_t) fd;
+    buf->writecallback = xmlFdWrite;
+    buf->closecallback = xmlFdClose;
+    return(XML_ERR_OK);
 }
 #endif
-#endif /* LIBXML_OUTPUT_ENABLED */
 
 /**
  * xmlAllocParserInputBuffer:
@@ -2403,22 +1508,36 @@
  * flushes and close the output I/O channel
  * and free up all the associated resources
  *
- * Returns the number of byte written or -1 in case of error.
+ * Returns the number of byte written or a negative xmlParserErrors
+ * code in case of error.
  */
 int
 xmlOutputBufferClose(xmlOutputBufferPtr out)
 {
-    int written;
-    int err_rc = 0;
+    int ret;
 
     if (out == NULL)
         return (-1);
+
     if (out->writecallback != NULL)
         xmlOutputBufferFlush(out);
+
     if (out->closecallback != NULL) {
-        err_rc = out->closecallback(out->context);
+        int code = out->closecallback(out->context);
+
+        if ((code != XML_ERR_OK) && (out->error == XML_ERR_OK)) {
+            if (code < 0)
+                out->error = XML_IO_UNKNOWN;
+            else
+                out->error = code;
+        }
     }
-    written = out->written;
+
+    if (out->error != XML_ERR_OK)
+        ret = -out->error;
+    else
+        ret = out->written;
+
     if (out->conv) {
         xmlBufFree(out->conv);
         out->conv = NULL;
@@ -2431,81 +1550,77 @@
         out->buffer = NULL;
     }
 
-    if (out->error)
-        err_rc = -1;
     xmlFree(out);
-    return ((err_rc == 0) ? written : err_rc);
+
+    return(ret);
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
 
-xmlParserInputBufferPtr
-__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
-    xmlParserInputBufferPtr ret;
-    int i = 0;
-    void *context = NULL;
+/**
+ * xmlParserInputBufferCreateFilenameInt:
+ * @URI:  the filename or URI
+ * @enc:  encoding enum (deprecated)
+ * @out:  pointer to resulting input buffer
+ *
+ * Returns an xmlParserErrors code.
+ */
+static int
+xmlParserInputBufferCreateFilenameInt(const char *URI, xmlCharEncoding enc,
+                                      xmlParserInputBufferPtr *out) {
+    xmlParserInputBufferPtr buf;
+    int ret;
+    int i;
 
-    if (xmlInputCallbackInitialized == 0)
-	xmlRegisterDefaultInputCallbacks();
+    *out = NULL;
+    if (URI == NULL)
+        return(XML_ERR_ARGUMENT);
 
-    if (URI == NULL) return(NULL);
+    /*
+     * Allocate the Input buffer front-end.
+     */
+    buf = xmlAllocParserInputBuffer(enc);
+    if (buf == NULL)
+        return(XML_ERR_NO_MEMORY);
 
     /*
      * Try to find one of the input accept method accepting that scheme
      * Go in reverse to give precedence to user defined handlers.
      */
-    if (context == NULL) {
-	for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
-	    if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
-		(xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
-		context = xmlInputCallbackTable[i].opencallback(URI);
-		if (context != NULL) {
-		    break;
-		}
-	    }
-	}
+    ret = XML_IO_ENOENT;
+    for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
+        xmlInputCallback *cb = &xmlInputCallbackTable[i];
+
+        if (cb->matchcallback == xmlIODefaultMatch) {
+            ret = xmlInputDefaultOpen(buf, URI);
+
+            if ((ret == XML_ERR_OK) || (ret != XML_IO_ENOENT))
+                break;
+        } else if ((cb->matchcallback != NULL) &&
+                   (cb->matchcallback(URI) != 0)) {
+            buf->context = cb->opencallback(URI);
+            if (buf->context != NULL) {
+                buf->readcallback = cb->readcallback;
+                buf->closecallback = cb->closecallback;
+                ret = XML_ERR_OK;
+                break;
+            }
+        }
     }
-    if (context == NULL) {
-	return(NULL);
+    if (ret != XML_ERR_OK) {
+        xmlFreeParserInputBuffer(buf);
+        *out = NULL;
+	return(ret);
     }
 
-    /*
-     * Allocate the Input buffer front-end.
-     */
-    ret = xmlAllocParserInputBuffer(enc);
-    if (ret != NULL) {
-	ret->context = context;
-	ret->readcallback = xmlInputCallbackTable[i].readcallback;
-	ret->closecallback = xmlInputCallbackTable[i].closecallback;
-#ifdef LIBXML_ZLIB_ENABLED
-	if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
-		(strcmp(URI, "-") != 0)) {
-#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
-            ret->compressed = !gzdirect(context);
-#else
-	    if (((z_stream *)context)->avail_in > 4) {
-	        char *cptr, buff4[4];
-		cptr = (char *) ((z_stream *)context)->next_in;
-		if (gzread(context, buff4, 4) == 4) {
-		    if (strncmp(buff4, cptr, 4) == 0)
-		        ret->compressed = 0;
-		    else
-		        ret->compressed = 1;
-		    gzrewind(context);
-		}
-	    }
-#endif
-	}
-#endif
-#ifdef LIBXML_LZMA_ENABLED
-	if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
-		(strcmp(URI, "-") != 0)) {
-            ret->compressed = __libxml2_xzcompressed(context);
-	}
-#endif
-    }
-    else
-      xmlInputCallbackTable[i].closecallback (context);
+    *out = buf;
+    return(ret);
+}
 
+xmlParserInputBufferPtr
+__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    xmlParserInputBufferCreateFilenameInt(URI, enc, &ret);
     return(ret);
 }
 
@@ -2515,7 +1630,6 @@
  * @enc:  the charset encoding if known
  *
  * Create a buffered parser input for the progressive parsing of a file
- * If filename is "-' then we use stdin as the input.
  * Automatic support for ZLIB/Compress compressed document is provided
  * by default if found at compile-time.
  * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
@@ -2524,135 +1638,102 @@
  */
 xmlParserInputBufferPtr
 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
-    if ((xmlParserInputBufferCreateFilenameValue)) {
-		return xmlParserInputBufferCreateFilenameValue(URI, enc);
-	}
-	return __xmlParserInputBufferCreateFilename(URI, enc);
+    if (xmlParserInputBufferCreateFilenameValue != NULL)
+        return(xmlParserInputBufferCreateFilenameValue(URI, enc));
+
+    return(__xmlParserInputBufferCreateFilename(URI, enc));
+}
+
+/**
+ * xmlParserInputBufferCreateFilenameSafe:
+ * @URI:  the filename or URI
+ * @enc:  encoding enum (deprecated)
+ * @out:  pointer to resulting input buffer
+ *
+ * Returns an xmlParserErrors code.
+ */
+int
+xmlParserInputBufferCreateFilenameSafe(const char *URI, xmlCharEncoding enc,
+                                       xmlParserInputBufferPtr *out) {
+    if (xmlParserInputBufferCreateFilenameValue != NULL) {
+        *out = xmlParserInputBufferCreateFilenameValue(URI, enc);
+
+        if (*out == NULL)
+            return(XML_IO_ENOENT);
+        return(XML_ERR_OK);
+    }
+
+    return(xmlParserInputBufferCreateFilenameInt(URI, enc, out));
 }
 
 #ifdef LIBXML_OUTPUT_ENABLED
 xmlOutputBufferPtr
 __xmlOutputBufferCreateFilename(const char *URI,
                               xmlCharEncodingHandlerPtr encoder,
-                              int compression ATTRIBUTE_UNUSED) {
+                              int compression) {
     xmlOutputBufferPtr ret;
     xmlURIPtr puri;
     int i = 0;
-    void *context = NULL;
     char *unescaped = NULL;
-#ifdef LIBXML_ZLIB_ENABLED
-    int is_file_uri = 1;
-#endif
 
-    if (xmlOutputCallbackInitialized == 0)
-	xmlRegisterDefaultOutputCallbacks();
-
-    if (URI == NULL) return(NULL);
+    if (URI == NULL)
+        return(NULL);
 
     puri = xmlParseURI(URI);
     if (puri != NULL) {
-#ifdef LIBXML_ZLIB_ENABLED
-        if ((puri->scheme != NULL) &&
-	    (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
-	    is_file_uri = 0;
-#endif
-	/*
-	 * try to limit the damages of the URI unescaping code.
-	 */
-	if ((puri->scheme == NULL) ||
-	    (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
-	    unescaped = xmlURIUnescapeString(URI, 0, NULL);
-	xmlFreeURI(puri);
-    }
-
-    /*
-     * Try to find one of the output accept method accepting that scheme
-     * Go in reverse to give precedence to user defined handlers.
-     * try with an unescaped version of the URI
-     */
-    if (unescaped != NULL) {
-#ifdef LIBXML_ZLIB_ENABLED
-	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
-	    context = xmlGzfileOpenW(unescaped, compression);
-	    if (context != NULL) {
-		ret = xmlAllocOutputBufferInternal(encoder);
-		if (ret != NULL) {
-		    ret->context = context;
-		    ret->writecallback = xmlGzfileWrite;
-		    ret->closecallback = xmlGzfileClose;
-		}
-		xmlFree(unescaped);
-		return(ret);
-	    }
-	}
-#endif
-	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
-	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
-		(xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
-#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
-		/*  Need to pass compression parameter into HTTP open calls  */
-		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
-		    context = xmlIOHTTPOpenW(unescaped, compression);
-		else
-#endif
-		    context = xmlOutputCallbackTable[i].opencallback(unescaped);
-		if (context != NULL)
-		    break;
-	    }
-	}
-	xmlFree(unescaped);
-    }
-
-    /*
-     * If this failed try with a non-escaped URI this may be a strange
-     * filename
-     */
-    if (context == NULL) {
-#ifdef LIBXML_ZLIB_ENABLED
-	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
-	    context = xmlGzfileOpenW(URI, compression);
-	    if (context != NULL) {
-		ret = xmlAllocOutputBufferInternal(encoder);
-		if (ret != NULL) {
-		    ret->context = context;
-		    ret->writecallback = xmlGzfileWrite;
-		    ret->closecallback = xmlGzfileClose;
-		}
-		else
-		    xmlGzfileClose(context);
-		return(ret);
-	    }
-	}
-#endif
-	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
-	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
-		(xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
-#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
-		/*  Need to pass compression parameter into HTTP open calls  */
-		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
-		    context = xmlIOHTTPOpenW(URI, compression);
-		else
-#endif
-		    context = xmlOutputCallbackTable[i].opencallback(URI);
-		if (context != NULL)
-		    break;
-	    }
-	}
-    }
-
-    if (context == NULL) {
-	return(NULL);
+        /*
+         * try to limit the damages of the URI unescaping code.
+         */
+        if (puri->scheme == NULL) {
+            unescaped = xmlURIUnescapeString(URI, 0, NULL);
+             if (unescaped == NULL) {
+                 xmlFreeURI(puri);
+                 return(NULL);
+             }
+             URI = unescaped;
+        }
+        xmlFreeURI(puri);
     }
 
     /*
      * Allocate the Output buffer front-end.
      */
     ret = xmlAllocOutputBufferInternal(encoder);
-    if (ret != NULL) {
-	ret->context = context;
-	ret->writecallback = xmlOutputCallbackTable[i].writecallback;
-	ret->closecallback = xmlOutputCallbackTable[i].closecallback;
+    if (ret == NULL) {
+        xmlFree(unescaped);
+        return(NULL);
     }
+
+    /*
+     * Try to find one of the output accept method accepting that scheme
+     * Go in reverse to give precedence to user defined handlers.
+     */
+    for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
+        xmlOutputCallback *cb = &xmlOutputCallbackTable[i];
+        int code;
+
+        if (cb->matchcallback == xmlIODefaultMatch) {
+            code = xmlOutputDefaultOpen(ret, URI, compression);
+            /* TODO: Handle other errors */
+            if (code == XML_ERR_OK)
+                break;
+        } else if ((cb->matchcallback != NULL) &&
+                   (cb->matchcallback(URI) != 0)) {
+            ret->context = cb->opencallback(URI);
+            if (ret->context != NULL) {
+                ret->writecallback = cb->writecallback;
+                ret->closecallback = cb->closecallback;
+                break;
+            }
+        }
+    }
+
+    if (ret->context == NULL) {
+        xmlOutputBufferClose(ret);
+	ret = NULL;
+    }
+
+    xmlFree(unescaped);
     return(ret);
 }
 
@@ -2700,16 +1781,13 @@
 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
     xmlParserInputBufferPtr ret;
 
-    if (xmlInputCallbackInitialized == 0)
-	xmlRegisterDefaultInputCallbacks();
-
     if (file == NULL) return(NULL);
 
     ret = xmlAllocParserInputBuffer(enc);
     if (ret != NULL) {
         ret->context = file;
 	ret->readcallback = xmlFileRead;
-	ret->closecallback = xmlFileFlush;
+	ret->closecallback = NULL;
     }
 
     return(ret);
@@ -2730,9 +1808,6 @@
 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
     xmlOutputBufferPtr ret;
 
-    if (xmlOutputCallbackInitialized == 0)
-	xmlRegisterDefaultOutputCallbacks();
-
     if (file == NULL) return(NULL);
 
     ret = xmlAllocOutputBufferInternal(encoder);
@@ -2833,7 +1908,8 @@
 }
 
 typedef struct {
-    const char *mem;
+    char *mem;
+    const char *cur;
     size_t size;
 } xmlMemIOCtxt;
 
@@ -2844,8 +1920,8 @@
     if ((size_t) size > ctxt->size)
         size = ctxt->size;
 
-    memcpy(buf, ctxt->mem, size);
-    ctxt->mem += size;
+    memcpy(buf, ctxt->cur, size);
+    ctxt->cur += size;
     ctxt->size -= size;
 
     return size;
@@ -2853,43 +1929,48 @@
 
 static int
 xmlMemClose(void *vctxt) {
-    xmlFree(vctxt);
+    xmlMemIOCtxt *ctxt = vctxt;
+
+    if (ctxt->mem != NULL)
+        xmlFree(ctxt->mem);
+    xmlFree(ctxt);
     return(0);
 }
 
-/**
- * xmlParserInputBufferCreateMem:
- * @mem:  the memory input
- * @size:  the length of the memory block
- * @enc:  the charset encoding if known (deprecated)
- *
- * Create a buffered parser input for the progressive parsing for the input
- * from a memory area.
- *
- * The encoding argument is deprecated and should be set to
- * XML_CHAR_ENCODING_NONE. The encoding can be changed with
- * xmlSwitchEncoding or xmlSwitchEncodingName later on.
- *
- * Returns the new parser input or NULL
- */
 xmlParserInputBufferPtr
-xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
+xmlNewInputBufferMemory(const void *mem, size_t size, int flags,
+                        xmlCharEncoding enc) {
     xmlParserInputBufferPtr ret;
     xmlMemIOCtxt *ctxt;
+    char *copy = NULL;
 
-    if (size < 0) return(NULL);
-    if (mem == NULL) return(NULL);
+    if ((flags & XML_INPUT_BUF_STATIC) == 0) {
+        if (size + 1 == 0)
+            return(NULL);
+        copy = xmlMalloc(size + 1);
+        if (copy == NULL)
+            return(NULL);
+        memcpy(copy, mem, size);
+        copy[size] = 0;
+
+        mem = copy;
+    }
 
     ret = xmlAllocParserInputBuffer(enc);
-    if (ret == NULL)
+    if (ret == NULL) {
+        xmlFree(copy);
         return(NULL);
+    }
 
     ctxt = xmlMalloc(sizeof(*ctxt));
     if (ctxt == NULL) {
         xmlFreeParserInputBuffer(ret);
+        xmlFree(copy);
         return(NULL);
     }
-    ctxt->mem = mem;
+
+    ctxt->mem = copy;
+    ctxt->cur = mem;
     ctxt->size = size;
 
     ret->context = ctxt;
@@ -2900,29 +1981,67 @@
 }
 
 /**
+ * xmlParserInputBufferCreateMem:
+ * @mem:  the memory input
+ * @size:  the length of the memory block
+ * @enc:  the charset encoding if known (deprecated)
+ *
+ * Create a parser input buffer for parsing from a memory area.
+ *
+ * This function makes a copy of the whole input buffer. If you are sure
+ * that the contents of the buffer will remain valid until the document
+ * was parsed, you can avoid the copy by using
+ * xmlParserInputBufferCreateStatic.
+ *
+ * The encoding argument is deprecated and should be set to
+ * XML_CHAR_ENCODING_NONE. The encoding can be changed with
+ * xmlSwitchEncoding or xmlSwitchEncodingName later on.
+ *
+ * Returns the new parser input or NULL in case of error.
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
+    if ((mem == NULL) || (size < 0))
+        return(NULL);
+
+    return(xmlNewInputBufferMemory(mem, size, 0, enc));
+}
+
+/**
  * xmlParserInputBufferCreateStatic:
  * @mem:  the memory input
  * @size:  the length of the memory block
  * @enc:  the charset encoding if known
  *
- * DEPRECATED: Use xmlParserInputBufferCreateMem.
+ * Create a parser input buffer for parsing from a memory area.
  *
- * Returns the new parser input or NULL
+ * This functions assumes that the contents of the input buffer remain
+ * valid until the document was parsed. Use xmlParserInputBufferCreateMem
+ * otherwise.
+ *
+ * The encoding argument is deprecated and should be set to
+ * XML_CHAR_ENCODING_NONE. The encoding can be changed with
+ * xmlSwitchEncoding or xmlSwitchEncodingName later on.
+ *
+ * Returns the new parser input or NULL in case of error.
  */
 xmlParserInputBufferPtr
 xmlParserInputBufferCreateStatic(const char *mem, int size,
                                  xmlCharEncoding enc) {
-    return(xmlParserInputBufferCreateMem(mem, size, enc));
+    if ((mem == NULL) || (size < 0))
+        return(NULL);
+
+    return(xmlNewInputBufferMemory(mem, size, XML_INPUT_BUF_STATIC, enc));
 }
 
 typedef struct {
-    const xmlChar *str;
+    const char *str;
 } xmlStringIOCtxt;
 
 static int
 xmlStringRead(void *vctxt, char *buf, int size) {
     xmlStringIOCtxt *ctxt = vctxt;
-    const xmlChar *zero;
+    const char *zero;
     size_t len;
 
     zero = memchr(ctxt->str, 0, size);
@@ -2940,21 +2059,14 @@
     return(0);
 }
 
-/**
- * xmlParserInputBufferCreateString:
- * @str:  a null-terminated string
- *
- * Create a buffered parser input for the progressive parsing for the input
- * from a null-terminated C string.
- *
- * Returns the new parser input or NULL
- */
 xmlParserInputBufferPtr
-xmlParserInputBufferCreateString(const xmlChar *str) {
+xmlNewInputBufferString(const char *str, int flags) {
     xmlParserInputBufferPtr ret;
     xmlStringIOCtxt *ctxt;
 
-    if (str == NULL) return(NULL);
+    if ((flags & XML_INPUT_BUF_STATIC) == 0)
+        return(xmlNewInputBufferMemory(str, strlen(str), flags,
+                                       XML_CHAR_ENCODING_NONE));
 
     ret = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
     if (ret == NULL)
@@ -2965,6 +2077,7 @@
         xmlFreeParserInputBuffer(ret);
         return(NULL);
     }
+
     ctxt->str = str;
 
     ret->context = ctxt;
@@ -3224,7 +2337,10 @@
 	if (res <= 0)
 	    in->readcallback = endOfInput;
         if (res < 0) {
-            in->error = XML_IO_UNKNOWN;
+            if (res == -1)
+                in->error = XML_IO_UNKNOWN;
+            else
+                in->error = -res;
             return(-1);
         }
 
@@ -3315,8 +2431,10 @@
                 }
 	    }
 	    ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
-	    if (ret != 0)
+	    if (ret != 0) {
+                out->error = XML_ERR_NO_MEMORY;
 	        return(-1);
+            }
 
 	    if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
 		goto done;
@@ -3675,9 +2793,6 @@
     char dir[1024];
     char *cur;
 
-    if (xmlInputCallbackInitialized == 0)
-	xmlRegisterDefaultInputCallbacks();
-
     if (filename == NULL) return(NULL);
 
 #if defined(_WIN32)
@@ -3707,323 +2822,200 @@
 #undef IS_XMLPGD_SEP
 }
 
-/****************************************************************
- *								*
- *		External entities loading			*
- *								*
- ****************************************************************/
-
 /**
- * xmlCheckHTTPInput:
- * @ctxt: an XML parser context
- * @ret: an XML parser input
+ * xmlNoNetExists:
+ * @filename:  the path to check
  *
- * Check an input in case it was created from an HTTP stream, in that
- * case it will handle encoding and update of the base URL in case of
- * redirection. It also checks for HTTP errors in which case the input
- * is cleanly freed up and an appropriate error is raised in context
+ * DEPRECATED: Internal function, don't use.
  *
- * Returns the input or NULL in case of HTTP error.
+ * Like xmlCheckFilename but handles file URIs.
  */
-xmlParserInputPtr
-xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
-    /* Avoid unused variable warning if features are disabled. */
-    (void) ctxt;
+int
+xmlNoNetExists(const char *filename) {
+    char *fromUri;
+    int ret;
 
-#ifdef LIBXML_HTTP_ENABLED
-    if ((ret != NULL) && (ret->buf != NULL) &&
-        (ret->buf->readcallback == xmlIOHTTPRead) &&
-        (ret->buf->context != NULL)) {
-        const char *encoding;
-        const char *redir;
-        const char *mime;
-        int code;
-
-        code = xmlNanoHTTPReturnCode(ret->buf->context);
-        if (code >= 400) {
-            /* fatal error */
-	    if (ret->filename != NULL)
-                xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
-                             (const char *) ret->filename);
-	    else
-                xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
-            xmlFreeInputStream(ret);
-            ret = NULL;
-        } else {
-
-            mime = xmlNanoHTTPMimeType(ret->buf->context);
-            if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
-                (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
-                encoding = xmlNanoHTTPEncoding(ret->buf->context);
-                if (encoding != NULL)
-                    xmlSwitchEncodingName(ctxt, encoding);
-#if 0
-            } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
-#endif
-            }
-            redir = xmlNanoHTTPRedir(ret->buf->context);
-            if (redir != NULL) {
-                if (ret->filename != NULL)
-                    xmlFree((xmlChar *) ret->filename);
-                if (ret->directory != NULL) {
-                    xmlFree((xmlChar *) ret->directory);
-                    ret->directory = NULL;
-                }
-                ret->filename =
-                    (char *) xmlStrdup((const xmlChar *) redir);
-            }
-        }
-    }
-#endif
-    return(ret);
-}
-
-static int xmlNoNetExists(const char *URL) {
-    const char *path;
-
-    if (URL == NULL)
+    if (filename == NULL)
 	return(0);
 
-    if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
-#if defined (_WIN32)
-	path = &URL[17];
-#else
-	path = &URL[16];
-#endif
-    else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
-#if defined (_WIN32)
-	path = &URL[8];
-#else
-	path = &URL[7];
-#endif
-    } else
-	path = URL;
+    if (xmlConvertUriToPath(filename, &fromUri) < 0)
+        return(0);
 
-    return xmlCheckFilename(path);
-}
+    if (fromUri != NULL)
+        filename = fromUri;
 
-#ifdef LIBXML_CATALOG_ENABLED
+    ret =  xmlCheckFilename(filename);
 
-/**
- * xmlResolveResourceFromCatalog:
- * @URL:  the URL for the entity to load
- * @ID:  the System ID for the entity to load
- * @ctxt:  the context in which the entity is called or NULL
- *
- * Resolves the URL and ID against the appropriate catalog.
- * This function is used by xmlDefaultExternalEntityLoader and
- * xmlNoNetExternalEntityLoader.
- *
- * Returns a new allocated URL, or NULL.
- */
-static xmlChar *
-xmlResolveResourceFromCatalog(const char *URL, const char *ID,
-                              xmlParserCtxtPtr ctxt) {
-    xmlChar *resource = NULL;
-    xmlCatalogAllow pref;
-
-    /*
-     * If the resource doesn't exists as a file,
-     * try to load it from the resource pointed in the catalogs
-     */
-    pref = xmlCatalogGetDefaults();
-
-    if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
-	/*
-	 * Do a local lookup
-	 */
-	if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
-	    ((pref == XML_CATA_ALLOW_ALL) ||
-	     (pref == XML_CATA_ALLOW_DOCUMENT))) {
-	    resource = xmlCatalogLocalResolve(ctxt->catalogs,
-					      (const xmlChar *)ID,
-					      (const xmlChar *)URL);
-        }
-	/*
-	 * Try a global lookup
-	 */
-	if ((resource == NULL) &&
-	    ((pref == XML_CATA_ALLOW_ALL) ||
-	     (pref == XML_CATA_ALLOW_GLOBAL))) {
-	    resource = xmlCatalogResolve((const xmlChar *)ID,
-					 (const xmlChar *)URL);
-	}
-	if ((resource == NULL) && (URL != NULL))
-	    resource = xmlStrdup((const xmlChar *) URL);
-
-	/*
-	 * TODO: do an URI lookup on the reference
-	 */
-	if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
-	    xmlChar *tmp = NULL;
-
-	    if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
-		((pref == XML_CATA_ALLOW_ALL) ||
-		 (pref == XML_CATA_ALLOW_DOCUMENT))) {
-		tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
-	    }
-	    if ((tmp == NULL) &&
-		((pref == XML_CATA_ALLOW_ALL) ||
-	         (pref == XML_CATA_ALLOW_GLOBAL))) {
-		tmp = xmlCatalogResolveURI(resource);
-	    }
-
-	    if (tmp != NULL) {
-		xmlFree(resource);
-		resource = tmp;
-	    }
-	}
-    }
-
-    return resource;
-}
-
-#endif
-
-/**
- * xmlDefaultExternalEntityLoader:
- * @URL:  the URL for the entity to load
- * @ID:  the System ID for the entity to load
- * @ctxt:  the context in which the entity is called or NULL
- *
- * By default we don't load external entities, yet.
- *
- * Returns a new allocated xmlParserInputPtr, or NULL.
- */
-static xmlParserInputPtr
-xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
-                               xmlParserCtxtPtr ctxt)
-{
-    xmlParserInputPtr ret = NULL;
-    xmlChar *resource = NULL;
-
-    if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
-        int options = ctxt->options;
-
-	ctxt->options -= XML_PARSE_NONET;
-        ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
-	ctxt->options = options;
-	return(ret);
-    }
-#ifdef LIBXML_CATALOG_ENABLED
-    resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
-#endif
-
-    if (resource == NULL)
-        resource = (xmlChar *) URL;
-
-    if (resource == NULL) {
-        if (ID == NULL)
-            ID = "NULL";
-        if (ctxt != NULL)
-            xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
-        return (NULL);
-    }
-    ret = xmlNewInputFromFile(ctxt, (const char *) resource);
-    if ((resource != NULL) && (resource != (xmlChar *) URL))
-        xmlFree(resource);
-    return (ret);
-}
-
-static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
-       xmlDefaultExternalEntityLoader;
-
-/**
- * xmlSetExternalEntityLoader:
- * @f:  the new entity resolver function
- *
- * Changes the defaultexternal entity resolver function for the application
- */
-void
-xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
-    xmlCurrentExternalEntityLoader = f;
-}
-
-/**
- * xmlGetExternalEntityLoader:
- *
- * Get the default external entity resolver function for the application
- *
- * Returns the xmlExternalEntityLoader function pointer
- */
-xmlExternalEntityLoader
-xmlGetExternalEntityLoader(void) {
-    return(xmlCurrentExternalEntityLoader);
-}
-
-/**
- * xmlLoadExternalEntity:
- * @URL:  the URL for the entity to load
- * @ID:  the Public ID for the entity to load
- * @ctxt:  the context in which the entity is called or NULL
- *
- * Load an external entity, note that the use of this function for
- * unparsed entities may generate problems
- *
- * Returns the xmlParserInputPtr or NULL
- */
-xmlParserInputPtr
-xmlLoadExternalEntity(const char *URL, const char *ID,
-                      xmlParserCtxtPtr ctxt) {
-    if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
-	char *canonicFilename;
-	xmlParserInputPtr ret;
-
-	canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
-	if (canonicFilename == NULL) {
-            xmlErrMemory(ctxt, "building canonical path\n");
-	    return(NULL);
-	}
-
-	ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
-	xmlFree(canonicFilename);
-	return(ret);
-    }
-    return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
+    xmlFree(fromUri);
+    return(ret);
 }
 
 /************************************************************************
  *									*
- *		Disabling Network access				*
+ *			Input/output callbacks				*
  *									*
  ************************************************************************/
 
 /**
- * xmlNoNetExternalEntityLoader:
- * @URL:  the URL for the entity to load
- * @ID:  the System ID for the entity to load
- * @ctxt:  the context in which the entity is called or NULL
+ * xmlInitIOCallbacks:
  *
- * A specific entity loader disabling network accesses, though still
- * allowing local catalog accesses for resolution.
- *
- * Returns a new allocated xmlParserInputPtr, or NULL.
+ * Initialize callback tables.
  */
-xmlParserInputPtr
-xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
-                             xmlParserCtxtPtr ctxt) {
-    xmlParserInputPtr input = NULL;
-    xmlChar *resource = NULL;
+void
+xmlInitIOCallbacks(void)
+{
+    xmlInputCallbackNr = 1;
+    xmlInputCallbackTable[0].matchcallback = xmlIODefaultMatch;
 
-#ifdef LIBXML_CATALOG_ENABLED
-    resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
+#ifdef LIBXML_OUTPUT_ENABLED
+    xmlOutputCallbackNr = 1;
+    xmlOutputCallbackTable[0].matchcallback = xmlIODefaultMatch;
 #endif
-
-    if (resource == NULL)
-	resource = (xmlChar *) URL;
-
-    if (resource != NULL) {
-        if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
-            (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
-            xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
-	    if (resource != (xmlChar *) URL)
-		xmlFree(resource);
-	    return(NULL);
-	}
-    }
-    input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
-    if (resource != (xmlChar *) URL)
-	xmlFree(resource);
-    return(input);
 }
 
+/**
+ * xmlRegisterInputCallbacks:
+ * @matchFunc:  the xmlInputMatchCallback
+ * @openFunc:  the xmlInputOpenCallback
+ * @readFunc:  the xmlInputReadCallback
+ * @closeFunc:  the xmlInputCloseCallback
+ *
+ * Register a new set of I/O callback for handling parser input.
+ *
+ * Returns the registered handler number or -1 in case of error
+ */
+int
+xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
+	xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
+	xmlInputCloseCallback closeFunc) {
+    if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
+	return(-1);
+    }
+    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
+    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
+    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
+    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
+    return(xmlInputCallbackNr++);
+}
+
+/**
+ * xmlRegisterDefaultInputCallbacks:
+ *
+ * Registers the default compiled-in I/O handlers.
+ */
+void
+xmlRegisterDefaultInputCallbacks(void) {
+    xmlRegisterInputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
+}
+
+/**
+ * xmlPopInputCallbacks:
+ *
+ * Clear the top input callback from the input stack. this includes the
+ * compiled-in I/O.
+ *
+ * Returns the number of input callback registered or -1 in case of error.
+ */
+int
+xmlPopInputCallbacks(void)
+{
+    if (xmlInputCallbackNr <= 0)
+        return(-1);
+
+    xmlInputCallbackNr--;
+
+    return(xmlInputCallbackNr);
+}
+
+/**
+ * xmlCleanupInputCallbacks:
+ *
+ * clears the entire input callback table. this includes the
+ * compiled-in I/O.
+ */
+void
+xmlCleanupInputCallbacks(void)
+{
+    xmlInputCallbackNr = 0;
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlRegisterOutputCallbacks:
+ * @matchFunc:  the xmlOutputMatchCallback
+ * @openFunc:  the xmlOutputOpenCallback
+ * @writeFunc:  the xmlOutputWriteCallback
+ * @closeFunc:  the xmlOutputCloseCallback
+ *
+ * Register a new set of I/O callback for handling output.
+ *
+ * Returns the registered handler number or -1 in case of error
+ */
+int
+xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
+	xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
+	xmlOutputCloseCallback closeFunc) {
+    if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
+	return(-1);
+    }
+    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
+    return(xmlOutputCallbackNr++);
+}
+
+/**
+ * xmlRegisterDefaultOutputCallbacks:
+ *
+ * Registers the default compiled-in I/O handlers.
+ */
+void
+xmlRegisterDefaultOutputCallbacks (void) {
+    xmlRegisterOutputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
+}
+
+/**
+ * xmlPopOutputCallbacks:
+ *
+ * Remove the top output callbacks from the output stack. This includes the
+ * compiled-in I/O.
+ *
+ * Returns the number of output callback registered or -1 in case of error.
+ */
+int
+xmlPopOutputCallbacks(void)
+{
+    if (xmlOutputCallbackNr <= 0)
+        return(-1);
+
+    xmlOutputCallbackNr--;
+
+    return(xmlOutputCallbackNr);
+}
+
+/**
+ * xmlCleanupOutputCallbacks:
+ *
+ * clears the entire output callback table. this includes the
+ * compiled-in I/O callbacks.
+ */
+void
+xmlCleanupOutputCallbacks(void)
+{
+    xmlOutputCallbackNr = 0;
+}
+
+#ifdef LIBXML_HTTP_ENABLED
+/**
+ * xmlRegisterHTTPPostCallbacks:
+ *
+ * DEPRECATED: Support for HTTP POST has been removed.
+ */
+void
+xmlRegisterHTTPPostCallbacks(void) {
+    xmlRegisterDefaultOutputCallbacks();
+}
+#endif
+#endif /* LIBXML_OUTPUT_ENABLED */
+
diff --git a/src/xmlmemory.c b/src/xmlmemory.c
index 1e999b1..b515f1c 100644
--- a/src/xmlmemory.c
+++ b/src/xmlmemory.c
@@ -126,7 +126,7 @@
 
 void
 xmlMallocBreakpoint(void) {
-    xmlGenericError(xmlGenericErrorContext,
+    fprintf(stderr,
 	    "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
 }
 
@@ -152,7 +152,7 @@
     TEST_POINT
 
     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 		"xmlMallocLoc : Unsigned overflow\n");
 	return(NULL);
     }
@@ -160,7 +160,7 @@
     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
 
     if (!p) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 		"xmlMallocLoc : Out of free space\n");
 	return(NULL);
     }
@@ -184,7 +184,7 @@
     ret = HDR_2_CLIENT(p);
 
     if (xmlMemTraceBlockAt == ret) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 			"%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
 			(long unsigned)size);
 	xmlMallocBreakpoint();
@@ -217,7 +217,7 @@
     TEST_POINT
 
     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 		"xmlMallocAtomicLoc : Unsigned overflow\n");
 	return(NULL);
     }
@@ -225,7 +225,7 @@
     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
 
     if (!p) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 		"xmlMallocAtomicLoc : Out of free space\n");
 	return(NULL);
     }
@@ -249,7 +249,7 @@
     ret = HDR_2_CLIENT(p);
 
     if (xmlMemTraceBlockAt == ret) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 			"%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
 			(long unsigned)size);
 	xmlMallocBreakpoint();
@@ -315,7 +315,7 @@
     xmlMutexUnlock(&xmlMemMutex);
 
     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 		"xmlReallocLoc : Unsigned overflow\n");
 	return(NULL);
     }
@@ -327,7 +327,7 @@
     }
     p = tmp;
     if (xmlMemTraceBlockAt == ptr) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 			"%p : Realloced(%lu -> %lu) Ok\n",
 			xmlMemTraceBlockAt, (long unsigned)p->mh_size,
 			(long unsigned)size);
@@ -387,13 +387,13 @@
 	return;
 
     if (ptr == (void *) -1) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 	    "trying to free pointer from freed area\n");
         goto error;
     }
 
     if (xmlMemTraceBlockAt == ptr) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 			"%p : Freed()\n", xmlMemTraceBlockAt);
 	xmlMallocBreakpoint();
     }
@@ -425,7 +425,7 @@
     return;
 
 error:
-    xmlGenericError(xmlGenericErrorContext,
+    fprintf(stderr,
 	    "xmlMemFree(%p) error\n", ptr);
     xmlMallocBreakpoint();
     return;
@@ -453,7 +453,7 @@
     TEST_POINT
 
     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 		"xmlMemStrdupLoc : Unsigned overflow\n");
 	return(NULL);
     }
@@ -486,7 +486,7 @@
     TEST_POINT
 
     if (xmlMemTraceBlockAt == s) {
-	xmlGenericError(xmlGenericErrorContext,
+	fprintf(stderr,
 			"%p : Strdup() Ok\n", xmlMemTraceBlockAt);
 	xmlMallocBreakpoint();
     }
@@ -733,7 +733,7 @@
 
 static void debugmem_tag_error(void *p)
 {
-     xmlGenericError(xmlGenericErrorContext,
+     fprintf(stderr,
 	     "Memory tag error occurs :%p \n\t bye\n", p);
 #ifdef MEM_LIST
      if (stderr)
diff --git a/src/xmlreader.c b/src/xmlreader.c
index 7dd6a69..4aaf6fc 100644
--- a/src/xmlreader.c
+++ b/src/xmlreader.c
@@ -41,12 +41,11 @@
 
 #include "private/buf.h"
 #include "private/tree.h"
+#include "private/parser.h"
 #ifdef LIBXML_XINCLUDE_ENABLED
 #include "private/xinclude.h"
 #endif
 
-#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
@@ -62,16 +61,6 @@
   #endif
 #endif
 
-/**
- * TODO:
- *
- * macro to flag unimplemented blocks
- */
-#define TODO								\
-    xmlGenericError(xmlGenericErrorContext,				\
-	    "Unimplemented block at %s:%d\n",				\
-            __FILE__, __LINE__);
-
 #define CHUNK_SIZE 512
 /************************************************************************
  *									*
@@ -203,6 +192,13 @@
 static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
 static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);
 
+static void
+xmlTextReaderErrMemory(xmlTextReaderPtr reader) {
+    xmlCtxtErrMemory(reader->ctxt);
+    reader->mode = XML_TEXTREADER_MODE_ERROR;
+    reader->state = XML_TEXTREADER_ERROR;
+}
+
 /**
  * xmlTextReaderFreeProp:
  * @reader:  the xmlTextReaderPtr used
@@ -482,6 +478,34 @@
  *									*
  ************************************************************************/
 
+static void
+xmlTextReaderStructuredRelay(void *userData, const xmlError *error)
+{
+    xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;
+
+    if (reader->sErrorFunc != NULL) {
+        reader->sErrorFunc(reader->errorFuncArg, error);
+    } else if (reader->errorFunc != NULL) {
+        xmlParserSeverities severity;
+
+        if ((error->domain == XML_FROM_VALID) ||
+            (error->domain == XML_FROM_DTD)) {
+            if (error->level == XML_ERR_WARNING)
+                severity = XML_PARSER_SEVERITY_VALIDITY_WARNING;
+            else
+                severity = XML_PARSER_SEVERITY_VALIDITY_ERROR;
+        } else {
+            if (error->level == XML_ERR_WARNING)
+                severity = XML_PARSER_SEVERITY_WARNING;
+            else
+                severity = XML_PARSER_SEVERITY_ERROR;
+        }
+
+        reader->errorFunc(reader->errorFuncArg, error->message, severity,
+                          reader->ctxt);
+    }
+}
+
 /**
  * xmlTextReaderEntPush:
  * @reader:  the xmlTextReaderPtr used
@@ -501,7 +525,7 @@
         tmp = (xmlNodePtr *) xmlRealloc(reader->entTab,
                                         newSize * sizeof(*tmp));
         if (tmp == NULL) {
-            xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
+            xmlTextReaderErrMemory(reader);
             return (-1);
         }
         reader->entTab = tmp;
@@ -718,11 +742,10 @@
                         break;
 		    }
 		} else if (val < 0) {
-                    xmlGenericError(xmlGenericErrorContext,
-                                    "xmlParserInputBufferRead failed\n");
-		    reader->mode = XML_TEXTREADER_MODE_EOF;
-		    reader->state = oldstate;
-		    return(val);
+                    xmlCtxtErrIO(reader->ctxt, reader->input->error, NULL);
+                    reader->mode = XML_TEXTREADER_MODE_ERROR;
+                    reader->state = XML_TEXTREADER_ERROR;
+                    return(-1);
 		}
 
 	    } else
@@ -804,8 +827,8 @@
  *
  * Push the current node for validation
  */
-static void
-xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
+static int
+xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
     xmlNodePtr node = reader->node;
 
 #ifdef LIBXML_VALID_ENABLED
@@ -819,13 +842,29 @@
 	    xmlChar *qname;
 
 	    qname = xmlStrdup(node->ns->prefix);
+            if (qname == NULL) {
+                xmlTextReaderErrMemory(reader);
+                return(-1);
+            }
 	    qname = xmlStrcat(qname, BAD_CAST ":");
+            if (qname == NULL) {
+                xmlTextReaderErrMemory(reader);
+                return(-1);
+            }
 	    qname = xmlStrcat(qname, node->name);
+            if (qname == NULL) {
+                xmlTextReaderErrMemory(reader);
+                return(-1);
+            }
 	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
 				    reader->ctxt->myDoc, node, qname);
-	    if (qname != NULL)
-		xmlFree(qname);
+	    xmlFree(qname);
 	}
+        /*if (reader->ctxt->errNo == XML_ERR_NO_MEMORY) {
+            reader->mode = XML_TEXTREADER_MODE_ERROR;
+            reader->state = XML_TEXTREADER_ERROR;
+            return(-1);
+        }*/
     }
 #endif /* LIBXML_VALID_ENABLED */
 #ifdef LIBXML_SCHEMAS_ENABLED
@@ -833,7 +872,7 @@
                (reader->rngValidCtxt != NULL)) {
 	int ret;
 
-	if (reader->rngFullNode != NULL) return;
+	if (reader->rngFullNode != NULL) return(0);
 	ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
 	                                    reader->ctxt->myDoc,
 					    node);
@@ -855,6 +894,8 @@
 	    reader->rngValidErrors++;
     }
 #endif
+
+    return(0);
 }
 
 /**
@@ -894,7 +935,7 @@
  *
  * Pop the current node from validation
  */
-static void
+static int
 xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
     xmlNodePtr node = reader->node;
 
@@ -909,13 +950,29 @@
 	    xmlChar *qname;
 
 	    qname = xmlStrdup(node->ns->prefix);
+            if (qname == NULL) {
+                xmlTextReaderErrMemory(reader);
+                return(-1);
+            }
 	    qname = xmlStrcat(qname, BAD_CAST ":");
+            if (qname == NULL) {
+                xmlTextReaderErrMemory(reader);
+                return(-1);
+            }
 	    qname = xmlStrcat(qname, node->name);
+            if (qname == NULL) {
+                xmlTextReaderErrMemory(reader);
+                return(-1);
+            }
 	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
 				    reader->ctxt->myDoc, node, qname);
-	    if (qname != NULL)
-		xmlFree(qname);
+	    xmlFree(qname);
 	}
+        /*if (reader->ctxt->errNo == XML_ERR_NO_MEMORY) {
+            reader->mode = XML_TEXTREADER_MODE_ERROR;
+            reader->state = XML_TEXTREADER_ERROR;
+            return(-1);
+        }*/
     }
 #endif /* LIBXML_VALID_ENABLED */
 #ifdef LIBXML_SCHEMAS_ENABLED
@@ -926,7 +983,7 @@
 	if (reader->rngFullNode != NULL) {
 	    if (node == reader->rngFullNode)
 	        reader->rngFullNode = NULL;
-	    return;
+	    return(0);
 	}
 	ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
 	                                   reader->ctxt->myDoc,
@@ -935,6 +992,8 @@
 	    reader->rngValidErrors++;
     }
 #endif
+
+    return(0);
 }
 
 /**
@@ -945,7 +1004,7 @@
  * entity substitution is not activated. As a result the parser interface
  * must walk through the entity and do the validation calls
  */
-static void
+static int
 xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
     xmlNodePtr oldnode = reader->node;
     xmlNodePtr node = reader->node;
@@ -973,7 +1032,8 @@
 #ifdef LIBXML_REGEXP_ENABLED
 	} else if (node->type == XML_ELEMENT_NODE) {
 	    reader->node = node;
-	    xmlTextReaderValidatePush(reader);
+	    if (xmlTextReaderValidatePush(reader) < 0)
+                return(-1);
 	} else if ((node->type == XML_TEXT_NODE) ||
 		   (node->type == XML_CDATA_SECTION_NODE)) {
             xmlTextReaderValidateCData(reader, node->content,
@@ -988,7 +1048,8 @@
 	    node = node->children;
 	    continue;
 	} else if (node->type == XML_ELEMENT_NODE) {
-	    xmlTextReaderValidatePop(reader);
+	    if (xmlTextReaderValidatePop(reader) < 0)
+                return(-1);
 	}
 skip_children:
 	if (node->next != NULL) {
@@ -1009,7 +1070,8 @@
 		    }
 		}
 		reader->node = node;
-		xmlTextReaderValidatePop(reader);
+		if (xmlTextReaderValidatePop(reader) < 0)
+                    return(-1);
 	    }
 	    if ((node->type == XML_ENTITY_DECL) &&
 		(reader->ent != NULL) && (reader->ent->children == node)) {
@@ -1024,6 +1086,8 @@
 	} while ((node != NULL) && (node != oldnode));
     } while ((node != NULL) && (node != oldnode));
     reader->node = oldnode;
+
+    return(0);
 }
 #endif /* LIBXML_REGEXP_ENABLED */
 
@@ -1066,7 +1130,8 @@
     if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
         return(-1);
     do {
-	if (reader->ctxt->instate == XML_PARSER_EOF) return(1);
+	if (PARSER_STOPPED(reader->ctxt))
+            return(1);
 
         if (xmlTextReaderGetSuccessor(reader->node) != NULL)
 	    return(1);
@@ -1077,6 +1142,7 @@
 	val = xmlTextReaderPushData(reader);
 	if (val < 0){
 	    reader->mode = XML_TEXTREADER_MODE_ERROR;
+            reader->state = XML_TEXTREADER_ERROR;
 	    return(-1);
 	}
     } while(reader->mode != XML_TEXTREADER_MODE_EOF);
@@ -1155,6 +1221,8 @@
         return(xmlTextReaderReadTree(reader));
     if (reader->ctxt == NULL)
 	return(-1);
+    if (reader->state == XML_TEXTREADER_ERROR)
+        return(-1);
 
     if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
 	reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
@@ -1163,11 +1231,11 @@
 	 */
 	do {
 	    val = xmlTextReaderPushData(reader);
-		if (val < 0){
-			reader->mode = XML_TEXTREADER_MODE_ERROR;
-			reader->state = XML_TEXTREADER_ERROR;
-		return(-1);
-		}
+            if (val < 0) {
+                reader->mode = XML_TEXTREADER_MODE_ERROR;
+                reader->state = XML_TEXTREADER_ERROR;
+                return(-1);
+            }
 	} while ((reader->ctxt->node == NULL) &&
 		 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
 		  (reader->state != XML_TEXTREADER_DONE)));
@@ -1175,11 +1243,11 @@
 	    if (reader->ctxt->myDoc != NULL) {
 		reader->node = reader->ctxt->myDoc->children;
 	    }
-	    if (reader->node == NULL){
-			reader->mode = XML_TEXTREADER_MODE_ERROR;
-			reader->state = XML_TEXTREADER_ERROR;
+	    if (reader->node == NULL) {
+                reader->mode = XML_TEXTREADER_MODE_ERROR;
+                reader->state = XML_TEXTREADER_ERROR;
 		return(-1);
-		}
+	    }
 	    reader->state = XML_TEXTREADER_ELEMENT;
 	} else {
 	    if (reader->ctxt->myDoc != NULL) {
@@ -1199,10 +1267,13 @@
 
 get_next_node:
     if (reader->node == NULL) {
-	if (reader->mode == XML_TEXTREADER_MODE_EOF)
+	if (reader->mode == XML_TEXTREADER_MODE_EOF) {
 	    return(0);
-	else
+        } else {
+            reader->mode = XML_TEXTREADER_MODE_ERROR;
+            reader->state = XML_TEXTREADER_ERROR;
 	    return(-1);
+        }
     }
 
     /*
@@ -1224,13 +1295,14 @@
 	   ((reader->ctxt->node == NULL) ||
 	    (reader->ctxt->node == reader->node) ||
 	    (reader->ctxt->node == reader->node->parent)) &&
-	   (reader->ctxt->instate != XML_PARSER_EOF)) {
+	   (reader->ctxt->instate != XML_PARSER_EOF) &&
+	   (PARSER_STOPPED(reader->ctxt) == 0)) {
 	val = xmlTextReaderPushData(reader);
-	if (val < 0){
-		reader->mode = XML_TEXTREADER_MODE_ERROR;
-		reader->state = XML_TEXTREADER_ERROR;
+	if (val < 0) {
+            reader->mode = XML_TEXTREADER_MODE_ERROR;
+            reader->state = XML_TEXTREADER_ERROR;
 	    return(-1);
-	}
+        }
 	if (reader->node == NULL)
 	    goto node_end;
     }
@@ -1260,7 +1332,8 @@
 #ifdef LIBXML_REGEXP_ENABLED
 	if ((reader->validate) &&
 	    (reader->node->type == XML_ELEMENT_NODE))
-	    xmlTextReaderValidatePop(reader);
+	    if (xmlTextReaderValidatePop(reader) < 0)
+                return(-1);
 #endif /* LIBXML_REGEXP_ENABLED */
         if ((reader->preserves > 0) &&
 	    (reader->node->extra & NODE_IS_SPRESERVED))
@@ -1297,8 +1370,11 @@
 	goto node_found;
     }
 #ifdef LIBXML_REGEXP_ENABLED
-    if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) && (reader->node->type == XML_ELEMENT_NODE))
-	xmlTextReaderValidatePop(reader);
+    if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) &&
+        (reader->node->type == XML_ELEMENT_NODE)) {
+        if (xmlTextReaderValidatePop(reader) < 0)
+            return(-1);
+    }
 #endif /* LIBXML_REGEXP_ENABLED */
     if ((reader->preserves > 0) &&
 	(reader->node->extra & NODE_IS_SPRESERVED))
@@ -1310,8 +1386,11 @@
 	if (reader->mode != XML_TEXTREADER_MODE_EOF) {
 	    val = xmlParseChunk(reader->ctxt, "", 0, 1);
 	    reader->state = XML_TEXTREADER_DONE;
-	    if (val != 0)
+	    if (val != 0) {
+                reader->mode = XML_TEXTREADER_MODE_ERROR;
+                reader->state = XML_TEXTREADER_ERROR;
 	        return(-1);
+            }
 	}
 	reader->node = NULL;
 	reader->depth = -1;
@@ -1363,6 +1442,7 @@
      * Handle XInclude if asked for
      */
     if ((reader->xinclude) && (reader->in_xinclude == 0) &&
+        (reader->state != XML_TEXTREADER_BACKTRACK) &&
         (reader->node != NULL) &&
 	(reader->node->type == XML_ELEMENT_NODE) &&
 	(reader->node->ns != NULL) &&
@@ -1370,16 +1450,29 @@
 	 (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) {
 	if (reader->xincctxt == NULL) {
 	    reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
+            if (reader->xincctxt == NULL) {
+                xmlTextReaderErrMemory(reader);
+                return(-1);
+            }
 	    xmlXIncludeSetFlags(reader->xincctxt,
 	                        reader->parserFlags & (~XML_PARSE_NOXINCNODE));
             xmlXIncludeSetStreamingMode(reader->xincctxt, 1);
+            if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL))
+                xmlXIncludeSetErrorHandler(reader->xincctxt,
+                        xmlTextReaderStructuredRelay, reader);
 	}
 	/*
 	 * expand that node and process it
 	 */
 	if (xmlTextReaderExpand(reader) == NULL)
-	    return -1;
-	xmlXIncludeProcessNode(reader->xincctxt, reader->node);
+	    return(-1);
+        if (xmlXIncludeProcessNode(reader->xincctxt, reader->node) < 0) {
+            int err = xmlXIncludeGetLastError(reader->xincctxt);
+
+            if (err == XML_ERR_NO_MEMORY)
+                xmlTextReaderErrMemory(reader);
+            return(-1);
+        }
     }
     if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) {
         reader->in_xinclude++;
@@ -1407,7 +1500,8 @@
     } else if ((reader->node != NULL) &&
 	       (reader->node->type == XML_ENTITY_REF_NODE) &&
 	       (reader->ctxt != NULL) && (reader->validate)) {
-	xmlTextReaderValidateEntity(reader);
+	if (xmlTextReaderValidateEntity(reader) < 0)
+            return(-1);
 #endif /* LIBXML_REGEXP_ENABLED */
     }
     if ((reader->node != NULL) &&
@@ -1424,7 +1518,8 @@
 	if ((node->type == XML_ELEMENT_NODE) &&
             ((reader->state != XML_TEXTREADER_END) &&
 	     (reader->state != XML_TEXTREADER_BACKTRACK))) {
-	    xmlTextReaderValidatePush(reader);
+	    if (xmlTextReaderValidatePush(reader) < 0)
+                return(-1);
 	} else if ((node->type == XML_TEXT_NODE) ||
 		   (node->type == XML_CDATA_SECTION_NODE)) {
             xmlTextReaderValidateCData(reader, node->content,
@@ -1658,7 +1753,7 @@
 	}
 	break;
     case XML_ATTRIBUTE_NODE:
-	TODO
+	/* TODO */
 	break;
     default:
        break;
@@ -1693,7 +1788,6 @@
 
     if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
 	return(0);
-    TODO
     return(0);
 }
 
@@ -1723,7 +1817,6 @@
 
     if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
 	return(0);
-    TODO
     return(0);
 }
 #endif
@@ -1923,11 +2016,8 @@
     if (input == NULL)
 	return(NULL);
     ret = xmlMalloc(sizeof(xmlTextReader));
-    if (ret == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNewTextReader : malloc failed\n");
+    if (ret == NULL)
 	return(NULL);
-    }
     memset(ret, 0, sizeof(xmlTextReader));
     ret->doc = NULL;
     ret->entTab = NULL;
@@ -1937,8 +2027,6 @@
     ret->buffer = xmlBufCreateSize(100);
     if (ret->buffer == NULL) {
         xmlFree(ret);
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNewTextReader : malloc failed\n");
 	return(NULL);
     }
     /* no operation on a reader should require a huge buffer */
@@ -1948,8 +2036,6 @@
     if (ret->sax == NULL) {
 	xmlBufFree(ret->buffer);
 	xmlFree(ret);
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNewTextReader : malloc failed\n");
 	return(NULL);
     }
     xmlSAXVersion(ret->sax, 2);
@@ -1995,8 +2081,6 @@
     }
 
     if (ret->ctxt == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNewTextReader : malloc failed\n");
 	xmlBufFree(ret->buffer);
 	xmlFree(ret->sax);
 	xmlFree(ret);
@@ -2010,7 +2094,6 @@
     /*
      * use the parser dictionary to allocate all elements and attributes names
      */
-    ret->ctxt->docdict = 1;
     ret->dict = ret->ctxt->dict;
 #ifdef LIBXML_XINCLUDE_ENABLED
     ret->xinclude = 0;
@@ -2034,7 +2117,6 @@
 xmlNewTextReaderFilename(const char *URI) {
     xmlParserInputBufferPtr input;
     xmlTextReaderPtr ret;
-    char *directory = NULL;
 
     input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
     if (input == NULL)
@@ -2045,12 +2127,6 @@
 	return(NULL);
     }
     ret->allocs |= XML_TEXTREADER_INPUT;
-    if (ret->ctxt->directory == NULL)
-        directory = xmlParserGetDirectory(URI);
-    if ((ret->ctxt->directory == NULL) && (directory != NULL))
-        ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
-    if (directory != NULL)
-	xmlFree(directory);
     return(ret);
 }
 
@@ -2386,7 +2462,6 @@
 	 *   - by the layer which allocated it.
 	 *   - by the layer to which would have been returned to.
 	 */
-	TODO
 	return(NULL);
     }
     return(ret);
@@ -2752,12 +2827,24 @@
 	if (reader->faketext == NULL) {
 	    reader->faketext = xmlNewDocText(reader->node->doc,
 		                             ns->href);
+            if (reader->faketext == NULL) {
+                xmlTextReaderErrMemory(reader);
+                return(-1);
+            }
 	} else {
             if ((reader->faketext->content != NULL) &&
 	        (reader->faketext->content !=
 		 (xmlChar *) &(reader->faketext->properties)))
 		xmlFree(reader->faketext->content);
-	    reader->faketext->content = xmlStrdup(ns->href);
+            if (ns->href == NULL) {
+                reader->faketext->content = NULL;
+            } else {
+                reader->faketext->content = xmlStrdup(ns->href);
+                if (reader->faketext->content == NULL) {
+                    xmlTextReaderErrMemory(reader);
+                    return(-1);
+                }
+            }
 	}
 	reader->curnode = reader->faketext;
     } else {
@@ -3471,11 +3558,8 @@
 	    else {
 		if (reader->buffer == NULL) {
 		    reader->buffer = xmlBufCreateSize(100);
-                    if (reader->buffer == NULL) {
-                        xmlGenericError(xmlGenericErrorContext,
-                                        "xmlTextReaderSetup : malloc failed\n");
+                    if (reader->buffer == NULL)
                         return (NULL);
-                    }
 		    xmlBufSetAllocationScheme(reader->buffer,
 		                              XML_BUFFER_ALLOC_DOUBLEIT);
                 } else
@@ -3650,18 +3734,21 @@
 		if (ctxt->loadsubset == 0) {
 		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
 			return(-1);
-		    ctxt->loadsubset = XML_DETECT_IDS;
+                    ctxt->options |= XML_PARSE_DTDLOAD;
+		    ctxt->loadsubset |= XML_DETECT_IDS;
 		}
 	    } else {
-		ctxt->loadsubset = 0;
+                ctxt->options &= ~XML_PARSE_DTDLOAD;
+		ctxt->loadsubset &= ~XML_DETECT_IDS;
 	    }
 	    return(0);
         case XML_PARSER_DEFAULTATTRS:
 	    if (value != 0) {
+                ctxt->options |= XML_PARSE_DTDATTR;
 		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
 	    } else {
-		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
-		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
+                ctxt->options &= ~XML_PARSE_DTDATTR;
+		ctxt->loadsubset &= ~XML_COMPLETE_ATTRS;
 	    }
 	    return(0);
         case XML_PARSER_VALIDATE:
@@ -3849,7 +3936,7 @@
 	reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
 					      sizeof(reader->patternTab[0]));
         if (reader->patternTab == NULL) {
-            xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
+            xmlTextReaderErrMemory(reader);
             return (-1);
         }
     }
@@ -3860,7 +3947,7 @@
                                       reader->patternMax *
                                       sizeof(reader->patternTab[0]));
         if (tmp == NULL) {
-            xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
+            xmlTextReaderErrMemory(reader);
 	    reader->patternMax /= 2;
             return (-1);
         }
@@ -3897,80 +3984,6 @@
 }
 
 #ifdef LIBXML_SCHEMAS_ENABLED
-static char *xmlTextReaderBuildMessage(const char *msg, va_list ap) LIBXML_ATTR_FORMAT(1,0);
-
-static void
-xmlTextReaderValidityError(void *ctxt, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
-
-static void
-xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
-
-static void
-xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
-
-static void
-xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
-
-static void
-xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...)
-{
-    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
-
-    char *str;
-
-    va_list ap;
-
-    va_start(ap, msg);
-    str = xmlTextReaderBuildMessage(msg, ap);
-    if (!reader->errorFunc) {
-        xmlTextReaderValidityError(ctx, "%s", str);
-    } else {
-        reader->errorFunc(reader->errorFuncArg, str,
-                          XML_PARSER_SEVERITY_VALIDITY_ERROR,
-                          NULL /* locator */ );
-    }
-    if (str != NULL)
-        xmlFree(str);
-    va_end(ap);
-}
-
-static void
-xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...)
-{
-    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
-
-    char *str;
-
-    va_list ap;
-
-    va_start(ap, msg);
-    str = xmlTextReaderBuildMessage(msg, ap);
-    if (!reader->errorFunc) {
-        xmlTextReaderValidityWarning(ctx, "%s", str);
-    } else {
-        reader->errorFunc(reader->errorFuncArg, str,
-                          XML_PARSER_SEVERITY_VALIDITY_WARNING,
-                          NULL /* locator */ );
-    }
-    if (str != NULL)
-        xmlFree(str);
-    va_end(ap);
-}
-
-static void
-xmlTextReaderStructuredError(void *ctxt, const xmlError *error);
-
-static void
-xmlTextReaderValidityStructuredRelay(void *userData, const xmlError *error)
-{
-    xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;
-
-    if (reader->sErrorFunc) {
-        reader->sErrorFunc(reader->errorFuncArg, error);
-    } else {
-        xmlTextReaderStructuredError(reader, error);
-    }
-}
 /**
  * xmlTextReaderRelaxNGSetSchema:
  * @reader:  the xmlTextReaderPtr used
@@ -4017,17 +4030,9 @@
     reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
     if (reader->rngValidCtxt == NULL)
         return(-1);
-    if (reader->errorFunc != NULL) {
-	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
-			xmlTextReaderValidityErrorRelay,
-			xmlTextReaderValidityWarningRelay,
-			reader);
-    }
-	if (reader->sErrorFunc != NULL) {
-		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
-			xmlTextReaderValidityStructuredRelay,
-			reader);
-    }
+    if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL))
+	xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
+			xmlTextReaderStructuredRelay, reader);
     reader->rngValidErrors = 0;
     reader->rngFullNode = NULL;
     reader->validate = XML_TEXTREADER_VALIDATE_RNG;
@@ -4159,17 +4164,9 @@
                                 xmlTextReaderLocator,
 				(void *) reader);
 
-    if (reader->errorFunc != NULL) {
-	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
-			xmlTextReaderValidityErrorRelay,
-			xmlTextReaderValidityWarningRelay,
-			reader);
-    }
-	if (reader->sErrorFunc != NULL) {
-		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
-			xmlTextReaderValidityStructuredRelay,
-			reader);
-    }
+    if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL))
+	xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
+			xmlTextReaderStructuredRelay, reader);
     reader->xsdValidErrors = 0;
     reader->validate = XML_TEXTREADER_VALIDATE_XSD;
     return(0);
@@ -4229,21 +4226,14 @@
 	/* Parse the schema and create validation environment. */
 
 	pctxt = xmlRelaxNGNewParserCtxt(rng);
-	if (reader->errorFunc != NULL) {
-	    xmlRelaxNGSetParserErrors(pctxt,
-		xmlTextReaderValidityErrorRelay,
-		xmlTextReaderValidityWarningRelay,
-		reader);
-	}
-	if (reader->sErrorFunc != NULL) {
-	    xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
-		xmlTextReaderValidityStructuredRelay,
-		reader);
-	}
+	if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL))
+	    xmlRelaxNGSetParserStructuredErrors(pctxt,
+                    xmlTextReaderStructuredRelay, reader);
 	reader->rngSchemas = xmlRelaxNGParse(pctxt);
 	xmlRelaxNGFreeParserCtxt(pctxt);
 	if (reader->rngSchemas == NULL)
 	    return(-1);
+
 	reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
 	if (reader->rngValidCtxt == NULL) {
 	    xmlRelaxNGFree(reader->rngSchemas);
@@ -4261,17 +4251,9 @@
     * TODO: In case the user provides the validation context we
     *	could make this redirection optional.
     */
-    if (reader->errorFunc != NULL) {
-	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
-			 xmlTextReaderValidityErrorRelay,
-			 xmlTextReaderValidityWarningRelay,
-			 reader);
-    }
-	if (reader->sErrorFunc != NULL) {
-		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
-			xmlTextReaderValidityStructuredRelay,
-			reader);
-    }
+    if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL))
+        xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
+                xmlTextReaderStructuredRelay, reader);
     reader->rngValidErrors = 0;
     reader->rngFullNode = NULL;
     reader->validate = XML_TEXTREADER_VALIDATE_RNG;
@@ -4334,12 +4316,9 @@
 	xmlSchemaParserCtxtPtr pctxt;
 	/* Parse the schema and create validation environment. */
 	pctxt = xmlSchemaNewParserCtxt(xsd);
-	if (reader->errorFunc != NULL) {
-	    xmlSchemaSetParserErrors(pctxt,
-		xmlTextReaderValidityErrorRelay,
-		xmlTextReaderValidityWarningRelay,
-		reader);
-	}
+	if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL))
+	    xmlSchemaSetParserStructuredErrors(pctxt,
+                    xmlTextReaderStructuredRelay, reader);
 	reader->xsdSchemas = xmlSchemaParse(pctxt);
 	xmlSchemaFreeParserCtxt(pctxt);
 	if (reader->xsdSchemas == NULL)
@@ -4382,17 +4361,9 @@
     * TODO: In case the user provides the validation context we
     *   could make this redirection optional.
     */
-    if (reader->errorFunc != NULL) {
-	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
-			 xmlTextReaderValidityErrorRelay,
-			 xmlTextReaderValidityWarningRelay,
-			 reader);
-    }
-	if (reader->sErrorFunc != NULL) {
-		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
-			xmlTextReaderValidityStructuredRelay,
-			reader);
-    }
+    if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL))
+	xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
+			xmlTextReaderStructuredRelay, reader);
     reader->xsdValidErrors = 0;
     reader->validate = XML_TEXTREADER_VALIDATE_XSD;
     return(0);
@@ -4565,43 +4536,6 @@
  *									*
  ************************************************************************/
 
-/* helper to build a xmlMalloc'ed string from a format and va_list */
-static char *
-xmlTextReaderBuildMessage(const char *msg, va_list ap) {
-    int size = 0;
-    int chars;
-    char *larger;
-    char *str = NULL;
-    va_list aq;
-
-    while (1) {
-        va_copy(aq, ap);
-        chars = vsnprintf(str, size, msg, aq);
-        va_end(aq);
-        if (chars < 0) {
-	    xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n");
-	    if (str)
-		xmlFree(str);
-	    return NULL;
-	}
-	if ((chars < size) || (size == MAX_ERR_MSG_SIZE))
-            break;
-        if (chars < MAX_ERR_MSG_SIZE)
-	size = chars + 1;
-	else
-		size = MAX_ERR_MSG_SIZE;
-        if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
-	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
-	    if (str)
-                xmlFree(str);
-            return NULL;
-        }
-        str = larger;
-    }
-
-    return str;
-}
-
 /**
  * xmlTextReaderLocatorLineNumber:
  * @locator: the xmlTextReaderLocatorPtr used
@@ -4675,105 +4609,14 @@
     return ret;
 }
 
-static void
-xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity,
-                          char *str)
-{
-    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
-
-    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
-
-    if (str != NULL) {
-        if (reader->errorFunc)
-            reader->errorFunc(reader->errorFuncArg, str, severity,
-                              (xmlTextReaderLocatorPtr) ctx);
-        xmlFree(str);
-    }
-}
-
-static void
-xmlTextReaderStructuredError(void *ctxt, const xmlError *error)
-{
-    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
-
-    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
-
-    if (error && reader->sErrorFunc) {
-        reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error);
-    }
-}
-
-static void LIBXML_ATTR_FORMAT(2,3)
-xmlTextReaderError(void *ctxt, const char *msg, ...)
-{
-    va_list ap;
-
-    va_start(ap, msg);
-    xmlTextReaderGenericError(ctxt,
-                              XML_PARSER_SEVERITY_ERROR,
-                              xmlTextReaderBuildMessage(msg, ap));
-    va_end(ap);
-
-}
-
-static void LIBXML_ATTR_FORMAT(2,3)
-xmlTextReaderWarning(void *ctxt, const char *msg, ...)
-{
-    va_list ap;
-
-    va_start(ap, msg);
-    xmlTextReaderGenericError(ctxt,
-                              XML_PARSER_SEVERITY_WARNING,
-                              xmlTextReaderBuildMessage(msg, ap));
-    va_end(ap);
-}
-
-static void
-xmlTextReaderValidityError(void *ctxt, const char *msg, ...)
-{
-    va_list ap;
-
-    int len = xmlStrlen((const xmlChar *) msg);
-
-    if ((len > 1) && (msg[len - 2] != ':')) {
-        /*
-         * some callbacks only report locator information:
-         * skip them (mimicking behaviour in error.c)
-         */
-        va_start(ap, msg);
-        xmlTextReaderGenericError(ctxt,
-                                  XML_PARSER_SEVERITY_VALIDITY_ERROR,
-                                  xmlTextReaderBuildMessage(msg, ap));
-        va_end(ap);
-    }
-}
-
-static void
-xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...)
-{
-    va_list ap;
-
-    int len = xmlStrlen((const xmlChar *) msg);
-
-    if ((len != 0) && (msg[len - 1] != ':')) {
-        /*
-         * some callbacks only report locator information:
-         * skip them (mimicking behaviour in error.c)
-         */
-        va_start(ap, msg);
-        xmlTextReaderGenericError(ctxt,
-                                  XML_PARSER_SEVERITY_VALIDITY_WARNING,
-                                  xmlTextReaderBuildMessage(msg, ap));
-        va_end(ap);
-    }
-}
-
 /**
  * xmlTextReaderSetErrorHandler:
  * @reader:  the xmlTextReaderPtr used
  * @f:	the callback function to call on error and warnings
  * @arg:    a user argument to pass to the callback function
  *
+ * DEPRECATED: Use xmlTextReaderSetStructuredErrorHandler.
+ *
  * Register a callback function that will be called on error and warnings.
  *
  * If @f is NULL, the default error and warning handlers are restored.
@@ -4783,53 +4626,35 @@
                              xmlTextReaderErrorFunc f, void *arg)
 {
     if (f != NULL) {
-        reader->ctxt->sax->error = xmlTextReaderError;
-        reader->ctxt->sax->serror = NULL;
-        reader->ctxt->vctxt.error = xmlTextReaderValidityError;
-        reader->ctxt->sax->warning = xmlTextReaderWarning;
-        reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
         reader->errorFunc = f;
         reader->sErrorFunc = NULL;
         reader->errorFuncArg = arg;
+        xmlCtxtSetErrorHandler(reader->ctxt,
+                xmlTextReaderStructuredRelay, reader);
 #ifdef LIBXML_SCHEMAS_ENABLED
         if (reader->rngValidCtxt) {
-            xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
-                                     xmlTextReaderValidityErrorRelay,
-                                     xmlTextReaderValidityWarningRelay,
-                                     reader);
-            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
-                                               reader);
+            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
+                    xmlTextReaderStructuredRelay, reader);
         }
         if (reader->xsdValidCtxt) {
-            xmlSchemaSetValidErrors(reader->xsdValidCtxt,
-                                    xmlTextReaderValidityErrorRelay,
-                                    xmlTextReaderValidityWarningRelay,
-                                    reader);
-            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
-                                              reader);
+            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
+                    xmlTextReaderStructuredRelay, reader);
         }
 #endif
     } else {
         /* restore defaults */
-        reader->ctxt->sax->error = xmlParserError;
-        reader->ctxt->vctxt.error = xmlParserValidityError;
-        reader->ctxt->sax->warning = xmlParserWarning;
-        reader->ctxt->vctxt.warning = xmlParserValidityWarning;
         reader->errorFunc = NULL;
         reader->sErrorFunc = NULL;
         reader->errorFuncArg = NULL;
+        xmlCtxtSetErrorHandler(reader->ctxt, NULL, NULL);
 #ifdef LIBXML_SCHEMAS_ENABLED
         if (reader->rngValidCtxt) {
-            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
-                                     reader);
             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
-                                               reader);
+                                               NULL);
         }
         if (reader->xsdValidCtxt) {
-            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
-                                    reader);
             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
-                                              reader);
+                                              NULL);
         }
 #endif
     }
@@ -4850,52 +4675,35 @@
                                        xmlStructuredErrorFunc f, void *arg)
 {
     if (f != NULL) {
-        reader->ctxt->sax->error = NULL;
-        reader->ctxt->sax->serror = xmlTextReaderStructuredError;
-        reader->ctxt->vctxt.error = xmlTextReaderValidityError;
-        reader->ctxt->sax->warning = xmlTextReaderWarning;
-        reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
         reader->sErrorFunc = f;
         reader->errorFunc = NULL;
         reader->errorFuncArg = arg;
+        xmlCtxtSetErrorHandler(reader->ctxt,
+                xmlTextReaderStructuredRelay, reader);
 #ifdef LIBXML_SCHEMAS_ENABLED
         if (reader->rngValidCtxt) {
-            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
-                                     reader);
             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
-                                        xmlTextReaderValidityStructuredRelay,
-                                               reader);
+                    xmlTextReaderStructuredRelay, reader);
         }
         if (reader->xsdValidCtxt) {
-            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
-                                    reader);
             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
-                                       xmlTextReaderValidityStructuredRelay,
-                                              reader);
+                    xmlTextReaderStructuredRelay, reader);
         }
 #endif
     } else {
         /* restore defaults */
-        reader->ctxt->sax->error = xmlParserError;
-        reader->ctxt->sax->serror = NULL;
-        reader->ctxt->vctxt.error = xmlParserValidityError;
-        reader->ctxt->sax->warning = xmlParserWarning;
-        reader->ctxt->vctxt.warning = xmlParserValidityWarning;
         reader->errorFunc = NULL;
         reader->sErrorFunc = NULL;
         reader->errorFuncArg = NULL;
+        xmlCtxtSetErrorHandler(reader->ctxt, NULL, NULL);
 #ifdef LIBXML_SCHEMAS_ENABLED
         if (reader->rngValidCtxt) {
-            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
-                                     reader);
             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
-                                               reader);
+                                               NULL);
         }
         if (reader->xsdValidCtxt) {
-            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
-                                    reader);
             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
-                                              reader);
+                                              NULL);
         }
 #endif
     }
@@ -4995,8 +4803,6 @@
     if (reader->buffer == NULL)
         reader->buffer = xmlBufCreateSize(100);
     if (reader->buffer == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-                        "xmlTextReaderSetup : malloc failed\n");
         return (-1);
     }
     /* no operation on a reader should require a huge buffer */
@@ -5005,8 +4811,6 @@
     if (reader->sax == NULL)
 	reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
     if (reader->sax == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-                        "xmlTextReaderSetup : malloc failed\n");
         return (-1);
     }
     xmlSAXVersion(reader->sax, 2);
@@ -5053,13 +4857,15 @@
                 reader->base = 0;
                 reader->cur = 0;
             }
+            if (reader->ctxt == NULL) {
+                return (-1);
+            }
         } else {
 	    xmlParserInputPtr inputStream;
 	    xmlParserInputBufferPtr buf;
-	    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
 
 	    xmlCtxtReset(reader->ctxt);
-	    buf = xmlAllocParserInputBuffer(enc);
+	    buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
 	    if (buf == NULL) return(-1);
 	    inputStream = xmlNewInputStream(reader->ctxt);
 	    if (inputStream == NULL) {
@@ -5078,11 +4884,6 @@
 	    inputPush(reader->ctxt, inputStream);
 	    reader->cur = 0;
 	}
-        if (reader->ctxt == NULL) {
-            xmlGenericError(xmlGenericErrorContext,
-                            "xmlTextReaderSetup : malloc failed\n");
-            return (-1);
-        }
     }
     if (reader->dict != NULL) {
         if (reader->ctxt->dict != NULL) {
@@ -5104,7 +4905,6 @@
     /*
      * use the parser dictionary to allocate all elements and attributes names
      */
-    reader->ctxt->docdict = 1;
     reader->ctxt->parseMode = XML_PARSE_READER;
 
 #ifdef LIBXML_XINCLUDE_ENABLED
@@ -5138,13 +4938,8 @@
         reader->validate = XML_TEXTREADER_VALIDATE_DTD;
 
     xmlCtxtUseOptions(reader->ctxt, options);
-    if (encoding != NULL) {
-        xmlCharEncodingHandlerPtr hdlr;
-
-        hdlr = xmlFindCharEncodingHandler(encoding);
-        if (hdlr != NULL)
-            xmlSwitchToEncoding(reader->ctxt, hdlr);
-    }
+    if (encoding != NULL)
+        xmlSwitchEncodingName(reader->ctxt, encoding);
     if ((URL != NULL) && (reader->ctxt->input != NULL) &&
         (reader->ctxt->input->filename == NULL))
         reader->ctxt->input->filename = (char *)
@@ -5168,6 +4963,14 @@
     xmlCtxtSetMaxAmplification(reader->ctxt, maxAmpl);
 }
 
+const xmlError *
+xmlTextReaderGetLastError(xmlTextReaderPtr reader)
+{
+    if (reader == NULL)
+        return(NULL);
+    return(&reader->ctxt->lastError);
+}
+
 /**
  * xmlTextReaderByteConsumed:
  * @reader: an XML reader
@@ -5207,8 +5010,6 @@
 
     ret = xmlMalloc(sizeof(xmlTextReader));
     if (ret == NULL) {
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlNewTextReader : malloc failed\n");
 	return(NULL);
     }
     memset(ret, 0, sizeof(xmlTextReader));
diff --git a/src/xmlsave.c b/src/xmlsave.c
index 20ee3aa..636432a 100644
--- a/src/xmlsave.c
+++ b/src/xmlsave.c
@@ -9,6 +9,7 @@
 #define IN_LIBXML
 #include "libxml.h"
 
+#include <stdlib.h>
 #include <string.h>
 #include <libxml/xmlmemory.h>
 #include <libxml/parserInternals.h>
@@ -28,11 +29,6 @@
 
 #define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
 
-#define TODO								\
-    xmlGenericError(xmlGenericErrorContext,				\
-	    "Unimplemented block at %s:%d\n",				\
-            __FILE__, __LINE__);
-
 struct _xmlSaveCtxt {
     void *_private;
     int type;
@@ -63,9 +59,11 @@
  * Handle an out of memory condition
  */
 static void
-xmlSaveErrMemory(const char *extra)
+xmlSaveErrMemory(xmlOutputBufferPtr out)
 {
-    __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra);
+    if (out != NULL)
+        out->error = XML_ERR_NO_MEMORY;
+    xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_OUTPUT, NULL);
 }
 
 /**
@@ -77,9 +75,23 @@
  * Handle an out of memory condition
  */
 static void
-xmlSaveErr(int code, xmlNodePtr node, const char *extra)
+xmlSaveErr(xmlOutputBufferPtr out, int code, xmlNodePtr node,
+           const char *extra)
 {
     const char *msg = NULL;
+    int res;
+
+    /* Don't overwrite memory errors */
+    if ((out != NULL) && (out->error == XML_ERR_NO_MEMORY))
+        return;
+
+    if (code == XML_ERR_NO_MEMORY) {
+        xmlSaveErrMemory(out);
+        return;
+    }
+
+    if (out != NULL)
+        out->error = code;
 
     switch(code) {
         case XML_SAVE_NOT_UTF8:
@@ -97,7 +109,13 @@
 	default:
 	    msg = "unexpected error number\n";
     }
-    __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra);
+
+    res = __xmlRaiseError(NULL, NULL, NULL, NULL, node,
+                          XML_FROM_OUTPUT, code, XML_ERR_ERROR, NULL, 0,
+                          extra, NULL, NULL, 0, 0,
+                          msg, extra);
+    if (res < 0)
+        xmlSaveErrMemory(out);
 }
 
 /************************************************************************
@@ -198,79 +216,56 @@
 	    *out++ = ';';
 	    in++;
 	    continue;
+	} else if (*in == 0xD) {
+	    if (outend - out < 5) break;
+	    *out++ = '&';
+	    *out++ = '#';
+	    *out++ = 'x';
+	    *out++ = 'D';
+	    *out++ = ';';
+	    in++;
 	} else if (((*in >= 0x20) && (*in < 0x80)) ||
-	           (*in == '\n') || (*in == '\t')) {
+	           (*in == 0xA) || (*in == 0x9)) {
 	    /*
 	     * default case, just copy !
 	     */
 	    *out++ = *in++;
 	    continue;
-	} else if (*in >= 0x80) {
-	    /*
-	     * We assume we have UTF-8 input.
-	     */
+	} else if (*in < 0x80) {
+            /* invalid control char */
+	    if (outend - out < 8) break;
+	    out = xmlSerializeHexCharRef(out, 0xFFFD);
+	    in++;
+	} else {
+            int len;
+
 	    if (outend - out < 11) break;
 
-	    if (*in < 0xC0) {
-		xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL);
-		in++;
-		goto error;
-	    } else if (*in < 0xE0) {
-		if (inend - in < 2) break;
-		val = (in[0]) & 0x1F;
-		val <<= 6;
-		val |= (in[1]) & 0x3F;
-		in += 2;
-	    } else if (*in < 0xF0) {
-		if (inend - in < 3) break;
-		val = (in[0]) & 0x0F;
-		val <<= 6;
-		val |= (in[1]) & 0x3F;
-		val <<= 6;
-		val |= (in[2]) & 0x3F;
-		in += 3;
-	    } else if (*in < 0xF8) {
-		if (inend - in < 4) break;
-		val = (in[0]) & 0x07;
-		val <<= 6;
-		val |= (in[1]) & 0x3F;
-		val <<= 6;
-		val |= (in[2]) & 0x3F;
-		val <<= 6;
-		val |= (in[3]) & 0x3F;
-		in += 4;
-	    } else {
-		xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
-		in++;
-		goto error;
-	    }
-	    if (!IS_CHAR(val)) {
-		xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL);
-		in++;
-		goto error;
-	    }
+            len = inend - in;
+            val = xmlGetUTF8Char(in, &len);
+
+            if (val < 0) {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+                fprintf(stderr, "xmlEscapeEntities: invalid UTF-8\n");
+                abort();
+#endif
+                val = 0xFFFD;
+                in++;
+            } else {
+                if (!IS_CHAR(val))
+                    val = 0xFFFD;
+                in += len;
+            }
 
 	    /*
 	     * We could do multiple things here. Just save as a char ref
 	     */
 	    out = xmlSerializeHexCharRef(out, val);
-	} else if (IS_BYTE_CHAR(*in)) {
-	    if (outend - out < 6) break;
-	    out = xmlSerializeHexCharRef(out, *in++);
-	} else {
-	    xmlGenericError(xmlGenericErrorContext,
-		"xmlEscapeEntities : char out of range\n");
-	    in++;
-	    goto error;
 	}
     }
     *outlen = out - outstart;
     *inlen = in - base;
     return(0);
-error:
-    *outlen = out - outstart;
-    *inlen = in - base;
-    return(-1);
 }
 
 /************************************************************************
@@ -340,15 +335,18 @@
 
     ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt));
     if (ret == NULL) {
-	xmlSaveErrMemory("creating saving context");
+	xmlSaveErrMemory(NULL);
 	return ( NULL );
     }
     memset(ret, 0, sizeof(xmlSaveCtxt));
 
     if (encoding != NULL) {
-        ret->handler = xmlFindCharEncodingHandler(encoding);
+        int res;
+
+        res = xmlOpenCharEncodingHandler(encoding, /* output */ 1,
+                                         &ret->handler);
 	if (ret->handler == NULL) {
-	    xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding);
+	    xmlSaveErr(NULL, res, NULL, encoding);
             xmlFreeSaveCtxt(ret);
 	    return(NULL);
 	}
@@ -415,6 +413,46 @@
 }
 
 /**
+ * xmlBufDumpNotationDecl:
+ * @buf:  the XML buffer output
+ * @nota:  A notation declaration
+ *
+ * This will dump the content the notation declaration as an XML DTD definition
+ */
+static void
+xmlBufDumpNotationDecl(xmlOutputBufferPtr buf, xmlNotationPtr nota) {
+    xmlOutputBufferWrite(buf, 11, "<!NOTATION ");
+    xmlOutputBufferWriteString(buf, (const char *) nota->name);
+
+    if (nota->PublicID != NULL) {
+	xmlOutputBufferWrite(buf, 8, " PUBLIC ");
+	xmlBufWriteQuotedString(buf->buffer, nota->PublicID);
+	if (nota->SystemID != NULL) {
+	    xmlOutputBufferWrite(buf, 1, " ");
+	    xmlBufWriteQuotedString(buf->buffer, nota->SystemID);
+	}
+    } else {
+	xmlOutputBufferWrite(buf, 8, " SYSTEM ");
+	xmlBufWriteQuotedString(buf->buffer, nota->SystemID);
+    }
+
+    xmlOutputBufferWrite(buf, 3, " >\n");
+}
+
+/**
+ * xmlBufDumpNotationDeclScan:
+ * @nota:  A notation declaration
+ * @buf:  the XML buffer output
+ *
+ * This is called with the hash scan function, and just reverses args
+ */
+static void
+xmlBufDumpNotationDeclScan(void *nota, void *buf,
+                           const xmlChar *name ATTRIBUTE_UNUSED) {
+    xmlBufDumpNotationDecl((xmlOutputBufferPtr) buf, (xmlNotationPtr) nota);
+}
+
+/**
  * xmlBufDumpNotationTable:
  * @buf:  an xmlBufPtr output
  * @table:  A notation table
@@ -422,17 +460,105 @@
  * This will dump the content of the notation table as an XML DTD definition
  */
 static void
-xmlBufDumpNotationTable(xmlOutputBufferPtr stream, xmlNotationTablePtr table) {
-    xmlBufferPtr buffer;
+xmlBufDumpNotationTable(xmlOutputBufferPtr buf, xmlNotationTablePtr table) {
+    xmlHashScan(table, xmlBufDumpNotationDeclScan, buf);
+}
 
-    buffer = xmlBufferCreate();
-    if (buffer == NULL) {
-        stream->error = XML_ERR_NO_MEMORY;
-        return;
+/**
+ * xmlBufDumpElementOccur:
+ * @buf:  output buffer
+ * @cur:  element table
+ *
+ * Dump the occurrence operator of an element.
+ */
+static void
+xmlBufDumpElementOccur(xmlOutputBufferPtr buf, xmlElementContentPtr cur) {
+    switch (cur->ocur) {
+        case XML_ELEMENT_CONTENT_ONCE:
+            break;
+        case XML_ELEMENT_CONTENT_OPT:
+            xmlOutputBufferWrite(buf, 1, "?");
+            break;
+        case XML_ELEMENT_CONTENT_MULT:
+            xmlOutputBufferWrite(buf, 1, "*");
+            break;
+        case XML_ELEMENT_CONTENT_PLUS:
+            xmlOutputBufferWrite(buf, 1, "+");
+            break;
     }
-    xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT);
-    xmlDumpNotationTable(buffer, table);
-    xmlBufMergeBuffer(stream->buffer, buffer);
+}
+
+/**
+ * xmlBufDumpElementContent:
+ * @buf:  output buffer
+ * @content:  element table
+ *
+ * This will dump the content of the element table as an XML DTD definition
+ */
+static void
+xmlBufDumpElementContent(xmlOutputBufferPtr buf,
+                         xmlElementContentPtr content) {
+    xmlElementContentPtr cur;
+
+    if (content == NULL) return;
+
+    xmlOutputBufferWrite(buf, 1, "(");
+    cur = content;
+
+    do {
+        if (cur == NULL) return;
+
+        switch (cur->type) {
+            case XML_ELEMENT_CONTENT_PCDATA:
+                xmlOutputBufferWrite(buf, 7, "#PCDATA");
+                break;
+            case XML_ELEMENT_CONTENT_ELEMENT:
+                if (cur->prefix != NULL) {
+                    xmlOutputBufferWriteString(buf,
+                            (const char *) cur->prefix);
+                    xmlOutputBufferWrite(buf, 1, ":");
+                }
+                xmlOutputBufferWriteString(buf, (const char *) cur->name);
+                break;
+            case XML_ELEMENT_CONTENT_SEQ:
+            case XML_ELEMENT_CONTENT_OR:
+                if ((cur != content) &&
+                    (cur->parent != NULL) &&
+                    ((cur->type != cur->parent->type) ||
+                     (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
+                    xmlOutputBufferWrite(buf, 1, "(");
+                cur = cur->c1;
+                continue;
+        }
+
+        while (cur != content) {
+            xmlElementContentPtr parent = cur->parent;
+
+            if (parent == NULL) return;
+
+            if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
+                 (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
+                ((cur->type != parent->type) ||
+                 (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
+                xmlOutputBufferWrite(buf, 1, ")");
+            xmlBufDumpElementOccur(buf, cur);
+
+            if (cur == parent->c1) {
+                if (parent->type == XML_ELEMENT_CONTENT_SEQ)
+                    xmlOutputBufferWrite(buf, 3, " , ");
+                else if (parent->type == XML_ELEMENT_CONTENT_OR)
+                    xmlOutputBufferWrite(buf, 3, " | ");
+
+                cur = parent->c2;
+                break;
+            }
+
+            cur = parent;
+        }
+    } while (cur != content);
+
+    xmlOutputBufferWrite(buf, 1, ")");
+    xmlBufDumpElementOccur(buf, content);
 }
 
 /**
@@ -444,39 +570,173 @@
  * DTD definition
  */
 static void
-xmlBufDumpElementDecl(xmlOutputBufferPtr stream, xmlElementPtr elem) {
-    xmlBufferPtr buffer;
-
-    buffer = xmlBufferCreate();
-    if (buffer == NULL) {
-        stream->error = XML_ERR_NO_MEMORY;
-        return;
+xmlBufDumpElementDecl(xmlOutputBufferPtr buf, xmlElementPtr elem) {
+    xmlOutputBufferWrite(buf, 10, "<!ELEMENT ");
+    if (elem->prefix != NULL) {
+        xmlOutputBufferWriteString(buf, (const char *) elem->prefix);
+        xmlOutputBufferWrite(buf, 1, ":");
     }
-    xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT);
-    xmlDumpElementDecl(buffer, elem);
-    xmlBufMergeBuffer(stream->buffer, buffer);
+    xmlOutputBufferWriteString(buf, (const char *) elem->name);
+    xmlOutputBufferWrite(buf, 1, " ");
+
+    switch (elem->etype) {
+	case XML_ELEMENT_TYPE_EMPTY:
+	    xmlOutputBufferWrite(buf, 5, "EMPTY");
+	    break;
+	case XML_ELEMENT_TYPE_ANY:
+	    xmlOutputBufferWrite(buf, 3, "ANY");
+	    break;
+	case XML_ELEMENT_TYPE_MIXED:
+	case XML_ELEMENT_TYPE_ELEMENT:
+	    xmlBufDumpElementContent(buf, elem->content);
+	    break;
+        default:
+            /* assert(0); */
+            break;
+    }
+
+    xmlOutputBufferWrite(buf, 2, ">\n");
 }
 
 /**
+ * xmlBufDumpEnumeration:
+ * @buf:  output buffer
+ * @enum:  An enumeration
+ *
+ * This will dump the content of the enumeration
+ */
+static void
+xmlBufDumpEnumeration(xmlOutputBufferPtr buf, xmlEnumerationPtr cur) {
+    while (cur != NULL) {
+        xmlOutputBufferWriteString(buf, (const char *) cur->name);
+        if (cur->next != NULL)
+            xmlOutputBufferWrite(buf, 3, " | ");
+
+        cur = cur->next;
+    }
+
+    xmlOutputBufferWrite(buf, 1, ")");
+}
+/**
  * xmlBufDumpAttributeDecl:
- * @buf:  an xmlBufPtr output
+ * @buf:  output buffer
  * @attr:  An attribute declaration
  *
  * This will dump the content of the attribute declaration as an XML
  * DTD definition
  */
 static void
-xmlBufDumpAttributeDecl(xmlOutputBufferPtr stream, xmlAttributePtr attr) {
-    xmlBufferPtr buffer;
-
-    buffer = xmlBufferCreate();
-    if (buffer == NULL) {
-        stream->error = XML_ERR_NO_MEMORY;
-        return;
+xmlBufDumpAttributeDecl(xmlOutputBufferPtr buf, xmlAttributePtr attr) {
+    xmlOutputBufferWrite(buf, 10, "<!ATTLIST ");
+    xmlOutputBufferWriteString(buf, (const char *) attr->elem);
+    xmlOutputBufferWrite(buf, 1, " ");
+    if (attr->prefix != NULL) {
+	xmlOutputBufferWriteString(buf, (const char *) attr->prefix);
+	xmlOutputBufferWrite(buf, 1, ":");
     }
-    xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT);
-    xmlDumpAttributeDecl(buffer, attr);
-    xmlBufMergeBuffer(stream->buffer, buffer);
+    xmlOutputBufferWriteString(buf, (const char *) attr->name);
+
+    switch (attr->atype) {
+	case XML_ATTRIBUTE_CDATA:
+	    xmlOutputBufferWrite(buf, 6, " CDATA");
+	    break;
+	case XML_ATTRIBUTE_ID:
+	    xmlOutputBufferWrite(buf, 3, " ID");
+	    break;
+	case XML_ATTRIBUTE_IDREF:
+	    xmlOutputBufferWrite(buf, 6, " IDREF");
+	    break;
+	case XML_ATTRIBUTE_IDREFS:
+	    xmlOutputBufferWrite(buf, 7, " IDREFS");
+	    break;
+	case XML_ATTRIBUTE_ENTITY:
+	    xmlOutputBufferWrite(buf, 7, " ENTITY");
+	    break;
+	case XML_ATTRIBUTE_ENTITIES:
+	    xmlOutputBufferWrite(buf, 9, " ENTITIES");
+	    break;
+	case XML_ATTRIBUTE_NMTOKEN:
+	    xmlOutputBufferWrite(buf, 8, " NMTOKEN");
+	    break;
+	case XML_ATTRIBUTE_NMTOKENS:
+	    xmlOutputBufferWrite(buf, 9, " NMTOKENS");
+	    break;
+	case XML_ATTRIBUTE_ENUMERATION:
+	    xmlOutputBufferWrite(buf, 2, " (");
+	    xmlBufDumpEnumeration(buf, attr->tree);
+	    break;
+	case XML_ATTRIBUTE_NOTATION:
+	    xmlOutputBufferWrite(buf, 11, " NOTATION (");
+	    xmlBufDumpEnumeration(buf, attr->tree);
+	    break;
+	default:
+            /* assert(0); */
+            break;
+    }
+
+    switch (attr->def) {
+	case XML_ATTRIBUTE_NONE:
+	    break;
+	case XML_ATTRIBUTE_REQUIRED:
+	    xmlOutputBufferWrite(buf, 10, " #REQUIRED");
+	    break;
+	case XML_ATTRIBUTE_IMPLIED:
+	    xmlOutputBufferWrite(buf, 9, " #IMPLIED");
+	    break;
+	case XML_ATTRIBUTE_FIXED:
+	    xmlOutputBufferWrite(buf, 7, " #FIXED");
+	    break;
+	default:
+            /* assert(0); */
+            break;
+    }
+
+    if (attr->defaultValue != NULL) {
+	xmlOutputBufferWrite(buf, 1, " ");
+	xmlBufWriteQuotedString(buf->buffer, attr->defaultValue);
+    }
+
+    xmlOutputBufferWrite(buf, 2, ">\n");
+}
+
+/**
+ * xmlBufDumpEntityContent:
+ * @buf:  output buffer
+ * @content:  entity content.
+ *
+ * This will dump the quoted string value, taking care of the special
+ * treatment required by %
+ */
+static void
+xmlBufDumpEntityContent(xmlOutputBufferPtr buf, const xmlChar *content) {
+    if (xmlStrchr(content, '%')) {
+        const char * base, *cur;
+
+	xmlOutputBufferWrite(buf, 1, "\"");
+	base = cur = (const char *) content;
+	while (*cur != 0) {
+	    if (*cur == '"') {
+		if (base != cur)
+		    xmlOutputBufferWrite(buf, cur - base, base);
+		xmlOutputBufferWrite(buf, 6, "&quot;");
+		cur++;
+		base = cur;
+	    } else if (*cur == '%') {
+		if (base != cur)
+		    xmlOutputBufferWrite(buf, cur - base, base);
+		xmlOutputBufferWrite(buf, 6, "&#x25;");
+		cur++;
+		base = cur;
+	    } else {
+		cur++;
+	    }
+	}
+	if (base != cur)
+	    xmlOutputBufferWrite(buf, cur - base, base);
+	xmlOutputBufferWrite(buf, 1, "\"");
+    } else {
+        xmlBufWriteQuotedString(buf->buffer, content);
+    }
 }
 
 /**
@@ -487,17 +747,47 @@
  * This will dump the content of the entity table as an XML DTD definition
  */
 static void
-xmlBufDumpEntityDecl(xmlOutputBufferPtr stream, xmlEntityPtr ent) {
-    xmlBufferPtr buffer;
+xmlBufDumpEntityDecl(xmlOutputBufferPtr buf, xmlEntityPtr ent) {
+    if ((ent->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
+        (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY))
+        xmlOutputBufferWrite(buf, 11, "<!ENTITY % ");
+    else
+        xmlOutputBufferWrite(buf, 9, "<!ENTITY ");
+    xmlOutputBufferWriteString(buf, (const char *) ent->name);
+    xmlOutputBufferWrite(buf, 1, " ");
 
-    buffer = xmlBufferCreate();
-    if (buffer == NULL) {
-        stream->error = XML_ERR_NO_MEMORY;
-        return;
+    if ((ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) ||
+        (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) ||
+        (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) {
+        if (ent->ExternalID != NULL) {
+             xmlOutputBufferWrite(buf, 7, "PUBLIC ");
+             xmlBufWriteQuotedString(buf->buffer, ent->ExternalID);
+             xmlOutputBufferWrite(buf, 1, " ");
+        } else {
+             xmlOutputBufferWrite(buf, 7, "SYSTEM ");
+        }
+        xmlBufWriteQuotedString(buf->buffer, ent->SystemID);
     }
-    xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT);
-    xmlDumpEntityDecl(buffer, ent);
-    xmlBufMergeBuffer(stream->buffer, buffer);
+
+    if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
+        if (ent->content != NULL) { /* Should be true ! */
+            xmlOutputBufferWrite(buf, 7, " NDATA ");
+            if (ent->orig != NULL)
+                xmlOutputBufferWriteString(buf, (const char *) ent->orig);
+            else
+                xmlOutputBufferWriteString(buf, (const char *) ent->content);
+        }
+    }
+
+    if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) ||
+        (ent->etype == XML_INTERNAL_PARAMETER_ENTITY)) {
+        if (ent->orig != NULL)
+            xmlBufWriteQuotedString(buf->buffer, ent->orig);
+        else
+            xmlBufDumpEntityContent(buf, ent->content);
+    }
+
+    xmlOutputBufferWrite(buf, 2, ">\n");
 }
 
 /************************************************************************
@@ -513,15 +803,15 @@
         xmlCharEncodingHandler *handler;
         int res;
 
-	res = xmlOpenCharEncodingHandler((const char *) encoding, &handler);
-        if (res != 0) {
-            buf->error = res;
+	res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler);
+        if (handler == NULL) {
+            xmlSaveErr(buf, res, NULL, encoding);
             return(-1);
         }
 	buf->conv = xmlBufCreate();
 	if (buf->conv == NULL) {
 	    xmlCharEncCloseFunc(handler);
-            buf->error = XML_ERR_NO_MEMORY;
+            xmlSaveErrMemory(buf);
 	    return(-1);
 	}
         buf->encoder = handler;
@@ -729,6 +1019,7 @@
     }
     xmlOutputBufferWriteString(buf, (const char *)cur->name);
     xmlOutputBufferWrite(buf, 2, "=\"");
+#ifdef LIBXML_HTML_ENABLED
     if ((ctxt->options & XML_SAVE_XHTML) &&
         (cur->ns == NULL) &&
         ((cur->children == NULL) ||
@@ -736,7 +1027,9 @@
          (cur->children->content[0] == 0)) &&
         (htmlIsBooleanAttr(cur->name))) {
         xmlOutputBufferWriteString(buf, (const char *) cur->name);
-    } else {
+    } else
+#endif
+    {
         xmlAttrSerializeContent(buf, cur);
     }
     xmlOutputBufferWrite(buf, 1, "\"");
@@ -1875,6 +2168,18 @@
     return(ret);
 }
 
+int
+xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur) {
+    xmlBufDumpNotationDecl(ctxt->buf, cur);
+    return(0);
+}
+
+int
+xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur) {
+    xmlBufDumpNotationTable(ctxt->buf, cur);
+    return(0);
+}
+
 /**
  * xmlSaveFlush:
  * @ctxt:  a document saving context
@@ -1985,7 +2290,8 @@
  */
 void
 xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
-                              xmlAttrPtr attr, const xmlChar * string)
+                              xmlAttrPtr attr ATTRIBUTE_UNUSED,
+                              const xmlChar * string)
 {
     xmlChar *base, *cur;
 
@@ -2041,54 +2347,31 @@
              * We assume we have UTF-8 content.
              */
             unsigned char tmp[12];
-            int val = 0, l = 1;
+            int val = 0, l = 4;
 
             if (base != cur)
                 xmlBufAdd(buf, base, cur - base);
-            if (*cur < 0xC0) {
-                xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL);
-		xmlSerializeHexCharRef(tmp, *cur);
-                xmlBufAdd(buf, (xmlChar *) tmp, -1);
+
+            val = xmlGetUTF8Char(cur, &l);
+            if (val < 0) {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+                fprintf(stderr, "xmlEscapeEntities: invalid UTF-8\n");
+                abort();
+#endif
+                val = 0xFFFD;
                 cur++;
-                base = cur;
-                continue;
-            } else if (*cur < 0xE0) {
-                val = (cur[0]) & 0x1F;
-                val <<= 6;
-                val |= (cur[1]) & 0x3F;
-                l = 2;
-            } else if ((*cur < 0xF0) && (cur [2] != 0)) {
-                val = (cur[0]) & 0x0F;
-                val <<= 6;
-                val |= (cur[1]) & 0x3F;
-                val <<= 6;
-                val |= (cur[2]) & 0x3F;
-                l = 3;
-            } else if ((*cur < 0xF8) && (cur [2] != 0) && (cur[3] != 0)) {
-                val = (cur[0]) & 0x07;
-                val <<= 6;
-                val |= (cur[1]) & 0x3F;
-                val <<= 6;
-                val |= (cur[2]) & 0x3F;
-                val <<= 6;
-                val |= (cur[3]) & 0x3F;
-                l = 4;
+            } else {
+                if (!IS_CHAR(val))
+                    val = 0xFFFD;
+                cur += l;
             }
-            if ((l == 1) || (!IS_CHAR(val))) {
-                xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL);
-		xmlSerializeHexCharRef(tmp, *cur);
-                xmlBufAdd(buf, (xmlChar *) tmp, -1);
-                cur++;
-                base = cur;
-                continue;
-            }
+
             /*
              * We could do multiple things here. Just save
              * as a char ref
              */
 	    xmlSerializeHexCharRef(tmp, val);
             xmlBufAdd(buf, (xmlChar *) tmp, -1);
-            cur += l;
             base = cur;
         } else {
             cur++;
@@ -2192,7 +2475,7 @@
     }
     outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
     if (outbuf == NULL) {
-        xmlSaveErrMemory("creating buffer");
+        xmlSaveErrMemory(NULL);
         return (-1);
     }
     memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
@@ -2235,13 +2518,11 @@
     outbuf = xmlOutputBufferCreateFile(f, NULL);
     if (outbuf == NULL)
         return;
-    if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
 #ifdef LIBXML_HTML_ENABLED
+    if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE))
         htmlNodeDumpOutput(outbuf, doc, cur, NULL);
-#else
-	xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n");
+    else
 #endif /* LIBXML_HTML_ENABLED */
-    } else
         xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL);
     xmlOutputBufferClose(outbuf);
 }
@@ -2358,16 +2639,18 @@
     if (txt_encoding == NULL)
 	txt_encoding = (const char *) out_doc->encoding;
     if (txt_encoding != NULL) {
-	conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
-	if ( conv_hdlr == NULL ) {
-	    xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc,
-		       txt_encoding);
+        int res;
+
+	res = xmlOpenCharEncodingHandler(txt_encoding, /* output */ 1,
+                                         &conv_hdlr);
+	if (conv_hdlr == NULL) {
+            xmlSaveErr(NULL, res, NULL, txt_encoding);
 	    return;
 	}
     }
 
     if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
-        xmlSaveErrMemory("creating buffer");
+        xmlSaveErrMemory(NULL);
         xmlCharEncCloseFunc(conv_hdlr);
         return;
     }
@@ -2401,7 +2684,7 @@
     return;
 
 error:
-    xmlSaveErrMemory("creating output");
+    xmlSaveErrMemory(NULL);
     xmlOutputBufferClose(out_buff);
     return;
 }
@@ -2485,7 +2768,7 @@
     encoding = (const char *) cur->encoding;
 
     if (encoding != NULL) {
-	handler = xmlFindCharEncodingHandler(encoding);
+	xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler);
 	if (handler == NULL) {
 	    xmlFree((char *) cur->encoding);
 	    cur->encoding = NULL;
@@ -2622,10 +2905,9 @@
 	encoding = (const char *) cur->encoding;
 
     if (encoding != NULL) {
-
-	    handler = xmlFindCharEncodingHandler(encoding);
-	    if (handler == NULL)
-		return(-1);
+        xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler);
+        if (handler == NULL)
+            return(-1);
     }
 
 #ifdef LIBXML_ZLIB_ENABLED
diff --git a/src/xmlstring.c b/src/xmlstring.c
index 5155955..e30c084 100644
--- a/src/xmlstring.c
+++ b/src/xmlstring.c
@@ -26,6 +26,14 @@
 #include "private/parser.h"
 #include "private/string.h"
 
+#ifndef va_copy
+  #ifdef __va_copy
+    #define va_copy(dest, src) __va_copy(dest, src)
+  #else
+    #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list))
+  #endif
+#endif
+
 /************************************************************************
  *                                                                      *
  *                Commodity functions to handle xmlChars                *
@@ -585,6 +593,148 @@
     return(ret);
 }
 
+/**
+ * xmlStrVASPrintf:
+ * @out:  pointer to the resulting string
+ * @maxSize:  maximum size of the output buffer
+ * @fmt:  printf format string
+ * @ap:  arguments for format string
+ *
+ * Creates a newly allocated string according to format.
+ *
+ * Returns 0 on success, 1 if the result was truncated or on other
+ * errors, -1 if a memory allocation failed.
+ */
+int
+xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap) {
+    char empty[1];
+    va_list copy;
+    xmlChar *buf;
+    int res, size;
+    int truncated = 0;
+
+    if (out == NULL)
+        return(1);
+    *out = NULL;
+    if (msg == NULL)
+        return(1);
+    if (maxSize < 32)
+        maxSize = 32;
+
+    va_copy(copy, ap);
+    res = vsnprintf(empty, 1, msg, copy);
+    va_end(copy);
+
+    if (res > 0) {
+        /* snprintf seems to work according to C99. */
+
+        if (res < maxSize) {
+            size = res + 1;
+        } else {
+            size = maxSize;
+            truncated = 1;
+        }
+        buf = xmlMalloc(size);
+        if (buf == NULL)
+            return(-1);
+        if (vsnprintf((char *) buf, size, msg, ap) < 0) {
+            xmlFree(buf);
+            return(1);
+        }
+    } else {
+        /*
+         * Unfortunately, older snprintf implementations don't follow the
+         * C99 spec. If the output exceeds the size of the buffer, they can
+         * return -1, 0 or the number of characters written instead of the
+         * needed size. Older MSCVRT also won't write a terminating null
+         * byte if the buffer is too small.
+         *
+         * If the value returned is non-negative and strictly less than
+         * the buffer size (without terminating null), the result should
+         * have been written completely, so we double the buffer size
+         * until this condition is true. This assumes that snprintf will
+         * eventually return a non-negative value. Otherwise, we will
+         * allocate more and more memory until we run out.
+         *
+         * Note that this code path is also executed on conforming
+         * platforms if the output is the empty string.
+         */
+
+        buf = NULL;
+        size = 32;
+        while (1) {
+            buf = xmlMalloc(size);
+            if (buf == NULL)
+                return(-1);
+
+            va_copy(copy, ap);
+            res = vsnprintf((char *) buf, size, msg, copy);
+            va_end(copy);
+            if ((res >= 0) && (res < size - 1))
+                break;
+
+            if (size >= maxSize) {
+                truncated = 1;
+                break;
+            }
+
+            xmlFree(buf);
+
+            if (size > maxSize / 2)
+                size = maxSize;
+            else
+                size *= 2;
+        }
+    }
+
+    /*
+     * If the output was truncated, make sure that the buffer doesn't
+     * end with a truncated UTF-8 sequence.
+     */
+    if (truncated != 0) {
+        int i = size - 1;
+
+        while (i > 0) {
+            /* Break after ASCII */
+            if (buf[i-1] < 0x80)
+                break;
+            i -= 1;
+            /* Break before non-ASCII */
+            if (buf[i] >= 0xc0)
+                break;
+        }
+
+        buf[i] = 0;
+    }
+
+    *out = (xmlChar *) buf;
+    return(truncated);
+}
+
+/**
+ * xmlStrASPrintf:
+ * @out:  pointer to the resulting string
+ * @maxSize:  maximum size of the output buffer
+ * @fmt:  printf format string
+ * @ap:  arguments for format string
+ *
+ * See xmlStrVASPrintf.
+ *
+ * Returns 0 on success, 1 if the result was truncated or on other
+ * errors, -1 if a memory allocation failed.
+ */
+int
+xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...) {
+    va_list ap;
+    int ret;
+
+    va_start(ap, msg);
+    ret = xmlStrVASPrintf(out, maxSize, msg, ap);
+    va_end(ap);
+
+    return(ret);
+}
+
 /************************************************************************
  *                                                                      *
  *              Generic UTF8 handling routines                          *
diff --git a/src/xmlwriter.c b/src/xmlwriter.c
index 686c99e..a63a69f 100644
--- a/src/xmlwriter.c
+++ b/src/xmlwriter.c
@@ -15,6 +15,7 @@
 
 #include <libxml/xmlmemory.h>
 #include <libxml/parser.h>
+#include <libxml/parserInternals.h>
 #include <libxml/uri.h>
 #include <libxml/HTMLtree.h>
 #include <libxml/SAX2.h>
@@ -4236,6 +4237,35 @@
 }
 
 /**
+ * xmlTextWriterClose:
+ * @writer:  the xmlTextWriterPtr
+ *
+ * Flushes and closes the output buffer.
+ *
+ * Available since 2.13.0.
+ *
+ * Returns an xmlParserErrors code.
+ */
+int
+xmlTextWriterClose(xmlTextWriterPtr writer)
+{
+    int result;
+
+    if ((writer == NULL) || (writer->out == NULL))
+        return XML_ERR_ARGUMENT;
+
+    result = xmlOutputBufferClose(writer->out);
+    writer->out = NULL;
+
+    if (result >= 0)
+        result = XML_ERR_OK;
+    else
+        result = -result;
+
+    return result;
+}
+
+/**
  * misc
  */
 
@@ -4503,28 +4533,17 @@
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
     xmlDocPtr doc;
 
-    if (ctxt->html) {
 #ifdef LIBXML_HTML_ENABLED
+    if (ctxt->html) {
         if (ctxt->myDoc == NULL)
             ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
         if (ctxt->myDoc == NULL) {
-            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-                ctxt->sax->error(ctxt->userData,
-                                 "SAX.startDocument(): out of memory\n");
-            ctxt->errNo = XML_ERR_NO_MEMORY;
-            ctxt->instate = XML_PARSER_EOF;
-            ctxt->disableSAX = 1;
+            xmlCtxtErrMemory(ctxt);
             return;
         }
-#else
-        xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR,
-                        "libxml2 built without HTML support\n");
-        ctxt->errNo = XML_ERR_INTERNAL_ERROR;
-        ctxt->instate = XML_PARSER_EOF;
-        ctxt->disableSAX = 1;
-        return;
+    } else
 #endif
-    } else {
+    {
         doc = ctxt->myDoc;
         if (doc == NULL)
             doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
@@ -4537,12 +4556,7 @@
                 doc->standalone = ctxt->standalone;
             }
         } else {
-            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-                ctxt->sax->error(ctxt->userData,
-                                 "SAX.startDocument(): out of memory\n");
-            ctxt->errNo = XML_ERR_NO_MEMORY;
-            ctxt->instate = XML_PARSER_EOF;
-            ctxt->disableSAX = 1;
+            xmlCtxtErrMemory(ctxt);
             return;
         }
     }
diff --git a/src/xpath.c b/src/xpath.c
index c642d37..3bff0d5 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -58,11 +58,6 @@
 #endif
 #endif
 
-#define TODO								\
-    xmlGenericError(xmlGenericErrorContext,				\
-	    "Unimplemented block at %s:%d\n",				\
-            __FILE__, __LINE__);
-
 /**
  * WITH_TIM_SORT:
  *
@@ -634,24 +629,12 @@
  * Handle a memory allocation failure.
  */
 void
-xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
+xmlXPathErrMemory(xmlXPathContextPtr ctxt)
 {
-    if (ctxt != NULL) {
-        xmlResetError(&ctxt->lastError);
-        if (extra) {
-            xmlChar buf[200];
-
-            xmlStrPrintf(buf, 200,
-                         "Memory allocation failed : %s\n",
-                         extra);
-            ctxt->lastError.message = (char *) xmlStrdup(buf);
-        } else {
-            ctxt->lastError.message = (char *)
-	       xmlStrdup(BAD_CAST "Memory allocation failed\n");
-        }
-        ctxt->lastError.domain = XML_FROM_XPATH;
-        ctxt->lastError.code = XML_ERR_NO_MEMORY;
-    }
+    if (ctxt == NULL)
+        return;
+    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
+                        &ctxt->lastError);
 }
 
 /**
@@ -662,12 +645,12 @@
  * Handle a memory allocation failure.
  */
 void
-xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
+xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
 {
-    if (ctxt != NULL) {
-	ctxt->error = XPATH_MEMORY_ERROR;
-	xmlXPathErrMemory(ctxt->context, extra);
-    }
+    if (ctxt == NULL)
+        return;
+    ctxt->error = XPATH_MEMORY_ERROR;
+    xmlXPathErrMemory(ctxt->context);
 }
 
 /**
@@ -680,70 +663,63 @@
 void
 xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
 {
-    xmlErrorPtr err;
+    xmlStructuredErrorFunc schannel = NULL;
+    xmlGenericErrorFunc channel = NULL;
+    void *data = NULL;
+    xmlNodePtr node = NULL;
+    int res;
 
+    if (ctxt == NULL)
+        return;
     if ((code < 0) || (code > MAXERRNO))
 	code = MAXERRNO;
-    if (ctxt == NULL) {
-	__xmlRaiseError(NULL, NULL, NULL,
-			NULL, NULL, XML_FROM_XPATH,
-			code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
-			XML_ERR_ERROR, NULL, 0,
-			NULL, NULL, NULL, 0, 0,
-			"%s", xmlXPathErrorMessages[code]);
-	return;
-    }
     /* Only report the first error */
     if (ctxt->error != 0)
         return;
+
     ctxt->error = code;
-    if (ctxt->context == NULL) {
-	__xmlRaiseError(NULL, NULL, NULL,
-			NULL, NULL, XML_FROM_XPATH,
-			code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
-			XML_ERR_ERROR, NULL, 0,
-			(const char *) ctxt->base, NULL, NULL,
-			ctxt->cur - ctxt->base, 0,
-			"%s", xmlXPathErrorMessages[code]);
-	return;
-    }
 
-    err = &ctxt->context->lastError;
-    /* Don't overwrite memory error. */
-    if (err->code == XML_ERR_NO_MEMORY)
-        return;
+    if (ctxt->context != NULL) {
+        xmlErrorPtr err = &ctxt->context->lastError;
 
-    /* cleanup current last error */
-    xmlResetError(err);
-
-    err->domain = XML_FROM_XPATH;
-    err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
-    err->level = XML_ERR_ERROR;
-    if (ctxt->base != NULL) {
-        err->str1 = (char *) xmlStrdup(ctxt->base);
-        if (err->str1 == NULL) {
-            xmlXPathPErrMemory(ctxt, NULL);
+        /* Don't overwrite memory error. */
+        if (err->code == XML_ERR_NO_MEMORY)
             return;
+
+        /* cleanup current last error */
+        xmlResetError(err);
+
+        err->domain = XML_FROM_XPATH;
+        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
+        err->level = XML_ERR_ERROR;
+        if (ctxt->base != NULL) {
+            err->str1 = (char *) xmlStrdup(ctxt->base);
+            if (err->str1 == NULL) {
+                xmlXPathPErrMemory(ctxt);
+                return;
+            }
         }
-    }
-    err->int1 = ctxt->cur - ctxt->base;
-    err->node = ctxt->context->debugNode;
-    if (ctxt->context->error != NULL) {
-	ctxt->context->error(ctxt->context->userData, err);
-    } else {
-        int res;
+        err->int1 = ctxt->cur - ctxt->base;
+        err->node = ctxt->context->debugNode;
 
-	res = __xmlRaiseError(NULL, NULL, NULL,
-			NULL, ctxt->context->debugNode, XML_FROM_XPATH,
-			code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
-			XML_ERR_ERROR, NULL, 0,
-			(const char *) ctxt->base, NULL, NULL,
-			ctxt->cur - ctxt->base, 0,
-			"%s", xmlXPathErrorMessages[code]);
-        if (res < 0)
-            xmlXPathPErrMemory(ctxt, NULL);
+        schannel = ctxt->context->error;
+        data = ctxt->context->userData;
+        node = ctxt->context->debugNode;
     }
 
+    if (schannel == NULL) {
+        channel = xmlGenericError;
+        data = xmlGenericErrorContext;
+    }
+
+    res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
+                          code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
+                          XML_ERR_ERROR, NULL, 0,
+                          (const char *) ctxt->base, NULL, NULL,
+                          ctxt->cur - ctxt->base, 0,
+                          "%s", xmlXPathErrorMessages[code]);
+    if (res < 0)
+        xmlXPathPErrMemory(ctxt);
 }
 
 /**
@@ -885,8 +861,7 @@
  *			Forward declarations				*
  *									*
  ************************************************************************/
-static void
-xmlXPathFreeValueTree(xmlNodeSetPtr obj);
+
 static void
 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
 static int
@@ -1009,7 +984,7 @@
 	xmlXPathStepOp *real;
 
         if (comp->maxStep >= XPATH_MAX_STEPS) {
-	    xmlXPathPErrMemory(ctxt, "adding step\n");
+	    xmlXPathPErrMemory(ctxt);
 	    return(-1);
         }
 	comp->maxStep *= 2;
@@ -1017,7 +992,7 @@
 		                      comp->maxStep * sizeof(xmlXPathStepOp));
 	if (real == NULL) {
 	    comp->maxStep /= 2;
-	    xmlXPathPErrMemory(ctxt, "adding step\n");
+	    xmlXPathPErrMemory(ctxt);
 	    return(-1);
 	}
 	comp->steps = real;
@@ -1120,11 +1095,6 @@
  *									*
  ************************************************************************/
 
-#define STRANGE							\
-    xmlGenericError(xmlGenericErrorContext,				\
-	    "Internal error at %s:%d\n",				\
-            __FILE__, __LINE__);
-
 #ifdef LIBXML_DEBUG_ENABLED
 static void
 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
@@ -1664,7 +1634,7 @@
 	if (ctxt->cache == NULL) {
 	    ctxt->cache = xmlXPathNewCache();
 	    if (ctxt->cache == NULL) {
-                xmlXPathErrMemory(ctxt, NULL);
+                xmlXPathErrMemory(ctxt);
 		return(-1);
             }
 	}
@@ -1717,7 +1687,7 @@
 
     ret = xmlXPathWrapNodeSet(val);
     if (ret == NULL)
-        xmlXPathPErrMemory(pctxt, NULL);
+        xmlXPathPErrMemory(pctxt);
     return(ret);
 }
 
@@ -1752,7 +1722,7 @@
 
     ret = xmlXPathWrapString(val);
     if (ret == NULL)
-        xmlXPathPErrMemory(pctxt, NULL);
+        xmlXPathPErrMemory(pctxt);
     return(ret);
 }
 
@@ -1791,7 +1761,7 @@
 		    (val->type == XML_NAMESPACE_DECL))
 		{
 		    if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
-                        xmlXPathPErrMemory(pctxt, NULL);
+                        xmlXPathPErrMemory(pctxt);
 		} else {
 		    ret->nodesetval->nodeTab[0] = val;
 		    ret->nodesetval->nodeNr = 1;
@@ -1806,7 +1776,7 @@
 
 	    set = xmlXPathNodeSetCreate(val);
 	    if (set == NULL) {
-                xmlXPathPErrMemory(pctxt, NULL);
+                xmlXPathPErrMemory(pctxt);
 		return(NULL);
 	    }
 
@@ -1822,7 +1792,7 @@
     }
     ret = xmlXPathNewNodeSet(val);
     if (ret == NULL)
-        xmlXPathPErrMemory(pctxt, NULL);
+        xmlXPathPErrMemory(pctxt);
     return(ret);
 }
 
@@ -1852,7 +1822,7 @@
                 val = BAD_CAST "";
             copy = xmlStrdup(val);
             if (copy == NULL) {
-                xmlXPathPErrMemory(pctxt, NULL);
+                xmlXPathPErrMemory(pctxt);
                 return(NULL);
             }
 
@@ -1867,7 +1837,7 @@
 
     ret = xmlXPathNewString(val);
     if (ret == NULL)
-        xmlXPathPErrMemory(pctxt, NULL);
+        xmlXPathPErrMemory(pctxt);
     return(ret);
 }
 
@@ -1919,7 +1889,7 @@
 
     ret = xmlXPathNewBoolean(val);
     if (ret == NULL)
-        xmlXPathPErrMemory(pctxt, NULL);
+        xmlXPathPErrMemory(pctxt);
     return(ret);
 }
 
@@ -1955,7 +1925,7 @@
 
     ret = xmlXPathNewFloat(val);
     if (ret == NULL)
-        xmlXPathPErrMemory(pctxt, NULL);
+        xmlXPathPErrMemory(pctxt);
     return(ret);
 }
 
@@ -1985,7 +1955,7 @@
 
                 set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
                 if (set == NULL) {
-                    xmlXPathPErrMemory(pctxt, NULL);
+                    xmlXPathPErrMemory(pctxt);
                     return(NULL);
                 }
                 return(xmlXPathCacheWrapNodeSet(pctxt, set));
@@ -2002,7 +1972,7 @@
     }
     ret = xmlXPathObjectCopy(val);
     if (ret == NULL)
-        xmlXPathPErrMemory(pctxt, NULL);
+        xmlXPathPErrMemory(pctxt);
     return(ret);
 }
 
@@ -2038,7 +2008,7 @@
 
 	str = xmlXPathCastNodeSetToString(val->nodesetval);
         if (str == NULL) {
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
             ret = xmlXPathNAN;
         } else {
 	    ret = xmlXPathCastStringToNumber(str);
@@ -2061,7 +2031,7 @@
     case XPATH_RANGE:
     case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-	TODO;
+	/* TODO */
 	ret = xmlXPathNAN;
 	break;
     }
@@ -2113,14 +2083,14 @@
         /*
          * A NULL value typically indicates that a memory allocation failed.
          */
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
         return(-1);
     }
     if (ctxt->valueNr >= ctxt->valueMax) {
         xmlXPathObjectPtr *tmp;
 
         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
-            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
+            xmlXPathPErrMemory(ctxt);
             xmlXPathFreeObject(value);
             return (-1);
         }
@@ -2128,7 +2098,7 @@
                                              2 * ctxt->valueMax *
                                              sizeof(ctxt->valueTab[0]));
         if (tmp == NULL) {
-            xmlXPathPErrMemory(ctxt, "pushing value\n");
+            xmlXPathPErrMemory(ctxt);
             xmlXPathFreeObject(value);
             return (-1);
         }
@@ -2215,7 +2185,7 @@
     }
     ret = xmlXPathCastToString(obj);
     if (ret == NULL)
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
     xmlXPathReleaseObject(ctxt->context, obj);
     return(ret);
 }
@@ -3409,34 +3379,6 @@
 }
 
 /**
- * xmlXPathFreeValueTree:
- * @obj:  the xmlNodeSetPtr to free
- *
- * Free the NodeSet compound and the actual tree, this is different
- * from xmlXPathFreeNodeSet()
- */
-static void
-xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
-    int i;
-
-    if (obj == NULL) return;
-
-    if (obj->nodeTab != NULL) {
-	for (i = 0;i < obj->nodeNr;i++) {
-	    if (obj->nodeTab[i] != NULL) {
-		if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
-		    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
-		} else {
-		    xmlFreeNodeList(obj->nodeTab[i]);
-		}
-	    }
-	}
-	xmlFree(obj->nodeTab);
-    }
-    xmlFree(obj);
-}
-
-/**
  * xmlXPathNewNodeSet:
  * @val:  the NodePtr value
  *
@@ -3477,18 +3419,11 @@
 xmlXPathNewValueTree(xmlNodePtr val) {
     xmlXPathObjectPtr ret;
 
-    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    ret = xmlXPathNewNodeSet(val);
     if (ret == NULL)
 	return(NULL);
-    memset(ret, 0 , sizeof(xmlXPathObject));
     ret->type = XPATH_XSLT_TREE;
-    ret->boolval = 1;
-    ret->user = (void *) val;
-    ret->nodesetval = xmlXPathNodeSetCreate(val);
-    if (ret->nodesetval == NULL) {
-        xmlFree(ret);
-        return(NULL);
-    }
+
     return(ret);
 }
 
@@ -4000,7 +3935,7 @@
     if (ctxt->funcHash == NULL)
 	ctxt->funcHash = xmlHashCreate(0);
     if (ctxt->funcHash == NULL) {
-        xmlXPathErrMemory(ctxt, NULL);
+        xmlXPathErrMemory(ctxt);
 	return(-1);
     }
     if (f == NULL)
@@ -4009,7 +3944,7 @@
     ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
 XML_POP_WARNINGS
     if (ret < 0) {
-        xmlXPathErrMemory(ctxt, NULL);
+        xmlXPathErrMemory(ctxt);
         return(-1);
     }
 
@@ -4286,7 +4221,7 @@
     if (ctxt->nsHash == NULL)
 	ctxt->nsHash = xmlHashCreate(10);
     if (ctxt->nsHash == NULL) {
-        xmlXPathErrMemory(ctxt, NULL);
+        xmlXPathErrMemory(ctxt);
 	return(-1);
     }
     if (ns_uri == NULL)
@@ -4295,12 +4230,12 @@
 
     copy = xmlStrdup(ns_uri);
     if (copy == NULL) {
-        xmlXPathErrMemory(ctxt, NULL);
+        xmlXPathErrMemory(ctxt);
         return(-1);
     }
     if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
                            xmlHashDefaultDeallocator) < 0) {
-        xmlXPathErrMemory(ctxt, NULL);
+        xmlXPathErrMemory(ctxt);
         xmlFree(copy);
         return(-1);
     }
@@ -4594,10 +4529,9 @@
         case XPATH_USERS:
 	    ret->user = val->user;
 	    break;
-        case XPATH_UNDEFINED:
-	    xmlGenericError(xmlGenericErrorContext,
-		    "xmlXPathObjectCopy: unsupported type %d\n",
-		    val->type);
+        default:
+            xmlFree(ret);
+            ret = NULL;
 	    break;
     }
     return(ret);
@@ -4613,20 +4547,8 @@
 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
     if (obj == NULL) return;
     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
-	if (obj->boolval) {
-#if 0
-	    if (obj->user != NULL) {
-                xmlXPathFreeNodeSet(obj->nodesetval);
-		xmlFreeNodeList((xmlNodePtr) obj->user);
-	    } else
-#endif
-	    obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
-	    if (obj->nodesetval != NULL)
-		xmlXPathFreeValueTree(obj->nodesetval);
-	} else {
-	    if (obj->nodesetval != NULL)
-		xmlXPathFreeNodeSet(obj->nodesetval);
-	}
+        if (obj->nodesetval != NULL)
+            xmlXPathFreeNodeSet(obj->nodesetval);
 #ifdef LIBXML_XPTR_LOCS_ENABLED
     } else if (obj->type == XPATH_LOCATIONSET) {
 	if (obj->user != NULL)
@@ -4666,17 +4588,8 @@
 	    case XPATH_NODESET:
 	    case XPATH_XSLT_TREE:
 		if (obj->nodesetval != NULL) {
-		    if (obj->boolval) {
-			/*
-			* It looks like the @boolval is used for
-			* evaluation if this an XSLT Result Tree Fragment.
-			* TODO: Check if this assumption is correct.
-			*/
-			obj->type = XPATH_XSLT_TREE; /* just for debugging */
-			xmlXPathFreeValueTree(obj->nodesetval);
-			obj->nodesetval = NULL;
-		    } else if ((obj->nodesetval->nodeMax <= 40) &&
-			       (cache->numNodeset < cache->maxNodeset)) {
+		    if ((obj->nodesetval->nodeMax <= 40) &&
+			(cache->numNodeset < cache->maxNodeset)) {
                         obj->stringval = (void *) cache->nodesetObjs;
                         cache->nodesetObjs = obj;
                         cache->numNodeset += 1;
@@ -4882,7 +4795,7 @@
 	case XPATH_RANGE:
 	case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-	    TODO
+	    /* TODO */
 	    ret = xmlStrdup((const xmlChar *) "");
 	    break;
     }
@@ -4926,7 +4839,7 @@
     case XPATH_RANGE:
     case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-	TODO;
+	/* TODO */
 	break;
     }
     xmlXPathFreeObject(val);
@@ -4980,7 +4893,7 @@
 	return(xmlXPathNAN);
     strval = xmlXPathCastNodeToString(node);
     if (strval == NULL) {
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
 	return(xmlXPathNAN);
     }
     ret = xmlXPathCastStringToNumber(strval);
@@ -5140,7 +5053,7 @@
     case XPATH_RANGE:
     case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-	TODO;
+	/* TODO */
 	ret = 0;
 	break;
     }
@@ -5247,43 +5160,33 @@
     xmlFree(ctxt);
 }
 
+/**
+ * xmlXPathSetErrorHandler:
+ * @ctxt:  the XPath context
+ * @handler:  error handler
+ * @data:  user data which will be passed to the handler
+ *
+ * Register a callback function that will be called on errors and
+ * warnings. If handler is NULL, the error handler will be deactivated.
+ *
+ * Available since 2.13.0.
+ */
+void
+xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
+                        xmlStructuredErrorFunc handler, void *data) {
+    if (ctxt == NULL)
+        return;
+
+    ctxt->error = handler;
+    ctxt->userData = data;
+}
+
 /************************************************************************
  *									*
  *		Routines to handle XPath parser contexts		*
  *									*
  ************************************************************************/
 
-#define CHECK_CTXT(ctxt)						\
-    if (ctxt == NULL) {						\
-	__xmlRaiseError(NULL, NULL, NULL,				\
-		NULL, NULL, XML_FROM_XPATH,				\
-		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
-		__FILE__, __LINE__,					\
-		NULL, NULL, NULL, 0, 0,					\
-		"NULL context pointer\n");				\
-	return(NULL);							\
-    }									\
-
-#define CHECK_CTXT_NEG(ctxt)						\
-    if (ctxt == NULL) {						\
-	__xmlRaiseError(NULL, NULL, NULL,				\
-		NULL, NULL, XML_FROM_XPATH,				\
-		XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,			\
-		__FILE__, __LINE__,					\
-		NULL, NULL, NULL, 0, 0,					\
-		"NULL context pointer\n");				\
-	return(-1);							\
-    }									\
-
-
-#define CHECK_CONTEXT(ctxt)						\
-    if ((ctxt == NULL) || (ctxt->doc == NULL) ||			\
-        (ctxt->doc->children == NULL)) {				\
-	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);	\
-	return(NULL);							\
-    }
-
-
 /**
  * xmlXPathNewParserContext:
  * @str:  the XPath expression
@@ -5299,7 +5202,7 @@
 
     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
     if (ret == NULL) {
-        xmlXPathErrMemory(ctxt, "creating parser context\n");
+        xmlXPathErrMemory(ctxt);
 	return(NULL);
     }
     memset(ret, 0 , sizeof(xmlXPathParserContext));
@@ -5308,7 +5211,7 @@
 
     ret->comp = xmlXPathNewCompExpr();
     if (ret->comp == NULL) {
-        xmlXPathErrMemory(ctxt, NULL);
+        xmlXPathErrMemory(ctxt);
 	xmlFree(ret->valueTab);
 	xmlFree(ret);
 	return(NULL);
@@ -5336,7 +5239,7 @@
 
     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
     if (ret == NULL) {
-        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
+        xmlXPathErrMemory(ctxt);
 	return(NULL);
     }
     memset(ret, 0 , sizeof(xmlXPathParserContext));
@@ -5346,7 +5249,7 @@
                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
     if (ret->valueTab == NULL) {
 	xmlFree(ret);
-	xmlXPathErrMemory(ctxt, "creating evaluation context\n");
+	xmlXPathErrMemory(ctxt);
 	return(NULL);
     }
     ret->valueNr = 0;
@@ -5575,7 +5478,7 @@
 		 if (ret)
 		     break;
 	     } else {
-                 xmlXPathPErrMemory(ctxt, NULL);
+                 xmlXPathPErrMemory(ctxt);
              }
 	}
     }
@@ -5631,7 +5534,7 @@
 		 if (ret)
 		     break;
 	     } else {
-                 xmlXPathPErrMemory(ctxt, NULL);
+                 xmlXPathPErrMemory(ctxt);
              }
 	}
     }
@@ -5706,7 +5609,7 @@
 
     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
     if (values2 == NULL) {
-        xmlXPathPErrMemory(ctxt, "comparing nodesets\n");
+        xmlXPathPErrMemory(ctxt);
 	xmlXPathFreeObject(arg1);
 	xmlXPathFreeObject(arg2);
 	return(0);
@@ -5785,10 +5688,6 @@
 	    valuePush(ctxt, val);
 	    return(xmlXPathCompareValues(ctxt, inf, strict));
 	default:
-            xmlGenericError(xmlGenericErrorContext,
-                    "xmlXPathCompareNodeSetValue: Can't compare node set "
-                    "and object of type %d\n",
-                    val->type);
             xmlXPathReleaseObject(ctxt->context, arg);
             xmlXPathReleaseObject(ctxt->context, val);
             XP_ERROR0(XPATH_INVALID_TYPE);
@@ -5834,7 +5733,7 @@
         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
             str2 = xmlNodeGetContent(ns->nodeTab[i]);
             if (str2 == NULL) {
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
                 return(0);
             }
             if (xmlStrEqual(str, str2)) {
@@ -5906,7 +5805,7 @@
 			ret = 1;
 		}
 	    } else {
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
             }
 	}
     }
@@ -5970,26 +5869,26 @@
 
     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
     if (values1 == NULL) {
-        xmlXPathPErrMemory(ctxt, "comparing nodesets\n");
+        xmlXPathPErrMemory(ctxt);
 	return(0);
     }
     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
     if (hashs1 == NULL) {
-        xmlXPathPErrMemory(ctxt, "comparing nodesets\n");
+        xmlXPathPErrMemory(ctxt);
 	xmlFree(values1);
 	return(0);
     }
     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
     if (values2 == NULL) {
-        xmlXPathPErrMemory(ctxt, "comparing nodesets\n");
+        xmlXPathPErrMemory(ctxt);
 	xmlFree(hashs1);
 	xmlFree(values1);
 	return(0);
     }
     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
     if (hashs2 == NULL) {
-        xmlXPathPErrMemory(ctxt, "comparing nodesets\n");
+        xmlXPathPErrMemory(ctxt);
 	xmlFree(hashs1);
 	xmlFree(values1);
 	xmlFree(values2);
@@ -6011,12 +5910,12 @@
 		if (values1[i] == NULL) {
 		    values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
                     if (values1[i] == NULL)
-                        xmlXPathPErrMemory(ctxt, NULL);
+                        xmlXPathPErrMemory(ctxt);
                 }
 		if (values2[j] == NULL) {
 		    values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
                     if (values2[j] == NULL)
-                        xmlXPathPErrMemory(ctxt, NULL);
+                        xmlXPathPErrMemory(ctxt);
                 }
 		ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
 		if (ret)
@@ -6074,7 +5973,7 @@
 		case XPATH_RANGE:
 		case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-		    TODO
+		    /* TODO */
 		    break;
 		case XPATH_NODESET:
 		case XPATH_XSLT_TREE:
@@ -6131,7 +6030,7 @@
 		case XPATH_RANGE:
 		case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-		    TODO
+		    /* TODO */
 		    break;
 		case XPATH_NODESET:
 		case XPATH_XSLT_TREE:
@@ -6192,7 +6091,7 @@
 		case XPATH_RANGE:
 		case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-		    TODO
+		    /* TODO */
 		    break;
 		case XPATH_NODESET:
 		case XPATH_XSLT_TREE:
@@ -6205,7 +6104,7 @@
 	case XPATH_RANGE:
 	case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-	    TODO
+	    /* TODO */
 	    break;
 	case XPATH_NODESET:
 	case XPATH_XSLT_TREE:
@@ -6285,7 +6184,7 @@
 	    case XPATH_RANGE:
 	    case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-		TODO
+		/* TODO */
 		break;
 	}
 	xmlXPathReleaseObject(ctxt->context, arg1);
@@ -6365,7 +6264,7 @@
 	    case XPATH_RANGE:
 	    case XPATH_LOCATIONSET:
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
-		TODO
+		/* TODO */
 		break;
 	}
 	xmlXPathReleaseObject(ctxt->context, arg1);
@@ -7437,7 +7336,7 @@
 	ctxt->context->tmpNsNr = 0;
         if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
                              &ctxt->context->tmpNsList) < 0) {
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
             return(NULL);
         }
         if (ctxt->context->tmpNsList != NULL) {
@@ -7684,20 +7583,20 @@
 
 	ret = xmlXPathNodeSetCreate(NULL);
         if (ret == NULL)
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
 
 	if (obj->nodesetval != NULL) {
 	    for (i = 0; i < obj->nodesetval->nodeNr; i++) {
 		tokens =
 		    xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
                 if (tokens == NULL)
-                    xmlXPathPErrMemory(ctxt, NULL);
+                    xmlXPathPErrMemory(ctxt);
 		ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
                 if (ns == NULL)
-                    xmlXPathPErrMemory(ctxt, NULL);
+                    xmlXPathPErrMemory(ctxt);
 		ret = xmlXPathNodeSetMerge(ret, ns);
                 if (ret == NULL)
-                    xmlXPathPErrMemory(ctxt, NULL);
+                    xmlXPathPErrMemory(ctxt);
 		xmlXPathFreeNodeSet(ns);
 		if (tokens != NULL)
 		    xmlFree(tokens);
@@ -7709,11 +7608,11 @@
     }
     tokens = xmlXPathCastToString(obj);
     if (tokens == NULL)
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
     xmlXPathReleaseObject(ctxt->context, obj);
     ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
     if (ret == NULL)
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
     xmlFree(tokens);
     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
     return;
@@ -7889,7 +7788,7 @@
 		    if (fullname == cur->nodesetval->nodeTab[i]->name)
 			fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
 		    if (fullname == NULL)
-                        xmlXPathPErrMemory(ctxt, NULL);
+                        xmlXPathPErrMemory(ctxt);
 		    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
                 }
                 break;
@@ -7948,7 +7847,7 @@
     if (nargs == 0) {
         stringval = xmlXPathCastNodeToString(ctxt->context->node);
         if (stringval == NULL)
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
 	return;
     }
@@ -7959,7 +7858,7 @@
     if (cur->type != XPATH_STRING) {
         stringval = xmlXPathCastToString(cur);
         if (stringval == NULL)
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
         xmlXPathReleaseObject(ctxt->context, cur);
         cur = xmlXPathCacheWrapString(ctxt, stringval);
     }
@@ -7992,7 +7891,7 @@
 
 	    content = xmlXPathCastNodeToString(ctxt->context->node);
             if (content == NULL)
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
 		xmlUTF8Strlen(content)));
 	    xmlFree(content);
@@ -8045,7 +7944,7 @@
 	}
 	tmp = xmlStrcat(newobj->stringval, cur->stringval);
         if (tmp == NULL)
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
 	newobj->stringval = cur->stringval;
 	cur->stringval = tmp;
 	xmlXPathReleaseObject(ctxt->context, newobj);
@@ -8217,7 +8116,7 @@
     if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
         xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
         if (ret == NULL)
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
 	valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
 	xmlFree(ret);
     } else {
@@ -8242,30 +8141,34 @@
  */
 void
 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
-  xmlXPathObjectPtr str;
-  xmlXPathObjectPtr find;
-  xmlBufPtr target;
-  const xmlChar *point;
-  int offset;
+    xmlXPathObjectPtr str = NULL;
+    xmlXPathObjectPtr find = NULL;
+    const xmlChar *point;
+    xmlChar *result;
 
-  CHECK_ARITY(2);
-  CAST_TO_STRING;
-  find = valuePop(ctxt);
-  CAST_TO_STRING;
-  str = valuePop(ctxt);
+    CHECK_ARITY(2);
+    CAST_TO_STRING;
+    find = valuePop(ctxt);
+    CAST_TO_STRING;
+    str = valuePop(ctxt);
+    if (ctxt->error != 0)
+        goto error;
 
-  target = xmlBufCreate();
-  if (target) {
     point = xmlStrstr(str->stringval, find->stringval);
-    if (point) {
-      offset = point - str->stringval;
-      xmlBufAdd(target, str->stringval, offset);
+    if (point == NULL) {
+        result = xmlStrdup(BAD_CAST "");
+    } else {
+        result = xmlStrndup(str->stringval, point - str->stringval);
     }
-    valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
-    xmlBufFree(target);
-  }
-  xmlXPathReleaseObject(ctxt->context, str);
-  xmlXPathReleaseObject(ctxt->context, find);
+    if (result == NULL) {
+        xmlXPathPErrMemory(ctxt);
+        goto error;
+    }
+    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
+
+error:
+    xmlXPathReleaseObject(ctxt->context, str);
+    xmlXPathReleaseObject(ctxt->context, find);
 }
 
 /**
@@ -8277,38 +8180,41 @@
  *    string substring-after(string, string)
  * The substring-after function returns the substring of the first
  * argument string that follows the first occurrence of the second
- * argument string in the first argument string, or the empty stringi
+ * argument string in the first argument string, or the empty string
  * if the first argument string does not contain the second argument
  * string. For example, substring-after("1999/04/01","/") returns 04/01,
  * and substring-after("1999/04/01","19") returns 99/04/01.
  */
 void
 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
-  xmlXPathObjectPtr str;
-  xmlXPathObjectPtr find;
-  xmlBufPtr target;
-  const xmlChar *point;
-  int offset;
+    xmlXPathObjectPtr str = NULL;
+    xmlXPathObjectPtr find = NULL;
+    const xmlChar *point;
+    xmlChar *result;
 
-  CHECK_ARITY(2);
-  CAST_TO_STRING;
-  find = valuePop(ctxt);
-  CAST_TO_STRING;
-  str = valuePop(ctxt);
+    CHECK_ARITY(2);
+    CAST_TO_STRING;
+    find = valuePop(ctxt);
+    CAST_TO_STRING;
+    str = valuePop(ctxt);
+    if (ctxt->error != 0)
+        goto error;
 
-  target = xmlBufCreate();
-  if (target) {
     point = xmlStrstr(str->stringval, find->stringval);
-    if (point) {
-      offset = point - str->stringval + xmlStrlen(find->stringval);
-      xmlBufAdd(target, &str->stringval[offset],
-		   xmlStrlen(str->stringval) - offset);
+    if (point == NULL) {
+        result = xmlStrdup(BAD_CAST "");
+    } else {
+        result = xmlStrdup(point + xmlStrlen(find->stringval));
     }
-    valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
-    xmlBufFree(target);
-  }
-  xmlXPathReleaseObject(ctxt->context, str);
-  xmlXPathReleaseObject(ctxt->context, find);
+    if (result == NULL) {
+        xmlXPathPErrMemory(ctxt);
+        goto error;
+    }
+    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
+
+error:
+    xmlXPathReleaseObject(ctxt->context, str);
+    xmlXPathReleaseObject(ctxt->context, find);
 }
 
 /**
@@ -8335,7 +8241,7 @@
         /* Use current context node */
         source = xmlXPathCastNodeToString(ctxt->context->node);
         if (source == NULL)
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
         valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
         nargs = 1;
     }
@@ -8392,14 +8298,14 @@
  */
 void
 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
-    xmlXPathObjectPtr str;
-    xmlXPathObjectPtr from;
-    xmlXPathObjectPtr to;
+    xmlXPathObjectPtr str = NULL;
+    xmlXPathObjectPtr from = NULL;
+    xmlXPathObjectPtr to = NULL;
     xmlBufPtr target;
     int offset, max;
     int ch;
     const xmlChar *point;
-    xmlChar *cptr;
+    xmlChar *cptr, *content;
 
     CHECK_ARITY(3);
 
@@ -8409,46 +8315,53 @@
     from = valuePop(ctxt);
     CAST_TO_STRING;
     str = valuePop(ctxt);
+    if (ctxt->error != 0)
+        goto error;
 
     target = xmlBufCreate();
-    if (target) {
-	max = xmlUTF8Strlen(to->stringval);
-	for (cptr = str->stringval; (ch=*cptr); ) {
-	    offset = xmlUTF8Strloc(from->stringval, cptr);
-	    if (offset >= 0) {
-		if (offset < max) {
-		    point = xmlUTF8Strpos(to->stringval, offset);
-		    if (point)
-			xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
-		}
-	    } else
-		xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
-
-	    /* Step to next character in input */
-	    cptr++;
-	    if ( ch & 0x80 ) {
-		/* if not simple ascii, verify proper format */
-		if ( (ch & 0xc0) != 0xc0 ) {
-		    xmlGenericError(xmlGenericErrorContext,
-			"xmlXPathTranslateFunction: Invalid UTF8 string\n");
-                    /* not asserting an XPath error is probably better */
-		    break;
-		}
-		/* then skip over remaining bytes for this char */
-		while ( (ch <<= 1) & 0x80 )
-		    if ( (*cptr++ & 0xc0) != 0x80 ) {
-			xmlGenericError(xmlGenericErrorContext,
-			    "xmlXPathTranslateFunction: Invalid UTF8 string\n");
-                        /* not asserting an XPath error is probably better */
-			break;
-		    }
-		if (ch & 0x80) /* must have had error encountered */
-		    break;
-	    }
-	}
+    if (target == NULL) {
+        xmlXPathPErrMemory(ctxt);
+        goto error;
     }
-    valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
+
+    max = xmlUTF8Strlen(to->stringval);
+    for (cptr = str->stringval; (ch=*cptr); ) {
+        offset = xmlUTF8Strloc(from->stringval, cptr);
+        if (offset >= 0) {
+            if (offset < max) {
+                point = xmlUTF8Strpos(to->stringval, offset);
+                if (point)
+                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
+            }
+        } else
+            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
+
+        /* Step to next character in input */
+        cptr++;
+        if ( ch & 0x80 ) {
+            /* if not simple ascii, verify proper format */
+            if ( (ch & 0xc0) != 0xc0 ) {
+                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
+                break;
+            }
+            /* then skip over remaining bytes for this char */
+            while ( (ch <<= 1) & 0x80 )
+                if ( (*cptr++ & 0xc0) != 0x80 ) {
+                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
+                    break;
+                }
+            if (ch & 0x80) /* must have had error encountered */
+                break;
+        }
+    }
+
+    content = xmlBufDetach(target);
+    if (content == NULL)
+        xmlXPathPErrMemory(ctxt);
+    else
+        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
     xmlBufFree(target);
+error:
     xmlXPathReleaseObject(ctxt->context, str);
     xmlXPathReleaseObject(ctxt->context, from);
     xmlXPathReleaseObject(ctxt->context, to);
@@ -8568,7 +8481,7 @@
     while (cur != NULL) {
         if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
                                 &theLang) < 0)
-            xmlXPathPErrMemory(ctxt, NULL);
+            xmlXPathPErrMemory(ctxt);
         if (theLang != NULL)
             break;
         cur = cur->parent;
@@ -8607,6 +8520,8 @@
 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
 	} else {
 	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
+            if (content == NULL)
+                xmlXPathPErrMemory(ctxt);
 
 	    res = xmlXPathStringEvalNumber(content);
 	    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
@@ -8881,7 +8796,7 @@
 		return(NULL);
 	    ret = xmlStrndup(ctxt->cur, count);
             if (ret == NULL)
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
 	    ctxt->cur = in;
 	    return(ret);
 	}
@@ -8964,7 +8879,7 @@
             }
 	    ret = xmlStrndup(ctxt->cur, count);
             if (ret == NULL)
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
 	    ctxt->cur = in;
 	    return(ret);
 	}
@@ -9013,7 +8928,7 @@
             }
 	    buffer = (xmlChar *) xmlMallocAtomic(max);
 	    if (buffer == NULL) {
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
                 return(NULL);
 	    }
 	    memcpy(buffer, buf, len);
@@ -9032,7 +8947,7 @@
 		    tmp = (xmlChar *) xmlRealloc(buffer, max);
 		    if (tmp == NULL) {
                         xmlFree(buffer);
-                        xmlXPathPErrMemory(ctxt, NULL);
+                        xmlXPathPErrMemory(ctxt);
                         return(NULL);
 		    }
                     buffer = tmp;
@@ -9049,7 +8964,7 @@
 	return(NULL);
     ret = xmlStrndup(buf, len);
     if (ret == NULL)
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
     return(ret);
 }
 
@@ -9302,7 +9217,7 @@
     }
     ret = xmlStrndup(q, CUR_PTR - q);
     if (ret == NULL)
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
     NEXT;
     return(ret);
 }
@@ -9588,7 +9503,7 @@
     }
     ret = xmlStrndup(cur, ctxt->cur - cur);
     if (ret == NULL)
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
     ctxt->cur = cur;
     return(ret);
 }
@@ -10097,7 +10012,6 @@
     int blanks;
 
     if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
-	STRANGE;
 	return(NULL);
     }
     *type = (xmlXPathTypeVal) 0;
@@ -10646,7 +10560,7 @@
         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
                 nodeMax * sizeof(xmlNodePtr));
         if (tmp == NULL) {
-            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
+            xmlXPathPErrMemory(ctxt);
         } else {
             set->nodeTab = tmp;
             set->nodeMax = nodeMax;
@@ -10764,7 +10678,7 @@
         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
                 locMax * sizeof(xmlXPathObjectPtr));
         if (tmp == NULL) {
-            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
+            xmlXPathPErrMemory(ctxt);
         } else {
             locset->locTab = tmp;
             locset->locMax = locMax;
@@ -10804,8 +10718,6 @@
 	* Process inner predicates first.
 	*/
 	if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
-            xmlGenericError(xmlGenericErrorContext,
-                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
             XP_ERROR(XPATH_INVALID_OPERAND);
 	}
         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
@@ -10888,11 +10800,11 @@
     if (hasAxisRange != 0) { \
 	if (++pos == maxPos) { \
 	    if (addNode(seq, cur) < 0) \
-	        xmlXPathPErrMemory(ctxt, NULL); \
+	        xmlXPathPErrMemory(ctxt); \
 	    goto axis_range_end; } \
     } else { \
 	if (addNode(seq, cur) < 0) \
-	    xmlXPathPErrMemory(ctxt, NULL); \
+	    xmlXPathPErrMemory(ctxt); \
 	if (breakOnFirstHit) goto first_hit; }
 
 #define XP_TEST_HIT_NS \
@@ -10900,12 +10812,12 @@
 	if (++pos == maxPos) { \
 	    hasNsNodes = 1; \
 	    if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
-	        xmlXPathPErrMemory(ctxt, NULL); \
+	        xmlXPathPErrMemory(ctxt); \
 	goto axis_range_end; } \
     } else { \
 	hasNsNodes = 1; \
 	if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
-	    xmlXPathPErrMemory(ctxt, NULL); \
+	    xmlXPathPErrMemory(ctxt); \
 	if (breakOnFirstHit) goto first_hit; }
 
     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
@@ -11045,8 +10957,7 @@
     }
     contextSeq = obj->nodesetval;
     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
-	xmlXPathReleaseObject(xpctxt, obj);
-        valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, NULL));
+        valuePush(ctxt, obj);
         return(0);
     }
     /*
@@ -11121,7 +11032,7 @@
 	if (seq == NULL) {
 	    seq = xmlXPathNodeSetCreate(NULL);
 	    if (seq == NULL) {
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
 		total = 0;
 		goto error;
 	    }
@@ -11175,7 +11086,6 @@
 	    switch (test) {
                 case NODE_TEST_NONE:
 		    total = 0;
-                    STRANGE
 		    goto error;
                 case NODE_TEST_TYPE:
 		    if (type == NODE_TYPE_NODE) {
@@ -11253,7 +11163,7 @@
                     }
                     break;
                 case NODE_TEST_NS:{
-                        TODO;
+                        /* TODO */
                         break;
                     }
                 case NODE_TEST_NAME:
@@ -11338,7 +11248,7 @@
 	} else {
 	    outSeq = mergeAndClear(outSeq, seq);
             if (outSeq == NULL)
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
         }
 	/*
 	* Break if only a true/false result was requested.
@@ -11358,7 +11268,7 @@
 	} else {
 	    outSeq = mergeAndClear(outSeq, seq);
             if (outSeq == NULL)
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
         }
 	break;
 
@@ -11421,7 +11331,7 @@
 	    } else {
 		outSeq = mergeAndClear(outSeq, seq);
                 if (outSeq == NULL)
-                    xmlXPathPErrMemory(ctxt, NULL);
+                    xmlXPathPErrMemory(ctxt);
 	    }
 
             if (toBool)
@@ -11452,7 +11362,7 @@
         } else {
 	    outSeq = xmlXPathNodeSetCreate(NULL);
             if (outSeq == NULL)
-                xmlXPathPErrMemory(ctxt, NULL);
+                xmlXPathPErrMemory(ctxt);
         }
     }
     if ((seq != NULL) && (seq != outSeq)) {
@@ -11565,7 +11475,7 @@
                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                                                         arg2->nodesetval);
                 if (arg1->nodesetval == NULL)
-                    xmlXPathPErrMemory(ctxt, NULL);
+                    xmlXPathPErrMemory(ctxt);
             }
             valuePush(ctxt, arg1);
 	    xmlXPathReleaseObject(ctxt->context, arg2);
@@ -11707,7 +11617,7 @@
                 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
                                                         arg2->nodesetval);
                 if (arg1->nodesetval == NULL)
-                    xmlXPathPErrMemory(ctxt, NULL);
+                    xmlXPathPErrMemory(ctxt);
             }
             valuePush(ctxt, arg1);
 	    xmlXPathReleaseObject(ctxt->context, arg2);
@@ -11998,7 +11908,7 @@
 		arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
 							arg2->nodesetval);
                 if (arg1->nodesetval == NULL)
-                    xmlXPathPErrMemory(ctxt, NULL);
+                    xmlXPathPErrMemory(ctxt);
 	    }
 
             valuePush(ctxt, arg1);
@@ -12046,10 +11956,7 @@
 
                     URI = xmlXPathNsLookup(ctxt->context, op->value5);
                     if (URI == NULL) {
-                        xmlGenericError(xmlGenericErrorContext,
-            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
-                                    (char *) op->value4, (char *)op->value5);
-                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
+                        XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
                         break;
                     }
 		    val = xmlXPathVariableLookupNS(ctxt->context,
@@ -12073,19 +11980,11 @@
                     if (ctxt->error != XPATH_EXPRESSION_OK)
                         break;
                 }
-		if (ctxt->valueNr < frame + op->value) {
-		    xmlGenericError(xmlGenericErrorContext,
-			    "xmlXPathCompOpEval: parameter error\n");
-		    ctxt->error = XPATH_INVALID_OPERAND;
-		    break;
-		}
+		if (ctxt->valueNr < frame + op->value)
+		    XP_ERROR0(XPATH_INVALID_OPERAND);
 		for (i = 0; i < op->value; i++) {
-		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
-			xmlGenericError(xmlGenericErrorContext,
-				"xmlXPathCompOpEval: parameter error\n");
-			ctxt->error = XPATH_INVALID_OPERAND;
-			break;
-		    }
+		    if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
+			XP_ERROR0(XPATH_INVALID_OPERAND);
                 }
                 if (op->cache != NULL)
                     func = op->cache;
@@ -12098,22 +11997,13 @@
                                                    op->value4);
                     else {
                         URI = xmlXPathNsLookup(ctxt->context, op->value5);
-                        if (URI == NULL) {
-                            xmlGenericError(xmlGenericErrorContext,
-            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
-                                    (char *)op->value4, (char *)op->value5);
-                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
-                            break;
-                        }
+                        if (URI == NULL)
+                            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
                         func = xmlXPathFunctionLookupNS(ctxt->context,
                                                         op->value4, URI);
                     }
-                    if (func == NULL) {
-                        xmlGenericError(xmlGenericErrorContext,
-                                "xmlXPathCompOpEval: function %s not found\n",
-                                        (char *)op->value4);
+                    if (func == NULL)
                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
-                    }
                     op->cache = func;
                     op->cacheURI = (void *) URI;
                 }
@@ -12443,9 +12333,7 @@
             }
 #endif /* LIBXML_XPTR_LOCS_ENABLED */
         default:
-            xmlGenericError(xmlGenericErrorContext,
-                            "XPath: unknown precompiled operation %d\n", op->op);
-            ctxt->error = XPATH_INVALID_OPERAND;
+            XP_ERROR0(XPATH_INVALID_OPERAND);
             break;
     }
 
@@ -12609,7 +12497,7 @@
 	}
 
         if (res < 0)
-            xmlXPathPErrMemory(pctxt, NULL);
+            xmlXPathPErrMemory(pctxt);
     }
     if (max_depth == 0) {
 	return(0);
@@ -12651,7 +12539,7 @@
 
     patstream = xmlPatternGetStreamCtxt(comp);
     if (patstream == NULL) {
-        xmlXPathPErrMemory(pctxt, NULL);
+        xmlXPathPErrMemory(pctxt);
 	return(-1);
     }
 
@@ -12664,7 +12552,7 @@
 	    if (toBool)
 		goto return_1;
 	    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
-                xmlXPathPErrMemory(pctxt, NULL);
+                xmlXPathPErrMemory(pctxt);
 	}
     }
     depth = 0;
@@ -12673,8 +12561,7 @@
     do {
         if (ctxt->opLimit != 0) {
             if (ctxt->opCount >= ctxt->opLimit) {
-                xmlGenericError(xmlGenericErrorContext,
-                        "XPath operation limit exceeded\n");
+                xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
                 xmlFreeStreamCtxt(patstream);
                 return(-1);
             }
@@ -12696,13 +12583,13 @@
 		    break;
 
 		if (ret < 0) {
-		    xmlXPathPErrMemory(pctxt, NULL);
+		    xmlXPathPErrMemory(pctxt);
 		} else if (ret == 1) {
 		    if (toBool)
 			goto return_1;
 		    if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
                                                  cur) < 0)
-                        xmlXPathPErrMemory(pctxt, NULL);
+                        xmlXPathPErrMemory(pctxt);
 		}
 		if ((cur->children == NULL) || (depth >= max_depth)) {
 		    ret = xmlStreamPop(patstream);
@@ -12802,7 +12689,7 @@
 	ctxt->valueTab = (xmlXPathObjectPtr *)
 			 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
 	if (ctxt->valueTab == NULL) {
-	    xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
+	    xmlXPathPErrMemory(ctxt);
 	    return(-1);
 	}
 	ctxt->valueNr = 0;
@@ -12843,8 +12730,7 @@
 #endif
     comp = ctxt->comp;
     if (comp->last < 0) {
-	xmlGenericError(xmlGenericErrorContext,
-	    "xmlXPathRunEval: last is less than zero\n");
+        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
 	return(-1);
     }
     oldDepth = ctxt->context->depth;
@@ -12897,7 +12783,7 @@
 	    return((res->stringval != NULL) &&
 	           (xmlStrlen(res->stringval) != 0));
         default:
-	    STRANGE
+	    break;
     }
     return(0);
 }
@@ -12948,7 +12834,7 @@
 	    }
 #endif
         default:
-	    STRANGE
+	    break;
     }
     return(0);
 }
@@ -13000,7 +12886,7 @@
 	    if (ctxt->nsNr > 0) {
 		namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
 		if (namespaces == NULL) {
-		    xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
+		    xmlXPathErrMemory(ctxt);
 		    return(NULL);
 		}
 		for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
@@ -13019,13 +12905,13 @@
 	    xmlFree((xmlChar **)namespaces);
 	}
         if (res < 0) {
-            xmlXPathErrMemory(ctxt, NULL);
+            xmlXPathErrMemory(ctxt);
             return(NULL);
         }
 	if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
 	    comp = xmlXPathNewCompExpr();
 	    if (comp == NULL) {
-		xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
+		xmlXPathErrMemory(ctxt);
 	        xmlFreePattern(stream);
 		return(NULL);
 	    }
@@ -13218,14 +13104,12 @@
 			     int toBool)
 {
     xmlXPathParserContextPtr pctxt;
-    xmlXPathObjectPtr resObj;
+    xmlXPathObjectPtr resObj = NULL;
 #ifndef LIBXML_THREAD_ENABLED
     static int reentance = 0;
 #endif
     int res;
 
-    CHECK_CTXT_NEG(ctxt)
-
     if (comp == NULL)
 	return(-1);
     xmlInitParser();
@@ -13243,19 +13127,11 @@
         return(-1);
     res = xmlXPathRunEval(pctxt, toBool);
 
-    if (pctxt->error != XPATH_EXPRESSION_OK) {
-        resObj = NULL;
-    } else {
-        resObj = valuePop(pctxt);
-        if (resObj == NULL) {
-            if (!toBool)
-                xmlGenericError(xmlGenericErrorContext,
-                    "xmlXPathCompiledEval: No result on the stack.\n");
-        } else if (pctxt->valueNr > 0) {
-            xmlGenericError(xmlGenericErrorContext,
-                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
-                pctxt->valueNr);
-        }
+    if (pctxt->error == XPATH_EXPRESSION_OK) {
+        if (pctxt->valueNr != ((toBool) ? 0 : 1))
+            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
+        else if (!toBool)
+            resObj = valuePop(pctxt);
     }
 
     if (resObjPtr)
@@ -13332,7 +13208,7 @@
     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
     if ((comp == NULL) &&
         (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
-        xmlXPathPErrMemory(ctxt, NULL);
+        xmlXPathPErrMemory(ctxt);
         return;
     }
     if (comp != NULL) {
@@ -13381,7 +13257,8 @@
     xmlXPathParserContextPtr ctxt;
     xmlXPathObjectPtr res;
 
-    CHECK_CTXT(ctx)
+    if (ctx == NULL)
+        return(NULL);
 
     xmlInitParser();
 
@@ -13394,16 +13271,11 @@
 
     if (ctxt->error != XPATH_EXPRESSION_OK) {
 	res = NULL;
+    } else if (ctxt->valueNr != 1) {
+        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
+	res = NULL;
     } else {
 	res = valuePop(ctxt);
-        if (res == NULL) {
-            xmlGenericError(xmlGenericErrorContext,
-                "xmlXPathEval: No result on the stack.\n");
-        } else if (ctxt->valueNr > 0) {
-            xmlGenericError(xmlGenericErrorContext,
-                "xmlXPathEval: %d object(s) left on the stack.\n",
-                ctxt->valueNr);
-        }
     }
 
     xmlXPathFreeParserContext(ctxt);
diff --git a/win32/include/libxml/xmlversion.h b/win32/include/libxml/xmlversion.h
index e2d590e..e11aa1c 100644
--- a/win32/include/libxml/xmlversion.h
+++ b/win32/include/libxml/xmlversion.h
@@ -10,20 +10,6 @@
 #ifndef __XML_VERSION_H__
 #define __XML_VERSION_H__
 
-#include <libxml/xmlexports.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * use those to be sure nothing nasty will happen if
- * your library and includes mismatch
- */
-#ifndef LIBXML2_COMPILING_MSCCDEF
-XMLPUBFUN void xmlCheckVersion(int version);
-#endif /* LIBXML2_COMPILING_MSCCDEF */
-
 /**
  * LIBXML_DOTTED_VERSION:
  *
@@ -286,15 +272,6 @@
 #endif
 
 /**
- * LIBXML_DEBUG_RUNTIME:
- *
- * Removed
- */
-#if 0
-#define LIBXML_DEBUG_RUNTIME
-#endif
-
-/**
  * LIBXML_UNICODE_ENABLED:
  *
  * Whether the Unicode related interfaces are compiled in
@@ -322,17 +299,6 @@
 #endif
 
 /**
- * LIBXML_EXPR_ENABLED:
- *
- * Whether the formal expressions interfaces are compiled in
- *
- * This code is unused and disabled unconditionally for now.
- */
-#if 0
-#define LIBXML_EXPR_ENABLED
-#endif
-
-/**
  * LIBXML_SCHEMAS_ENABLED:
  *
  * Whether the Schemas validation interfaces are compiled in
@@ -383,108 +349,8 @@
 #define LIBXML_LZMA_ENABLED
 #endif
 
-#ifdef __GNUC__
-/** DOC_DISABLE */
+#include <libxml/xmlexports.h>
 
-#ifndef ATTRIBUTE_UNUSED
-# if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7)))
-#  define ATTRIBUTE_UNUSED __attribute__((unused))
-# else
-#  define ATTRIBUTE_UNUSED
-# endif
-#endif
-
-#ifndef LIBXML_ATTR_ALLOC_SIZE
-# if (!defined(__clang__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3))))
-#  define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x)))
-# else
-#  define LIBXML_ATTR_ALLOC_SIZE(x)
-# endif
-#else
-# define LIBXML_ATTR_ALLOC_SIZE(x)
-#endif
-
-#ifndef LIBXML_ATTR_FORMAT
-# if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))
-#  define LIBXML_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args)))
-# else
-#  define LIBXML_ATTR_FORMAT(fmt,args)
-# endif
-#else
-# define LIBXML_ATTR_FORMAT(fmt,args)
-#endif
-
-#ifndef XML_DEPRECATED
-#  if defined (IN_LIBXML) || (__GNUC__ * 100 + __GNUC_MINOR__ < 301)
-#    define XML_DEPRECATED
-/* Available since at least GCC 3.1 */
-#  else
-#    define XML_DEPRECATED __attribute__((deprecated))
-#  endif
-#endif
-
-#if defined(__LCC__)
-  #define XML_IGNORE_FPTR_CAST_WARNINGS
-  #define XML_POP_WARNINGS \
-    _Pragma("diag_default 1215")
-#elif defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)
-  #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800)
-    #define XML_IGNORE_FPTR_CAST_WARNINGS \
-      _Pragma("GCC diagnostic push") \
-      _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
-      _Pragma("GCC diagnostic ignored \"-Wcast-function-type\"")
-  #else
-    #define XML_IGNORE_FPTR_CAST_WARNINGS \
-      _Pragma("GCC diagnostic push") \
-      _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
-  #endif
-  #define XML_POP_WARNINGS \
-    _Pragma("GCC diagnostic pop")
-#else
-  #define XML_IGNORE_FPTR_CAST_WARNINGS
-  #define XML_POP_WARNINGS
-#endif
-
-#else /* ! __GNUC__ */
-#define ATTRIBUTE_UNUSED
-#define LIBXML_ATTR_ALLOC_SIZE(x)
-#define LIBXML_ATTR_FORMAT(fmt,args)
-#ifndef XML_DEPRECATED
-#  if defined (IN_LIBXML) || !defined (_MSC_VER)
-#    define XML_DEPRECATED
-/* Available since Visual Studio 2005 */
-#  elif defined (_MSC_VER) && (_MSC_VER >= 1400)
-#    define XML_DEPRECATED __declspec(deprecated)
-#  endif
-#endif
-#if defined (_MSC_VER) && (_MSC_VER >= 1400)
-#  define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push))
-#else
-#  define XML_IGNORE_FPTR_CAST_WARNINGS
-#endif
-#ifndef XML_POP_WARNINGS
-#  if defined (_MSC_VER) && (_MSC_VER >= 1400)
-#    define XML_POP_WARNINGS __pragma(warning(pop))
-#  else
-#    define XML_POP_WARNINGS
-#  endif
-#endif
-#endif /* __GNUC__ */
-
-#define XML_NO_ATTR
-
-#ifdef LIBXML_THREAD_ENABLED
-  #define XML_DECLARE_GLOBAL(name, type, attrs) \
-    attrs XMLPUBFUN type *__##name(void);
-  #define XML_GLOBAL_MACRO(name) (*__##name())
-#else
-  #define XML_DECLARE_GLOBAL(name, type, attrs) \
-    attrs XMLPUBVAR type name;
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
 #endif