Roll libxml from c444c96e to 9bce9dbb

2024-03-26 wellnhofer@aevum.de valid: Report malloc failure in xmlValidateOneElement
2024-03-26 wellnhofer@aevum.de fuzz: Restrict input size of API fuzzer
2024-03-26 wellnhofer@aevum.de fuzz: Restrict number of copies in API fuzzer
2024-03-26 wellnhofer@aevum.de html: Use binary search in htmlEntityValueLookup
2024-03-25 wellnhofer@aevum.de tree: Work on documentation
2024-03-24 wellnhofer@aevum.de fuzz: Enable float-divide-by-zero on OSS-Fuzz
2024-03-24 wellnhofer@aevum.de xinclude: Report malloc failure in xmlXIncludeAddNode
2024-03-22 wellnhofer@aevum.de tree: Fix uninitialized value in xmlSearchNsSafe
2024-03-22 wellnhofer@aevum.de ci: Support ASan in Docker container
2024-03-22 wellnhofer@aevum.de ci: Show config.log if configuration failed
2024-03-22 wellnhofer@aevum.de ci: Remove Python 2 job, update C89 job
2024-03-22 wellnhofer@aevum.de doc: Update Docker CI instructions
2024-03-22 wellnhofer@aevum.de ci: Update Docker container to Ubuntu 23.10
2024-03-22 wellnhofer@aevum.de ci: Add meson to Docker container
2024-03-22 wellnhofer@aevum.de fuzz: Fix namespaces after xmlDOMWrapRemoveNode
2024-03-22 wellnhofer@aevum.de SAX2: Report malloc failure in xmlSAX2AttributeNs
2024-03-22 wellnhofer@aevum.de xinclude: Report malloc failures in xmlXIncludeIncludeNode
2024-03-22 wellnhofer@aevum.de tree: Fix uninitialized value in xmlSearchNsByHrefSafe
2024-03-20 wellnhofer@aevum.de fuzz: Enable API fuzzer on OSS-Fuzz
2024-03-20 wellnhofer@aevum.de fuzz: Reorder API fuzzer ops
2024-03-20 wellnhofer@aevum.de fuzz: Check text nodes after merging
2024-03-19 wellnhofer@aevum.de valid: Check for NULL node->name in xmlSnprintfElements
2024-03-18 wellnhofer@aevum.de io: Allocate output buffer with XML_BUFFER_ALLOC_IO
2024-03-18 wellnhofer@aevum.de encoding: Don't shrink input too early in xmlCharEncOutput
2024-03-18 wellnhofer@aevum.de tree: Report malloc failures in attribute setters
2024-03-18 wellnhofer@aevum.de xinclude: Set errNo in xmlXIncludeErrMemory
2024-03-17 wellnhofer@aevum.de tree: Introduce xmlSearchNsSafe
2024-03-17 wellnhofer@aevum.de Revert "tree: Allocate XML namespace statically"
2024-03-17 wellnhofer@aevum.de save: Check for NULL node->name in xhtmlIsEmpty
2024-03-17 wellnhofer@aevum.de schemas: Fix ADD_ANNOTATION
2024-03-17 wellnhofer@aevum.de xmlreader: Fix memory leak in xmlTextReaderFreeProp
2024-03-16 wellnhofer@aevum.de valid: Deprecate internal validation functions
2024-03-16 wellnhofer@aevum.de fuzz: Move fuzzer options to environment variable
2024-03-15 wellnhofer@aevum.de fuzz: Add OSS-Fuzz build.sh
2024-03-15 wellnhofer@aevum.de fuzz: Add some comments in api.c
2024-02-29 wellnhofer@aevum.de fuzz: New tree API fuzzer
2024-03-15 wellnhofer@aevum.de tree: Tighten source doc check in xmlDOMWrapAdoptNode
2024-03-14 wellnhofer@aevum.de tree: Check destParent->doc in xmlDOMWrapCloneNode
2024-03-13 wellnhofer@aevum.de tree: Switch to xmlNodeSetDoc in xmlDOMWrapAdoptNode
2024-03-13 wellnhofer@aevum.de tree: Fix tree iteration in xmlDOMWrapRemoveNode
2024-03-12 wellnhofer@aevum.de tree: Don't abort early if malloc fails in DOM functions
2024-03-12 wellnhofer@aevum.de tree: Fix reallocation in xmlDOMWrapNSNormAddNsMapItem2
2024-03-12 wellnhofer@aevum.de tree: Set parent->last early in xmlDOMWrapCloneNode
2024-03-12 wellnhofer@aevum.de tree: Declare namespace on clone in xmlDOMWrapCloneNode
2024-03-12 wellnhofer@aevum.de tree: Don't free linked DOM namespaces in error case
2024-03-12 wellnhofer@aevum.de tree: Report malloc failure in xmlDOMWrapCloneNode
2024-03-11 wellnhofer@aevum.de tree: Refactor text node updates
2024-03-11 wellnhofer@aevum.de tree: Refactor node insertion
2024-03-11 wellnhofer@aevum.de tree: Refactor element creation and parsing of attribute values
2024-03-05 wellnhofer@aevum.de tree: Simplify xmlNodeGetContent, xmlBufGetNodeContent
2024-03-11 wellnhofer@aevum.de buf: Don't use default buffer size for small strings
2024-03-08 wellnhofer@aevum.de valid: Set document on dummmy element declaration
2024-03-07 wellnhofer@aevum.de tree: Work on documentation
2024-03-06 wellnhofer@aevum.de string: Fix xmlStrncatNew(NULL, "")
2024-03-05 wellnhofer@aevum.de malloc-fail: Stop using xmlSplitQName2
2024-03-05 wellnhofer@aevum.de malloc-fail: Report in xmlAddAttributeDecl
2024-03-05 wellnhofer@aevum.de malloc-fail: Fix erroneous report in xmlNodeGetBaseSafe
2024-03-04 wellnhofer@aevum.de malloc-fail: Avoid use-after-free in xmlAddChild
2024-03-04 wellnhofer@aevum.de malloc-fail: Fix memory leak in xmlNewNodeEatName
2024-03-04 wellnhofer@aevum.de malloc-fail: Check for NULL pointer in xmlSaveNotation*
2024-03-04 wellnhofer@aevum.de malloc-fail: Fix use-after-free in xmlBufBackToBuffer
2024-03-05 wellnhofer@aevum.de entities: Don't allow null name in xmlNewEntity
2024-03-05 wellnhofer@aevum.de entities: Check for illegal entity types in xmlAddEntity
2024-03-06 wellnhofer@aevum.de io: Report more malloc failures when writing to output buffer
2024-03-06 wellnhofer@aevum.de html: Fix quadratic behavior in htmlNodeDump
2024-03-05 wellnhofer@aevum.de save: Report malloc failure in xmlAttrSerializeTxtContent
2024-03-04 wellnhofer@aevum.de save: Cast return code of xmlBufNodeDump
2024-03-05 wellnhofer@aevum.de save: Check for output buffer errors
2024-03-03 wellnhofer@aevum.de save: Add range check for level in xmlNodeDump
2024-03-15 wellnhofer@aevum.de valid: Check for NULL text content in xmlValidateOneElement
2024-03-14 wellnhofer@aevum.de valid: Check for elem->name in xmlIsID
2024-03-06 wellnhofer@aevum.de valid: Fix some return codes after errors
2024-03-05 wellnhofer@aevum.de valid: Eliminate xmlCtxtGetDtdElementDesc
2024-03-05 wellnhofer@aevum.de valid: Report malloc failure in legacy DTD serialization
2024-03-05 wellnhofer@aevum.de valid: Fix hash removal in xmlRemoveRef
2024-03-05 wellnhofer@aevum.de valid: Don't report errors with null context
2024-03-02 wellnhofer@aevum.de valid: Remove id before updating attribute type
2024-03-01 wellnhofer@aevum.de valid: Fix id handling in xmlValidateDtd
2024-03-02 wellnhofer@aevum.de valid: Reset attribute in xmlFreeID
2024-03-01 wellnhofer@aevum.de valid: Rework checks in xmlValidateOneElement
2024-02-29 wellnhofer@aevum.de valid: Check element type in xmlIsID
2024-02-29 wellnhofer@aevum.de valid: Change error code to XML_ERR_ARGUMENT
2024-03-08 wellnhofer@aevum.de tree: Check return value of xmlNodeAddContent
2024-03-07 wellnhofer@aevum.de tree: Fix error return in xmlGetPropNodeValueInternal
2024-03-07 wellnhofer@aevum.de tree: Prefer xmlGetPropNodeInternal over xmlHasNsProp
2024-03-06 wellnhofer@aevum.de tree: Report malloc failure in xmlAddNextSibling
2024-03-02 wellnhofer@aevum.de tree: Rewrite xmlSetTreeDoc
2024-03-05 wellnhofer@aevum.de tree: Remove more unused node types
2024-03-06 wellnhofer@aevum.de tree: Report more malloc failures
2024-03-04 wellnhofer@aevum.de tree: Fix adding ids in xmlNewPropInternal
2024-02-29 wellnhofer@aevum.de valid: Rework xmlAddID
2024-03-05 wellnhofer@aevum.de tree: Improve argument check in xmlTextConcat
2024-03-05 wellnhofer@aevum.de tree: Remove unused node types
2024-03-05 wellnhofer@aevum.de tree: Make namespace comparison more consistent
2024-03-05 wellnhofer@aevum.de tree: Don't allow NULL name in xmlSetNsProp
2024-03-04 wellnhofer@aevum.de tree: Allocate XML namespace statically
2024-03-05 wellnhofer@aevum.de tree: Rework xmlNodeListGetString
2024-02-28 wellnhofer@aevum.de tree: Rework xmlTextMerge
2024-02-28 wellnhofer@aevum.de tree: Rework xmlNodeSetName
2024-02-27 wellnhofer@aevum.de tree: Simplify xmlAddChild with text parent
2024-02-27 wellnhofer@aevum.de tree: Don't allow misuse of xmlAddChild
2024-02-27 wellnhofer@aevum.de tree: Fix xmlAddPropSibling with duplicate attributes
2024-02-27 wellnhofer@aevum.de tree: Fix indentation in xmlAddPropSibling
2024-02-27 wellnhofer@aevum.de tree: Fix xmlAddSibling with last sibling
2024-02-27 wellnhofer@aevum.de tree: Move type check in xmlAddChild
2024-02-23 wellnhofer@aevum.de tree: Fix xmlDocSetRootElement with multiple top-level elements
2024-02-22 wellnhofer@aevum.de tree: Only allow elements in xmlDocSetRootElement
2024-02-22 wellnhofer@aevum.de tree: Disallow setting content of entity reference nodes
2024-02-22 wellnhofer@aevum.de tree: Rework xmlReconciliateNs
2024-02-22 wellnhofer@aevum.de tree: Unlink DTD in xmlStaticCopyNodeList
2024-02-22 wellnhofer@aevum.de tree: Unlink DTD in xmlFreeNodeList
2024-03-12 wellnhofer@aevum.de parser: Fix detection of duplicate attributes in XML namespace
2024-03-10 wellnhofer@aevum.de fuzz: Improve README
2024-03-03 wellnhofer@aevum.de catalog: Fetch XML catalog before dumping
2024-03-02 bgilbert@backtick.net schemas: fix spurious warning about truncated snprintf output
2024-02-29 maks.mishinFZ@gmail.com xmlschemastypes: Remove unreachable if statement
2024-02-29 maks.mishinFZ@gmail.com relaxng: Remove useless if statement
2024-02-26 wellnhofer@aevum.de xmlreader: Fix xmlTextReaderConstEncoding
2024-02-26 wellnhofer@aevum.de html: Regression test for #696
2024-02-21 wellnhofer@aevum.de tree: Check for integer overflow in xmlStringGetNodeList
2024-02-20 wellnhofer@aevum.de SAX2: Report malloc failure in xmlCheckDefaultedAttributes
2024-02-19 wellnhofer@aevum.de http: Improve error message for HTTPS redirects
2024-02-16 wellnhofer@aevum.de save: Don't write directly to internal buffer
2024-02-14 wellnhofer@aevum.de dict: Include unistd.h for getentropy

Bug: 934413
Change-Id: I136270e532c21e40bc880509603308c6e5543bff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5403594
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1281330}
NOKEYCHECK=True
GitOrigin-RevId: 63d2d18490fbe995343561fcd603369156efb846
diff --git a/README.chromium b/README.chromium
index 291f832..6e09d2d 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,6 +1,6 @@
 Name: libxml
 URL: http://xmlsoft.org
-Version: c444c96e20253e5996f4209a123b96a6c273dac6
+Version: 9bce9dbb19987224905f40e64fe227c0c981fa3a
 CPEPrefix: cpe:/a:xmlsoft:libxml2:2.12.5
 License: MIT
 License File: src/Copyright
diff --git a/chromium/remove-getentropy.patch b/chromium/remove-getentropy.patch
index 7d19136..80f65ed 100644
--- a/chromium/remove-getentropy.patch
+++ b/chromium/remove-getentropy.patch
@@ -5,25 +5,29 @@
 generation behavior before a recent libxml upstream patch.
 
 diff --git a/dict.c b/dict.c
-index 5c9f3aa2..7a492895 100644
+index c843bb7b..96435d52 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
- 
+@@ -909,17 +909,12 @@ xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) {
  #ifdef _WIN32
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
--#include <bcrypt.h>
+   #define WIN32_LEAN_AND_MEAN
+   #include <windows.h>
+-  #include <bcrypt.h>
+ #elif defined(HAVE_GETENTROPY)
+   #ifdef HAVE_UNISTD_H
+     #include <unistd.h>
+   #endif
+-  #ifdef HAVE_SYS_RANDOM_H
+-    #include <sys/random.h>
+-  #endif
+-#else
+-  #include <time.h>
  #endif
++#include <time.h>
  
- #include "private/dict.h"
-@@ -926,29 +922,6 @@ xmlInitRandom(void) {
+ static xmlMutex xmlRngMutex;
+ 
+@@ -931,29 +926,6 @@ xmlInitRandom(void) {
      xmlInitMutex(&xmlRngMutex);
  
      {
@@ -53,7 +57,7 @@
          int var;
  
          globalRngState[0] =
-@@ -957,7 +930,6 @@ xmlInitRandom(void) {
+@@ -962,7 +934,6 @@ xmlInitRandom(void) {
          globalRngState[1] =
                  HASH_ROL((unsigned) ((size_t) &xmlRngMutex & 0xFFFFFFFF), 16) ^
                  HASH_ROL((unsigned) ((size_t) &var & 0xFFFFFFFF), 24);
diff --git a/mac/config.h b/mac/config.h
index 59b8e8c..0ea06ac 100644
--- a/mac/config.h
+++ b/mac/config.h
@@ -22,13 +22,13 @@
 /* Define to 1 if you have the <fcntl.h> header file. */
 #define HAVE_FCNTL_H 1
 
-/* Define to 1 if you have the `ftime' function. */
+/* Define to 1 if you have the 'ftime' function. */
 #define HAVE_FTIME 1
 
-/* Define to 1 if you have the `getentropy' function. */
+/* Define to 1 if you have the 'getentropy' function. */
 #define HAVE_GETENTROPY 1
 
-/* Define to 1 if you have the `gettimeofday' function. */
+/* Define to 1 if you have the 'gettimeofday' function. */
 #define HAVE_GETTIMEOFDAY 1
 
 /* Define to 1 if you have the <glob.h> header file. */
@@ -37,7 +37,7 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #define HAVE_INTTYPES_H 1
 
-/* Define to 1 if you have the `isascii' function. */
+/* Define to 1 if you have the 'isascii' function. */
 #define HAVE_ISASCII 1
 
 /* Define if history library is there (-lhistory) */
@@ -49,10 +49,10 @@
 /* Define to 1 if you have the <lzma.h> header file. */
 /* #undef HAVE_LZMA_H */
 
-/* Define to 1 if you have the `mmap' function. */
+/* Define to 1 if you have the 'mmap' function. */
 #define HAVE_MMAP 1
 
-/* Define to 1 if you have the `munmap' function. */
+/* Define to 1 if you have the 'munmap' function. */
 #define HAVE_MUNMAP 1
 
 /* mmap() is no good without munmap() */
@@ -75,7 +75,7 @@
 /* Have shl_load based dso */
 /* #undef HAVE_SHLLOAD */
 
-/* Define to 1 if you have the `stat' function. */
+/* Define to 1 if you have the 'stat' function. */
 #define HAVE_STAT 1
 
 /* Define to 1 if you have the <stdint.h> header file. */
@@ -147,7 +147,7 @@
 /* Define to the version of this package. */
 #define PACKAGE_VERSION "2.13.0"
 
-/* Define to 1 if all of the C90 standard headers exist (not just the ones
+/* Define to 1 if all of the C89 standard headers exist (not just the ones
    required in a freestanding environment). This macro is provided for
    backward compatibility; new code need not use it. */
 #define STDC_HEADERS 1
diff --git a/src/HTMLparser.c b/src/HTMLparser.c
index 30b0fc8..b1271e6 100644
--- a/src/HTMLparser.c
+++ b/src/HTMLparser.c
@@ -2011,6 +2011,14 @@
     return(NULL);
 }
 
+static int
+htmlCompareEntityDesc(const void *vkey, const void *vdesc) {
+    const unsigned *key = vkey;
+    const htmlEntityDesc *desc = vdesc;
+
+    return((int) *key - (int) desc->value);
+}
+
 /**
  * htmlEntityValueLookup:
  * @value: the entity's unicode value
@@ -2023,17 +2031,14 @@
  */
 const htmlEntityDesc *
 htmlEntityValueLookup(unsigned int value) {
-    unsigned int i;
+    const htmlEntityDesc *desc;
+    size_t nmemb;
 
-    for (i = 0;i < (sizeof(html40EntitiesTable)/
-                    sizeof(html40EntitiesTable[0]));i++) {
-        if (html40EntitiesTable[i].value >= value) {
-	    if (html40EntitiesTable[i].value > value)
-		break;
-            return((htmlEntityDescPtr) &html40EntitiesTable[i]);
-	}
-    }
-    return(NULL);
+    nmemb = sizeof(html40EntitiesTable) / sizeof(html40EntitiesTable[0]);
+    desc = bsearch(&value, html40EntitiesTable, nmemb, sizeof(htmlEntityDesc),
+                   htmlCompareEntityDesc);
+
+    return(desc);
 }
 
 /**
diff --git a/src/HTMLtree.c b/src/HTMLtree.c
index 89d6181..acdde75 100644
--- a/src/HTMLtree.c
+++ b/src/HTMLtree.c
@@ -421,18 +421,18 @@
 htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur,
 	           int format) {
     size_t use;
-    int ret;
+    size_t ret;
     xmlOutputBufferPtr outbuf;
 
     if (cur == NULL) {
-	return (-1);
+	return ((size_t) -1);
     }
     if (buf == NULL) {
-	return (-1);
+	return ((size_t) -1);
     }
     outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
     if (outbuf == NULL)
-	return (-1);
+	return ((size_t) -1);
     memset(outbuf, 0, sizeof(xmlOutputBuffer));
     outbuf->buffer = buf;
     outbuf->encoder = NULL;
@@ -443,8 +443,11 @@
 
     use = xmlBufUse(buf);
     htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format);
+    if (outbuf->error)
+        ret = (size_t) -1;
+    else
+        ret = xmlBufUse(buf) - use;
     xmlFree(outbuf);
-    ret = xmlBufUse(buf) - use;
     return (ret);
 }
 
@@ -472,6 +475,7 @@
     if (buffer == NULL)
         return(-1);
 
+    xmlBufSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT);
     ret = htmlBufNodeDumpFormat(buffer, doc, cur, 1);
 
     xmlBufBackToBuffer(buffer);
@@ -551,32 +555,32 @@
 
     if ((mem == NULL) || (size == NULL))
         return;
-    if (cur == NULL) {
-	*mem = NULL;
-	*size = 0;
+    *mem = NULL;
+    *size = 0;
+    if (cur == NULL)
 	return;
-    }
 
     encoding = (const char *) htmlGetMetaEncoding(cur);
     handler = htmlFindOutputEncoder(encoding);
     buf = xmlAllocOutputBufferInternal(handler);
-    if (buf == NULL) {
-	*mem = NULL;
-	*size = 0;
+    if (buf == NULL)
 	return;
-    }
 
     htmlDocContentDumpFormatOutput(buf, cur, NULL, format);
 
     xmlOutputBufferFlush(buf);
-    if (buf->conv != NULL) {
-	*size = xmlBufUse(buf->conv);
-	*mem = xmlStrndup(xmlBufContent(buf->conv), *size);
-    } else {
-	*size = xmlBufUse(buf->buffer);
-	*mem = xmlStrndup(xmlBufContent(buf->buffer), *size);
+
+    if (!buf->error) {
+        if (buf->conv != NULL) {
+            *size = xmlBufUse(buf->conv);
+            *mem = xmlStrndup(xmlBufContent(buf->conv), *size);
+        } else {
+            *size = xmlBufUse(buf->buffer);
+            *mem = xmlStrndup(xmlBufContent(buf->buffer), *size);
+        }
     }
-    (void)xmlOutputBufferClose(buf);
+
+    xmlOutputBufferClose(buf);
 }
 
 /**
@@ -623,15 +627,15 @@
     xmlOutputBufferWriteString(buf, (const char *)cur->name);
     if (cur->ExternalID != NULL) {
 	xmlOutputBufferWriteString(buf, " PUBLIC ");
-	xmlBufWriteQuotedString(buf->buffer, cur->ExternalID);
+	xmlOutputBufferWriteQuotedString(buf, cur->ExternalID);
 	if (cur->SystemID != NULL) {
 	    xmlOutputBufferWriteString(buf, " ");
-	    xmlBufWriteQuotedString(buf->buffer, cur->SystemID);
+	    xmlOutputBufferWriteQuotedString(buf, cur->SystemID);
 	}
     } else if (cur->SystemID != NULL &&
 	       xmlStrcmp(cur->SystemID, BAD_CAST "about:legacy-compat")) {
 	xmlOutputBufferWriteString(buf, " SYSTEM ");
-	xmlBufWriteQuotedString(buf->buffer, cur->SystemID);
+	xmlOutputBufferWriteQuotedString(buf, cur->SystemID);
     }
     xmlOutputBufferWriteString(buf, ">\n");
 }
@@ -691,13 +695,13 @@
 		escaped = xmlURIEscapeStr(tmp,
                         BAD_CAST "\"#$%&+,/:;<=>?@[\\]^`{|}");
 		if (escaped != NULL) {
-		    xmlBufWriteQuotedString(buf->buffer, escaped);
+		    xmlOutputBufferWriteQuotedString(buf, escaped);
 		    xmlFree(escaped);
 		} else {
                     buf->error = XML_ERR_NO_MEMORY;
 		}
 	    } else {
-		xmlBufWriteQuotedString(buf->buffer, value);
+		xmlOutputBufferWriteQuotedString(buf, value);
 	    }
 	    xmlFree(value);
 	} else  {
diff --git a/src/SAX2.c b/src/SAX2.c
index f102bb6..30bff09 100644
--- a/src/SAX2.c
+++ b/src/SAX2.c
@@ -812,10 +812,6 @@
 	    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)) {
@@ -846,17 +842,7 @@
 
     doc = ctxt->myDoc;
     if ((doc != NULL) && (doc->encoding == NULL)) {
-        const xmlChar *encoding = NULL;
-
-        if ((ctxt->input->flags & XML_INPUT_USES_ENC_DECL) ||
-            (ctxt->input->flags & XML_INPUT_AUTO_ENCODING)) {
-            /* Preserve encoding exactly */
-            encoding = ctxt->encoding;
-        } else if ((ctxt->input->buf) && (ctxt->input->buf->encoder)) {
-            encoding = BAD_CAST ctxt->input->buf->encoder->name;
-        } else if (ctxt->input->flags & XML_INPUT_HAS_ENCODING) {
-            encoding = BAD_CAST "UTF-8";
-        }
+        const xmlChar *encoding = xmlGetActualEncoding(ctxt);
 
         if (encoding != NULL) {
             doc->encoding = xmlStrdup(encoding);
@@ -1114,7 +1100,11 @@
     }
 
     if (ns != NULL) {
-	namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns);
+        int res;
+
+	res = xmlSearchNsSafe(ctxt->node, ns, &namespace);
+        if (res < 0)
+            xmlSAX2ErrMemory(ctxt);
 
 	if (namespace == NULL) {
 	    xmlNsErrMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
@@ -1154,20 +1144,8 @@
     }
 
     if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
-        xmlNodePtr tmp;
-
-        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;
-            if (tmp->next == NULL)
-                ret->last = tmp;
-            tmp = tmp->next;
-        }
+        if (xmlNodeParseContent((xmlNodePtr) ret, value, INT_MAX) < 0)
+            xmlSAX2ErrMemory(ctxt);
     } else if (value != NULL) {
         ret->children = xmlNewDocText(ctxt->myDoc, value);
         if (ret->children == NULL) {
@@ -1304,8 +1282,10 @@
 
 		    if (attr->prefix != NULL) {
 			fulln = xmlStrdup(attr->prefix);
-			fulln = xmlStrcat(fulln, BAD_CAST ":");
-			fulln = xmlStrcat(fulln, attr->name);
+                        if (fulln != NULL)
+			    fulln = xmlStrcat(fulln, BAD_CAST ":");
+                        if (fulln != NULL)
+			    fulln = xmlStrcat(fulln, attr->name);
 		    } else {
 			fulln = xmlStrdup(attr->name);
 		    }
@@ -1509,6 +1489,8 @@
     xmlAddChild(parent, ret);
 
     if (!ctxt->html) {
+        int res;
+
         /*
          * Insert all the defaulted attributes from the DTD especially
          * namespaces
@@ -1539,9 +1521,14 @@
          * Search the namespace, note that since the attributes have been
          * processed, the local namespaces are available.
          */
-        ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
-        if ((ns == NULL) && (parent != NULL))
-            ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
+        res = xmlSearchNsSafe(ret, prefix, &ns);
+        if (res < 0)
+            xmlSAX2ErrMemory(ctxt);
+        if ((ns == NULL) && (parent != NULL)) {
+            res = xmlSearchNsSafe(parent, prefix, &ns);
+            if (res < 0)
+                xmlSAX2ErrMemory(ctxt);
+        }
         if ((prefix != NULL) && (ns == NULL)) {
             xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE,
                          "Namespace prefix %s is not defined\n",
@@ -1793,7 +1780,11 @@
     if (prefix != NULL) {
 	namespace = xmlParserNsLookupSax(ctxt, prefix);
 	if ((namespace == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
-	    namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, prefix);
+            int res;
+
+	    res = xmlSearchNsSafe(ctxt->node, prefix, &namespace);
+            if (res < 0)
+                xmlSAX2ErrMemory(ctxt);
 	}
     }
 
@@ -1856,18 +1847,9 @@
 		tmp->parent = (xmlNodePtr) ret;
 	    }
 	} else if (valueend > value) {
-	    ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value,
-						    valueend - value);
-            if (ret->children == NULL)
+            if (xmlNodeParseContent((xmlNodePtr) ret, value,
+                                    valueend - value) < 0)
                 xmlSAX2ErrMemory(ctxt);
-	    tmp = ret->children;
-	    while (tmp != NULL) {
-	        tmp->doc = ret->doc;
-		tmp->parent = (xmlNodePtr) ret;
-		if (tmp->next == NULL)
-		    ret->last = tmp;
-		tmp = tmp->next;
-	    }
 	}
     } else if (value != NULL) {
 	xmlNodePtr tmp;
@@ -1921,7 +1903,9 @@
 		    xmlChar *fullname;
 
 		    fullname = xmlBuildQName(localname, prefix, fn, 50);
-		    if (fullname != NULL) {
+                    if (fullname == NULL) {
+                        xmlSAX2ErrMemory(ctxt);
+                    } else {
 			ctxt->vctxt.valid = 1;
 		        nvalnorm = xmlValidCtxtNormalizeAttributeValue(
 			                 &ctxt->vctxt, ctxt->myDoc,
@@ -2183,7 +2167,11 @@
     if ((URI != NULL) && (ret->ns == NULL)) {
         ret->ns = xmlParserNsLookupSax(ctxt, prefix);
 	if ((ret->ns == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) {
-	    ret->ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
+            int res;
+
+	    res = xmlSearchNsSafe(ret, prefix, &ret->ns);
+            if (res < 0)
+                xmlSAX2ErrMemory(ctxt);
 	}
 	if (ret->ns == NULL) {
 	    ns = xmlNewNs(ret, NULL, prefix);
diff --git a/src/buf.c b/src/buf.c
index 7e860f7..f9f59b2 100644
--- a/src/buf.c
+++ b/src/buf.c
@@ -195,8 +195,16 @@
     if (buf->error)
         return(NULL);
 
-    ret = buf->content;
+    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
+        (buf->content != buf->contentIO)) {
+        ret = xmlStrndup(buf->content, buf->use);
+        xmlFree(buf->contentIO);
+    } else {
+        ret = buf->content;
+    }
+
     buf->content = NULL;
+    buf->contentIO = NULL;
     buf->size = 0;
     buf->use = 0;
     UPDATE_COMPAT(buf);
@@ -743,8 +751,7 @@
  * Add a string range to an XML buffer. if len == -1, the length of
  * str is recomputed.
  *
- * Returns 0 successful, a positive error code number otherwise
- *         and -1 in case of internal or API error.
+ * Returns 0 if successful, -1 in case of error.
  */
 int
 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
@@ -781,10 +788,8 @@
 		return(-1);
 	    }
 	}
-        if (!xmlBufResize(buf, needSize)){
-	    xmlBufMemoryError(buf);
-            return XML_ERR_NO_MEMORY;
-        }
+        if (!xmlBufResize(buf, needSize))
+            return(-1);
     }
 
     memmove(&buf->content[buf->use], str, len);
@@ -814,72 +819,6 @@
 }
 
 /**
- * xmlBufCCat:
- * @buf:  the buffer to dump
- * @str:  the C char string
- *
- * Append a zero terminated C string to an XML buffer.
- *
- * Returns 0 successful, a positive error code number otherwise
- *         and -1 in case of internal or API error.
- */
-int
-xmlBufCCat(xmlBufPtr buf, const char *str) {
-    return xmlBufCat(buf, (const xmlChar *) str);
-}
-
-/**
- * xmlBufWriteQuotedString:
- * @buf:  the XML buffer output
- * @string:  the string to add
- *
- * routine which manage and grows an output buffer. This one writes
- * a quoted or double quoted #xmlChar string, checking first if it holds
- * quote or double-quotes internally
- *
- * Returns 0 if successful, a positive error code number otherwise
- *         and -1 in case of internal or API error.
- */
-int
-xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
-    const xmlChar *cur, *base;
-    if ((buf == NULL) || (buf->error))
-        return(-1);
-    CHECK_COMPAT(buf)
-    if (xmlStrchr(string, '\"')) {
-        if (xmlStrchr(string, '\'')) {
-	    xmlBufCCat(buf, "\"");
-            base = cur = string;
-            while(*cur != 0){
-                if(*cur == '"'){
-                    if (base != cur)
-                        xmlBufAdd(buf, base, cur - base);
-                    xmlBufAdd(buf, BAD_CAST "&quot;", 6);
-                    cur++;
-                    base = cur;
-                }
-                else {
-                    cur++;
-                }
-            }
-            if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
-	    xmlBufCCat(buf, "\"");
-	}
-        else{
-	    xmlBufCCat(buf, "\'");
-            xmlBufCat(buf, string);
-	    xmlBufCCat(buf, "\'");
-        }
-    } else {
-        xmlBufCCat(buf, "\"");
-        xmlBufCat(buf, string);
-        xmlBufCCat(buf, "\"");
-    }
-    return(0);
-}
-
-/**
  * xmlBufFromBuffer:
  * @buffer: incoming old buffer to convert to a new one
  *
@@ -932,12 +871,19 @@
     if (buf == NULL)
         return(NULL);
     CHECK_COMPAT(buf)
-    if ((buf->error) || (buf->buffer == NULL)) {
+    ret = buf->buffer;
+
+    if ((buf->error) || (ret == NULL)) {
         xmlBufFree(buf);
+        if (ret != NULL) {
+            ret->content = NULL;
+            ret->contentIO = NULL;
+            ret->use = 0;
+            ret->size = 0;
+        }
         return(NULL);
     }
 
-    ret = buf->buffer;
     /*
      * What to do in case of error in the buffer ???
      */
diff --git a/src/config.h.in b/src/config.h.in
index f07ca83..9954a4a 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -21,13 +21,13 @@
 /* Define to 1 if you have the <fcntl.h> header file. */
 #undef HAVE_FCNTL_H
 
-/* Define to 1 if you have the `ftime' function. */
+/* Define to 1 if you have the 'ftime' function. */
 #undef HAVE_FTIME
 
-/* Define to 1 if you have the `getentropy' function. */
+/* Define to 1 if you have the 'getentropy' function. */
 #undef HAVE_GETENTROPY
 
-/* Define to 1 if you have the `gettimeofday' function. */
+/* Define to 1 if you have the 'gettimeofday' function. */
 #undef HAVE_GETTIMEOFDAY
 
 /* Define to 1 if you have the <glob.h> header file. */
@@ -36,7 +36,7 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
-/* Define to 1 if you have the `isascii' function. */
+/* Define to 1 if you have the 'isascii' function. */
 #undef HAVE_ISASCII
 
 /* Define if history library is there (-lhistory) */
@@ -48,10 +48,10 @@
 /* Define to 1 if you have the <lzma.h> header file. */
 #undef HAVE_LZMA_H
 
-/* Define to 1 if you have the `mmap' function. */
+/* Define to 1 if you have the 'mmap' function. */
 #undef HAVE_MMAP
 
-/* Define to 1 if you have the `munmap' function. */
+/* Define to 1 if you have the 'munmap' function. */
 #undef HAVE_MUNMAP
 
 /* mmap() is no good without munmap() */
@@ -74,7 +74,7 @@
 /* Have shl_load based dso */
 #undef HAVE_SHLLOAD
 
-/* Define to 1 if you have the `stat' function. */
+/* Define to 1 if you have the 'stat' function. */
 #undef HAVE_STAT
 
 /* Define to 1 if you have the <stdint.h> header file. */
@@ -146,7 +146,7 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
-/* Define to 1 if all of the C90 standard headers exist (not just the ones
+/* Define to 1 if all of the C89 standard headers exist (not just the ones
    required in a freestanding environment). This macro is provided for
    backward compatibility; new code need not use it. */
 #undef STDC_HEADERS
diff --git a/src/dict.c b/src/dict.c
index 7a49289..96435d5 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -23,12 +23,6 @@
 #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"
@@ -912,6 +906,16 @@
  * Pseudo-random generator
  */
 
+#ifdef _WIN32
+  #define WIN32_LEAN_AND_MEAN
+  #include <windows.h>
+#elif defined(HAVE_GETENTROPY)
+  #ifdef HAVE_UNISTD_H
+    #include <unistd.h>
+  #endif
+#endif
+#include <time.h>
+
 static xmlMutex xmlRngMutex;
 
 static unsigned globalRngState[2];
diff --git a/src/encoding.c b/src/encoding.c
index 0f58029..f1cd440 100644
--- a/src/encoding.c
+++ b/src/encoding.c
@@ -2491,7 +2491,6 @@
          */
         charrefLen = snprintf((char *) &charref[0], sizeof(charref),
                          "&#%d;", cur);
-        xmlBufShrink(in, len);
         xmlBufGrow(out, charrefLen * 4);
         c_out = xmlBufAvail(out);
         c_in = charrefLen;
@@ -2502,6 +2501,7 @@
             goto error;
         }
 
+        xmlBufShrink(in, len);
         xmlBufAddLen(out, c_out);
         writtentot += c_out;
         goto retry;
diff --git a/src/entities.c b/src/entities.c
index 9e951c3..c679cb3 100644
--- a/src/entities.c
+++ b/src/entities.c
@@ -253,7 +253,7 @@
             }
 	    table = dtd->pentities;
 	    break;
-        case XML_INTERNAL_PREDEFINED_ENTITY:
+        default:
 	    return(XML_ERR_ARGUMENT);
     }
     ret = xmlCreateEntity(dtd->doc, name, type, ExternalID, SystemID, content);
@@ -395,6 +395,8 @@
     if ((doc != NULL) && (doc->intSubset != NULL)) {
 	return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content));
     }
+    if (name == NULL)
+        return(NULL);
     return(xmlCreateEntity(doc, name, type, ExternalID, SystemID, content));
 }
 
@@ -654,11 +656,6 @@
                 l = 4;
                 val = xmlGetUTF8Char(cur, &l);
                 if (val < 0) {
-#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-                    fprintf(stderr, "xmlEncodeEntitiesInternal: "
-                            "invalid UTF-8\n");
-                    abort();
-#endif
                     val = 0xFFFD;
                     cur++;
                 } else {
@@ -937,7 +934,8 @@
 
     save = xmlSaveToBuffer(buf, NULL, 0);
     xmlSaveTree(save, (xmlNodePtr) ent);
-    xmlSaveClose(save);
+    if (xmlSaveFinish(save) != XML_ERR_OK)
+        xmlFree(xmlBufferDetach(buf));
 }
 
 /**
@@ -948,9 +946,9 @@
  * When using the hash table scan function, arguments need to be reversed
  */
 static void
-xmlDumpEntityDeclScan(void *ent, void *buf,
+xmlDumpEntityDeclScan(void *ent, void *save,
                       const xmlChar *name ATTRIBUTE_UNUSED) {
-    xmlDumpEntityDecl((xmlBufferPtr) buf, (xmlEntityPtr) ent);
+    xmlSaveTree(save, ent);
 }
 
 /**
@@ -962,6 +960,14 @@
  */
 void
 xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
-    xmlHashScan(table, xmlDumpEntityDeclScan, buf);
+    xmlSaveCtxtPtr save;
+
+    if ((buf == NULL) || (table == NULL))
+        return;
+
+    save = xmlSaveToBuffer(buf, NULL, 0);
+    xmlHashScan(table, xmlDumpEntityDeclScan, save);
+    if (xmlSaveFinish(save) != XML_ERR_OK)
+        xmlFree(xmlBufferDetach(buf));
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
diff --git a/src/error.c b/src/error.c
index e5553d5..f47edb6 100644
--- a/src/error.c
+++ b/src/error.c
@@ -698,8 +698,7 @@
     if (code == XML_ERR_OK)
         return(0);
 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-    if ((code == XML_ERR_INTERNAL_ERROR) ||
-        (code == XML_ERR_ARGUMENT)) {
+    if (code == XML_ERR_INTERNAL_ERROR) {
         fprintf(stderr, "Unexpected error: %d\n", code);
         abort();
     }
@@ -1307,6 +1306,8 @@
             errmsg = "already in use"; break;
         case XML_IO_EAFNOSUPPORT:
             errmsg = "unknown address family"; break;
+        case XML_IO_UNSUPPORTED_PROTOCOL:
+            errmsg = "unsupported protocol"; break;
 
         default:
             errmsg = "Unregistered error message";
diff --git a/src/gentest.py b/src/gentest.py
index 79025f8..ebb5218 100755
--- a/src/gentest.py
+++ b/src/gentest.py
@@ -224,7 +224,7 @@
    "xmlAddPrevSibling": 
        "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
    "xmlDocSetRootElement": 
-       "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
+       "if (ret_val == NULL) { xmlFreeNode(root) ; root = NULL ; }",
    "xmlReplaceNode": 
        """if (cur != NULL) {
               xmlUnlinkNode(cur);
@@ -234,9 +234,10 @@
               xmlFreeNode(old) ; old = NULL ; }
 \t  ret_val = NULL;""",
    "xmlTextMerge": 
-       """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
+       """if (ret_val == NULL) {
               xmlUnlinkNode(second);
-              xmlFreeNode(second) ; second = NULL ; }""",
+              xmlFreeNode(second) ; second = NULL ;
+              ret_val = first; }""",
    "xmlBuildQName": 
        """if ((ret_val != NULL) && (ret_val != ncname) &&
               (ret_val != prefix) && (ret_val != memory))
diff --git a/src/include/libxml/tree.h b/src/include/libxml/tree.h
index 03449ce..bc99548 100644
--- a/src/include/libxml/tree.h
+++ b/src/include/libxml/tree.h
@@ -164,13 +164,13 @@
     XML_TEXT_NODE=		3,
     XML_CDATA_SECTION_NODE=	4,
     XML_ENTITY_REF_NODE=	5,
-    XML_ENTITY_NODE=		6,
+    XML_ENTITY_NODE=		6,  /* unused */
     XML_PI_NODE=		7,
     XML_COMMENT_NODE=		8,
     XML_DOCUMENT_NODE=		9,
-    XML_DOCUMENT_TYPE_NODE=	10,
+    XML_DOCUMENT_TYPE_NODE=	10, /* unused */
     XML_DOCUMENT_FRAG_NODE=	11,
-    XML_NOTATION_NODE=		12,
+    XML_NOTATION_NODE=		12, /* unused */
     XML_HTML_DOCUMENT_NODE=	13,
     XML_DTD_NODE=		14,
     XML_ELEMENT_DECL=		15,
@@ -1003,10 +1003,10 @@
 		xmlFreeNodeList		(xmlNodePtr cur);
 XMLPUBFUN void
 		xmlFreeNode		(xmlNodePtr cur);
-XMLPUBFUN void
+XMLPUBFUN int
 		xmlSetTreeDoc		(xmlNodePtr tree,
 					 xmlDocPtr doc);
-XMLPUBFUN void
+XMLPUBFUN int
 		xmlSetListDoc		(xmlNodePtr list,
 					 xmlDocPtr doc);
 /*
@@ -1125,10 +1125,10 @@
 XMLPUBFUN int
 		xmlNodeGetSpacePreserve	(const xmlNode *cur);
 #ifdef LIBXML_TREE_ENABLED
-XMLPUBFUN void
+XMLPUBFUN int
 		xmlNodeSetLang		(xmlNodePtr cur,
 					 const xmlChar *lang);
-XMLPUBFUN void
+XMLPUBFUN int
 		xmlNodeSetSpacePreserve (xmlNodePtr cur,
 					 int val);
 #endif /* LIBXML_TREE_ENABLED */
diff --git a/src/include/libxml/valid.h b/src/include/libxml/valid.h
index 10d6d19..361e965 100644
--- a/src/include/libxml/valid.h
+++ b/src/include/libxml/valid.h
@@ -255,11 +255,8 @@
 
 /* IDs */
 XMLPUBFUN int
-		xmlAddIDSafe	       (xmlDocPtr doc,
-					const xmlChar *value,
-					xmlAttrPtr attr,
-					int streaming,
-					xmlIDPtr *id);
+		xmlAddIDSafe	       (xmlAttrPtr attr,
+					const xmlChar *value);
 XMLPUBFUN xmlIDPtr
 		xmlAddID	       (xmlValidCtxtPtr ctxt,
 					xmlDocPtr doc,
@@ -312,31 +309,38 @@
 XMLPUBFUN void
 		xmlFreeValidCtxt(xmlValidCtxtPtr);
 
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateRoot		(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateElementDecl	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 		                         xmlElementPtr elem);
+XML_DEPRECATED
 XMLPUBFUN xmlChar *
 		xmlValidNormalizeAttributeValue(xmlDocPtr doc,
 					 xmlNodePtr elem,
 					 const xmlChar *name,
 					 const xmlChar *value);
+XML_DEPRECATED
 XMLPUBFUN xmlChar *
 		xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 					 xmlNodePtr elem,
 					 const xmlChar *name,
 					 const xmlChar *value);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 		                         xmlAttributePtr attr);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateAttributeValue(xmlAttributeType type,
 					 const xmlChar *value);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateNotationDecl	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
@@ -345,6 +349,7 @@
 		xmlValidateDtd		(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 					 xmlDtdPtr dtd);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateDtdFinal	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc);
@@ -355,16 +360,19 @@
 		xmlValidateElement	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 					 xmlNodePtr elem);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateOneElement	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 		                         xmlNodePtr elem);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateOneAttribute	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 					 xmlNodePtr	elem,
 					 xmlAttrPtr attr,
 					 const xmlChar *value);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateOneNamespace	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
@@ -372,12 +380,14 @@
 					 const xmlChar *prefix,
 					 xmlNsPtr ns,
 					 const xmlChar *value);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc);
 #endif /* LIBXML_VALID_ENABLED */
 
 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidateNotationUse	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
@@ -433,19 +443,23 @@
 /*
  * Validation based on the regexp support
  */
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidBuildContentModel(xmlValidCtxtPtr ctxt,
 					 xmlElementPtr elem);
 
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidatePushElement	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
 					 xmlNodePtr elem,
 					 const xmlChar *qname);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidatePushCData	(xmlValidCtxtPtr ctxt,
 					 const xmlChar *data,
 					 int len);
+XML_DEPRECATED
 XMLPUBFUN int
 		xmlValidatePopElement	(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc,
diff --git a/src/include/libxml/xmlerror.h b/src/include/libxml/xmlerror.h
index 373e5f6..7d83f45 100644
--- a/src/include/libxml/xmlerror.h
+++ b/src/include/libxml/xmlerror.h
@@ -478,6 +478,7 @@
     XML_IO_EADDRINUSE, /* 1554 */
     XML_IO_EALREADY, /* 1555 */
     XML_IO_EAFNOSUPPORT, /* 1556 */
+    XML_IO_UNSUPPORTED_PROTOCOL, /* 1557 */
     XML_XINCLUDE_RECURSION=1600,
     XML_XINCLUDE_PARSE_VALUE, /* 1601 */
     XML_XINCLUDE_ENTITY_DEF_MISMATCH, /* 1602 */
diff --git a/src/include/private/buf.h b/src/include/private/buf.h
index 678294f..982b9ee 100644
--- a/src/include/private/buf.h
+++ b/src/include/private/buf.h
@@ -28,10 +28,6 @@
 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len);
 XML_HIDDEN int
 xmlBufCat(xmlBufPtr buf, const xmlChar *str);
-XML_HIDDEN int
-xmlBufCCat(xmlBufPtr buf, const char *str);
-XML_HIDDEN int
-xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string);
 
 XML_HIDDEN size_t
 xmlBufAvail(const xmlBufPtr buf);
diff --git a/src/include/private/io.h b/src/include/private/io.h
index 01c2ced..a2535ae 100644
--- a/src/include/private/io.h
+++ b/src/include/private/io.h
@@ -27,6 +27,9 @@
 #ifdef LIBXML_OUTPUT_ENABLED
 XML_HIDDEN xmlOutputBufferPtr
 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
+XML_HIDDEN void
+xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf,
+                                 const xmlChar *string);
 #endif
 
 #endif /* XML_IO_H_PRIVATE__ */
diff --git a/src/include/private/parser.h b/src/include/private/parser.h
index c5df068..d7bb782 100644
--- a/src/include/private/parser.h
+++ b/src/include/private/parser.h
@@ -68,6 +68,8 @@
 xmlDetectEncoding(xmlParserCtxtPtr ctxt);
 XML_HIDDEN void
 xmlSetDeclaredEncoding(xmlParserCtxtPtr ctxt, xmlChar *encoding);
+XML_HIDDEN const xmlChar *
+xmlGetActualEncoding(xmlParserCtxtPtr ctxt);
 
 XML_HIDDEN xmlParserNsData *
 xmlParserNsCreate(void);
diff --git a/src/include/private/save.h b/src/include/private/save.h
index 6e16a2f..5d4a753 100644
--- a/src/include/private/save.h
+++ b/src/include/private/save.h
@@ -13,8 +13,8 @@
 xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur);
 
 XML_HIDDEN void
-xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
-                              xmlAttrPtr attr, const xmlChar * string);
+xmlBufAttrSerializeTxtContent(xmlOutputBufferPtr buf, xmlDocPtr doc,
+                              const xmlChar *string);
 XML_HIDDEN void
 xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
 
diff --git a/src/include/private/tree.h b/src/include/private/tree.h
index a88cb0e..2d651d5 100644
--- a/src/include/private/tree.h
+++ b/src/include/private/tree.h
@@ -9,8 +9,13 @@
 XML_HIDDEN extern int
 __xmlRegisterCallbacks;
 
-XML_HIDDEN xmlNsPtr
-xmlTreeEnsureXMLDecl(xmlDocPtr doc);
+XML_HIDDEN int
+xmlSearchNsSafe(xmlNodePtr node, const xmlChar *href, xmlNsPtr *out);
+XML_HIDDEN int
+xmlSearchNsByHrefSafe(xmlNodePtr node, const xmlChar *href, xmlNsPtr *out);
+
+XML_HIDDEN int
+xmlNodeParseContent(xmlNodePtr node, const xmlChar *content, int len);
 XML_HIDDEN xmlNodePtr
 xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
                   int extended);
diff --git a/src/nanohttp.c b/src/nanohttp.c
index 81da585..e508292 100644
--- a/src/nanohttp.c
+++ b/src/nanohttp.c
@@ -1388,7 +1388,7 @@
     }
 
     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
-	__xmlIOErr(XML_FROM_HTTP, XML_HTTP_URL_SYNTAX, "Not a valid HTTP URI");
+	__xmlIOErr(XML_FROM_IO, XML_IO_UNSUPPORTED_PROTOCOL, ctxt->protocol);
         xmlNanoHTTPFreeCtxt(ctxt);
 	if (redirURL != NULL) xmlFree(redirURL);
         return(NULL);
diff --git a/src/parser.c b/src/parser.c
index 8859e3c..95f3ed1 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -2980,13 +2980,6 @@
 
     if (cur == NULL) return(NULL);
 
-#ifndef XML_XML_NAMESPACE
-    /* xml: prefix is not really a namespace */
-    if ((cur[0] == 'x') && (cur[1] == 'm') &&
-        (cur[2] == 'l') && (cur[3] == ':'))
-	return(xmlStrdup(name));
-#endif
-
     /* nasty but well=formed */
     if (cur[0] == ':')
 	return(xmlStrdup(name));
@@ -8910,7 +8903,7 @@
             int nsIndex = (int) (ptrdiff_t) atts[2];
 
             if ((nsIndex == NS_INDEX_EMPTY) ? (uri == NULL) :
-                (nsIndex == NS_INDEX_XML) ? (uri == ctxt->str_xml) :
+                (nsIndex == NS_INDEX_XML) ? (uri == ctxt->str_xml_ns) :
                 (uri == ctxt->nsTab[nsIndex * 2 + 1]))
                 return(bucket->index);
         }
diff --git a/src/parserInternals.c b/src/parserInternals.c
index 4d3dc7f..fa69110 100644
--- a/src/parserInternals.c
+++ b/src/parserInternals.c
@@ -1398,6 +1398,30 @@
     ctxt->encoding = encoding;
 }
 
+/**
+ * xmlGetActualEncoding:
+ * @ctxt:  the parser context
+ *
+ * Returns the actual used to parse the document. This can differ from
+ * the declared encoding.
+ */
+const xmlChar *
+xmlGetActualEncoding(xmlParserCtxtPtr ctxt) {
+    const xmlChar *encoding = NULL;
+
+    if ((ctxt->input->flags & XML_INPUT_USES_ENC_DECL) ||
+        (ctxt->input->flags & XML_INPUT_AUTO_ENCODING)) {
+        /* Preserve encoding exactly */
+        encoding = ctxt->encoding;
+    } else if ((ctxt->input->buf) && (ctxt->input->buf->encoder)) {
+        encoding = BAD_CAST ctxt->input->buf->encoder->name;
+    } else if (ctxt->input->flags & XML_INPUT_HAS_ENCODING) {
+        encoding = BAD_CAST "UTF-8";
+    }
+
+    return(encoding);
+}
+
 /************************************************************************
  *									*
  *	Commodity functions to handle entities processing		*
diff --git a/src/testapi.c b/src/testapi.c
index 35c74fa..bbfb2a1 100644
--- a/src/testapi.c
+++ b/src/testapi.c
@@ -19789,7 +19789,7 @@
         root = gen_xmlNodePtr_in(n_root, 1);
 
         ret_val = xmlDocSetRootElement(doc, root);
-        if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }
+        if (ret_val == NULL) { xmlFreeNode(root) ; root = NULL ; }
         desret_xmlNodePtr(ret_val);
         call_tests++;
         des_xmlDocPtr(n_doc, doc, 0);
@@ -23412,9 +23412,10 @@
         second = gen_xmlNodePtr_in(n_second, 1);
 
         ret_val = xmlTextMerge(first, second);
-        if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
+        if (ret_val == NULL) {
               xmlUnlinkNode(second);
-              xmlFreeNode(second) ; second = NULL ; }
+              xmlFreeNode(second) ; second = NULL ;
+              ret_val = first; }
         desret_xmlNodePtr(ret_val);
         call_tests++;
         des_xmlNodePtr_in(n_first, first, 0);
diff --git a/src/testparser.c b/src/testparser.c
index 08965b5..cabc5f4 100644
--- a/src/testparser.c
+++ b/src/testparser.c
@@ -7,6 +7,7 @@
 #include <libxml/parser.h>
 #include <libxml/xmlreader.h>
 #include <libxml/xmlwriter.h>
+#include <libxml/HTMLparser.h>
 
 #include <string.h>
 
@@ -143,9 +144,72 @@
 
     return err;
 }
+
+#ifdef LIBXML_HTML_ENABLED
+static int
+testHtmlPushWithEncoding(void) {
+    htmlParserCtxtPtr ctxt;
+    htmlDocPtr doc;
+    htmlNodePtr node;
+    int err = 0;
+
+    ctxt = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL,
+                                    XML_CHAR_ENCODING_UTF8);
+    htmlParseChunk(ctxt, "-\xC3\xA4-", 4, 1);
+
+    doc = ctxt->myDoc;
+    if (!xmlStrEqual(doc->encoding, BAD_CAST "UTF-8")) {
+        fprintf(stderr, "testHtmlPushWithEncoding failed\n");
+        err = 1;
+    }
+
+    node = xmlDocGetRootElement(doc)->children->children->children;
+    if (!xmlStrEqual(node->content, BAD_CAST "-\xC3\xA4-")) {
+        fprintf(stderr, "testHtmlPushWithEncoding failed\n");
+        err = 1;
+    }
+
+    xmlFreeDoc(doc);
+    htmlFreeParserCtxt(ctxt);
+    return err;
+}
+#endif
 #endif
 
-#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_XINCLUDE_ENABLED)
+#ifdef LIBXML_READER_ENABLED
+static int
+testReaderEncoding(void) {
+    xmlBuffer *buf;
+    xmlTextReader *reader;
+    xmlChar *xml;
+    const xmlChar *encoding;
+    int err = 0;
+    int i;
+
+    buf = xmlBufferCreate();
+    xmlBufferCCat(buf, "<?xml version='1.0' encoding='ISO-8859-1'?>\n");
+    xmlBufferCCat(buf, "<doc>");
+    for (i = 0; i < 8192; i++)
+        xmlBufferCCat(buf, "x");
+    xmlBufferCCat(buf, "</doc>");
+    xml = xmlBufferDetach(buf);
+    xmlBufferFree(buf);
+
+    reader = xmlReaderForDoc(BAD_CAST xml, NULL, NULL, 0);
+    xmlTextReaderRead(reader);
+    encoding = xmlTextReaderConstEncoding(reader);
+
+    if (!xmlStrEqual(encoding, BAD_CAST "ISO-8859-1")) {
+        fprintf(stderr, "testReaderEncoding failed\n");
+        err = 1;
+    }
+
+    xmlFreeTextReader(reader);
+    xmlFree(xml);
+    return err;
+}
+
+#ifdef LIBXML_XINCLUDE_ENABLED
 typedef struct {
     char *message;
     int code;
@@ -223,6 +287,7 @@
     return err;
 }
 #endif
+#endif
 
 #ifdef LIBXML_WRITER_ENABLED
 static int
@@ -279,10 +344,16 @@
 #ifdef LIBXML_PUSH_ENABLED
     err |= testHugePush();
     err |= testHugeEncodedChunk();
+#ifdef LIBXML_HTML_ENABLED
+    err |= testHtmlPushWithEncoding();
 #endif
-#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_XINCLUDE_ENABLED)
+#endif
+#ifdef LIBXML_READER_ENABLED
+    err |= testReaderEncoding();
+#ifdef LIBXML_XINCLUDE_ENABLED
     err |= testReaderXIncludeError();
 #endif
+#endif
 #ifdef LIBXML_WRITER_ENABLED
     err |= testWriterClose();
 #endif
diff --git a/src/tree.c b/src/tree.c
index f9cab14..a8869fd 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -56,10 +56,17 @@
  ************************************************************************/
 
 static xmlNsPtr
-xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns);
+xmlNewReconciledNs(xmlNodePtr tree, xmlNsPtr ns);
+
+static xmlAttrPtr
+xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name,
+		       const xmlChar *nsName, int useDTD);
 
 static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
 
+static void
+xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree);
+
 /************************************************************************
  *									*
  *		A few static variables and macros			*
@@ -75,19 +82,6 @@
 
 static int xmlCompressMode = 0;
 
-#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) {		\
-    xmlNodePtr ulccur = (n)->children;					\
-    if (ulccur == NULL) {						\
-        (n)->last = NULL;						\
-    } else {								\
-        while (ulccur->next != NULL) {					\
-		ulccur->parent = (n);					\
-		ulccur = ulccur->next;					\
-	}								\
-	ulccur->parent = (n);						\
-	(n)->last = ulccur;						\
-}}
-
 #define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \
   (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0))
 
@@ -218,13 +212,6 @@
     *prefix = NULL;
     if (name == NULL) return(NULL);
 
-#ifndef XML_XML_NAMESPACE
-    /* xml: prefix is not really a namespace */
-    if ((name[0] == 'x') && (name[1] == 'm') &&
-        (name[2] == 'l') && (name[3] == ':'))
-	return(NULL);
-#endif
-
     /* nasty but valid */
     if (name[0] == ':')
 	return(NULL);
@@ -292,6 +279,18 @@
     return(&name[l+1]);
 }
 
+/**
+ * xmlSplitQName4:
+ * @name:  the full QName
+ * @prefixPtr:  pointer to resulting prefix
+ *
+ * Parse a QName. The return value points to the start of the local
+ * name in the input string. If the QName has a prefix, it will be
+ * allocated and stored in @prefixPtr. This string must be freed by
+ * the caller. If there's no prefix, @prefixPtr is set to NULL.
+ *
+ * Returns the local name or NULL if a memory allocation failed.
+ */
 const xmlChar *
 xmlSplitQName4(const xmlChar *name, xmlChar **prefixPtr) {
     xmlChar *prefix;
@@ -691,19 +690,21 @@
 
 /**
  * xmlNewNs:
- * @node:  the element carrying the namespace
+ * @node:  the element carrying the namespace (optional)
  * @href:  the URI associated
- * @prefix:  the prefix for the namespace
+ * @prefix:  the prefix for the namespace (optional)
  *
- * Creation of a new Namespace. This function will refuse to create
- * a namespace with a similar prefix than an existing one present on this
- * node.
- * Note that for a default namespace, @prefix should be NULL.
+ * Create a new namespace. For a default namespace, @prefix should be
+ * NULL. The namespace URI in @href is not checked. You should make sure
+ * to pass a valid URI.
  *
- * We use href==NULL in the case of an element creation where the namespace
- * was not defined.
+ * If @node is provided, it must be an element node. The namespace will
+ * be appended to the node's namespace declarations. It is an error if
+ * the node already has a definition for the prefix or default
+ * namespace.
  *
- * Returns a new namespace pointer or NULL
+ * Returns a new namespace pointer or NULL if arguments are invalid,
+ * the prefix is already in use or a memory allocation failed.
  */
 xmlNsPtr
 xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
@@ -742,13 +743,11 @@
 	} else {
 	    xmlNsPtr prev = node->nsDef;
 
-	    if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
-		(xmlStrEqual(prev->prefix, cur->prefix)))
+	    if (xmlStrEqual(prev->prefix, cur->prefix))
                 goto error;
 	    while (prev->next != NULL) {
 	        prev = prev->next;
-		if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
-		    (xmlStrEqual(prev->prefix, cur->prefix)))
+		if (xmlStrEqual(prev->prefix, cur->prefix))
                     goto error;
 	    }
 	    prev->next = cur;
@@ -764,9 +763,10 @@
 /**
  * xmlSetNs:
  * @node:  a node in the document
- * @ns:  a namespace pointer
+ * @ns:  a namespace pointer (optional)
  *
- * Associate a namespace to a node, a posteriori.
+ * Set the namespace of an element or attribute node. Passing a NULL
+ * namespace unsets the namespace.
  */
 void
 xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
@@ -782,7 +782,7 @@
  * xmlFreeNs:
  * @cur:  the namespace pointer
  *
- * Free up the structures associated to a namespace
+ * Free an xmlNs object.
  */
 void
 xmlFreeNs(xmlNsPtr cur) {
@@ -798,7 +798,7 @@
  * xmlFreeNsList:
  * @cur:  the first namespace pointer
  *
- * Free up all the structures associated to the chained namespaces.
+ * Free a list of xmlNs objects.
  */
 void
 xmlFreeNsList(xmlNsPtr cur) {
@@ -815,15 +815,21 @@
 
 /**
  * xmlNewDtd:
- * @doc:  the document pointer
- * @name:  the DTD name
- * @ExternalID:  the external ID
- * @SystemID:  the system ID
+ * @doc:  the document pointer (optional)
+ * @name:  the DTD name (optional)
+ * @ExternalID:  the external ID (optional)
+ * @SystemID:  the system ID (optional)
  *
- * Creation of a new DTD for the external subset. To create an
- * internal subset, use xmlCreateIntSubset().
+ * Create a DTD node.
  *
- * Returns a pointer to the new DTD structure
+ * If a document is provided, it is an error if it already has an
+ * external subset. If the document has no external subset, it
+ * will be set to the created DTD.
+ *
+ * To create an internal subset, use xmlCreateIntSubset().
+ *
+ * Returns a pointer to the new DTD object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlDtdPtr
 xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
@@ -875,10 +881,10 @@
  * xmlGetIntSubset:
  * @doc:  the document pointer
  *
- * Get the internal subset of a document
- * Returns a pointer to the DTD structure or NULL if not found
+ * Get the internal subset of a document.
+ *
+ * Returns a pointer to the DTD object or NULL if not found.
  */
-
 xmlDtdPtr
 xmlGetIntSubset(const xmlDoc *doc) {
     xmlNodePtr cur;
@@ -896,13 +902,20 @@
 
 /**
  * xmlCreateIntSubset:
- * @doc:  the document pointer
- * @name:  the DTD name
- * @ExternalID:  the external (PUBLIC) ID
- * @SystemID:  the system ID
+ * @doc:  the document pointer (optional)
+ * @name:  the DTD name (optional)
+ * @ExternalID:  the external (PUBLIC) ID (optional)
+ * @SystemID:  the system ID (optional)
  *
- * Create the internal subset of a document
- * Returns a pointer to the new DTD structure
+ * Create a DTD node.
+ *
+ * If a document is provided and it already has an internal subset,
+ * the existing DTD object is returned without creating a new object.
+ * If the document has no internal subset, it will be set to the
+ * created DTD.
+ *
+ * Returns a pointer to the new or existing DTD object or NULL if
+ * arguments are invalid or a memory allocation failed.
  */
 xmlDtdPtr
 xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
@@ -999,42 +1012,6 @@
 	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
 	    xmlFree((char *)(str));
 
-
-/**
- * DICT_COPY:
- * @str:  a string
- *
- * Copy a string using a "dict" dictionary in the current scope,
- * if available.
- */
-#define DICT_COPY(str, cpy) \
-    if (str) { \
-	if (dict) { \
-	    if (xmlDictOwns(dict, (const xmlChar *)(str))) \
-		cpy = (xmlChar *) (str); \
-	    else \
-		cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \
-	} else \
-	    cpy = xmlStrdup((const xmlChar *)(str)); }
-
-/**
- * DICT_CONST_COPY:
- * @str:  a string
- *
- * Copy a string using a "dict" dictionary in the current scope,
- * if available.
- */
-#define DICT_CONST_COPY(str, cpy) \
-    if (str) { \
-	if (dict) { \
-	    if (xmlDictOwns(dict, (const xmlChar *)(str))) \
-		cpy = (const xmlChar *) (str); \
-	    else \
-		cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \
-	} else \
-	    cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); }
-
-
 /**
  * xmlFreeDtd:
  * @cur:  the DTD structure to free up
@@ -1062,8 +1039,7 @@
 	 */
         while (c != NULL) {
 	    next = c->next;
-	    if ((c->type != XML_NOTATION_NODE) &&
-	        (c->type != XML_ELEMENT_DECL) &&
+	    if ((c->type != XML_ELEMENT_DECL) &&
 		(c->type != XML_ATTRIBUTE_DECL) &&
 		(c->type != XML_ENTITY_DECL)) {
 		xmlUnlinkNode(c);
@@ -1093,11 +1069,11 @@
 
 /**
  * xmlNewDoc:
- * @version:  xmlChar string giving the version of XML "1.0"
+ * @version:  XML version string like "1.0" (optional)
  *
- * Creates a new XML document
+ * Creates a new XML document. If version is NULL, "1.0" is used.
  *
- * Returns a new document
+ * Returns a new document or NULL if a memory allocation failed.
  */
 xmlDocPtr
 xmlNewDoc(const xmlChar *version) {
@@ -1141,7 +1117,7 @@
  * xmlFreeDoc:
  * @cur:  pointer to the document
  *
- * Free up all the structures used by a document, tree included.
+ * Free a document including all children and associated DTDs.
  */
 void
 xmlFreeDoc(xmlDocPtr cur) {
@@ -1191,48 +1167,52 @@
 }
 
 /**
- * xmlStringLenGetNodeList:
- * @doc:  the document
- * @value:  the value of the text
- * @len:  the length of the string value
+ * xmlNodeParseContentInternal:
+ * @doc:  a document (optional)
+ * @parent:  an element or attribute (optional)
+ * @value:  an attribute value
+ * @len:  maximum length of the attribute value
+ * @listPtr:  pointer to the resulting node list (optional)
  *
- * Parse the value string and build the node list associated. Should
- * produce a flat tree with only TEXTs and ENTITY_REFs.
- * Returns a pointer to the first child
+ * See xmlNodeParseContent.
+ *
+ * Returns 0 on success, -1 if a memory allocation failed.
  */
-xmlNodePtr
-xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) {
-    xmlNodePtr ret = NULL, head = NULL, last = NULL;
+static int
+xmlNodeParseContentInternal(const xmlDoc *doc, xmlNodePtr parent,
+                            const xmlChar *value, int len,
+                            xmlNodePtr *listPtr) {
+    xmlNodePtr head = NULL, last = NULL;
     xmlNodePtr node;
     xmlChar *val = NULL;
-    const xmlChar *cur, *end;
+    const xmlChar *cur;
     const xmlChar *q;
     xmlEntityPtr ent;
     xmlBufPtr buf;
+    int remaining;
 
-    /*
-     * 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 (listPtr != NULL)
+        *listPtr = NULL;
 
-    if (value == NULL) return(NULL);
+    if (len < 0)
+        remaining = INT_MAX;
+    else
+        remaining = len;
+
+    if (value == NULL)
+        goto done;
+
     cur = value;
-    end = cur + len;
 
-    buf = xmlBufCreateSize(0);
-    if (buf == NULL) return(NULL);
+    buf = xmlBufCreateSize(64);
+    if (buf == NULL)
+        return(-1);
     xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
 
     q = cur;
-    while ((cur < end) && (*cur != 0)) {
+    while ((remaining > 0) && (*cur != 0)) {
 	if (cur[0] == '&') {
 	    int charval = 0;
-	    xmlChar tmp;
 
 	    /*
 	     * Save the current text.
@@ -1240,15 +1220,15 @@
             if (cur != q) {
 		if (xmlBufAdd(buf, q, cur - q))
 		    goto out;
+	        q = cur;
 	    }
-	    q = cur;
-	    if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
+
+	    if ((remaining > 2) && (cur[1] == '#') && (cur[2] == 'x')) {
+	        int tmp = 0;
+
 		cur += 3;
-		if (cur < end)
-		    tmp = *cur;
-		else
-		    tmp = 0;
-		while (tmp != ';') { /* Non input consuming loop */
+                remaining -= 3;
+		while ((remaining > 0) && ((tmp = *cur) != ';')) {
 		    if ((tmp >= '0') && (tmp <= '9'))
 			charval = charval * 16 + (tmp - '0');
 		    else if ((tmp >= 'a') && (tmp <= 'f'))
@@ -1259,56 +1239,61 @@
 			charval = 0;
 			break;
 		    }
+                    if (charval > 0x110000)
+                        charval = 0x110000;
 		    cur++;
-		    if (cur < end)
-			tmp = *cur;
-		    else
-			tmp = 0;
+                    remaining--;
 		}
-		if (tmp == ';')
+		if (tmp == ';') {
 		    cur++;
+                    remaining--;
+                }
 		q = cur;
-	    } else if ((cur + 1 < end) && (cur[1] == '#')) {
+	    } else if ((remaining > 1) && (cur[1] == '#')) {
+	        int tmp = 0;
+
 		cur += 2;
-		if (cur < end)
-		    tmp = *cur;
-		else
-		    tmp = 0;
-		while (tmp != ';') { /* Non input consuming loops */
-                    /* Don't check for integer overflow, see above. */
+                remaining -= 2;
+		while ((remaining > 0) && ((tmp = *cur) != ';')) {
 		    if ((tmp >= '0') && (tmp <= '9'))
 			charval = charval * 10 + (tmp - '0');
 		    else {
 			charval = 0;
 			break;
 		    }
+                    if (charval > 0x110000)
+                        charval = 0x110000;
 		    cur++;
-		    if (cur < end)
-			tmp = *cur;
-		    else
-			tmp = 0;
+                    remaining--;
 		}
-		if (tmp == ';')
+		if (tmp == ';') {
 		    cur++;
+                    remaining--;
+                }
 		q = cur;
 	    } else {
 		/*
 		 * Read the entity string
 		 */
 		cur++;
+                remaining--;
 		q = cur;
-		while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
-		if ((cur >= end) || (*cur == 0))
+		while ((remaining > 0) && (*cur != 0) && (*cur != ';')) {
+                    cur++;
+                    remaining--;
+                }
+		if ((remaining <= 0) || (*cur == 0))
 		    break;
 		if (cur != q) {
-		    /*
-		     * Predefined entities don't generate nodes
-		     */
 		    val = xmlStrndup(q, cur - q);
+                    if (val == NULL)
+                        goto out;
 		    ent = xmlGetDocEntity(doc, val);
 		    if ((ent != NULL) &&
 			(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
-
+                        /*
+                         * Predefined entities don't generate nodes
+                         */
 			if (xmlBufCat(buf, ent->content))
 			    goto out;
 		    } else {
@@ -1320,72 +1305,77 @@
 			    if (node == NULL)
 				goto out;
 			    node->content = xmlBufDetach(buf);
+                            node->parent = parent;
 
 			    if (last == NULL) {
-				last = head = node;
+				head = node;
 			    } else {
-				last = xmlAddNextSibling(last, node);
+                                last->next = node;
+                                node->prev = last;
 			    }
+                            last = node;
+			}
+
+			if ((ent != NULL) &&
+                            ((ent->flags & XML_ENT_PARSED) == 0) &&
+                            ((ent->flags & XML_ENT_EXPANDING) == 0) &&
+                            (ent->content != NULL)) {
+                            int res;
+
+                            ent->flags |= XML_ENT_EXPANDING;
+                            res = xmlNodeParseContentInternal(doc,
+                                    (xmlNodePtr) ent, ent->content, -1, NULL);
+                            ent->flags &= ~XML_ENT_EXPANDING;
+                            if (res < 0)
+                                goto out;
+                            ent->flags |= XML_ENT_PARSED;
 			}
 
 			/*
 			 * Create a new REFERENCE_REF node
 			 */
-			node = xmlNewReference(doc, val);
+			node = xmlNewCharRef((xmlDocPtr) doc, val);
 			if (node == NULL)
 			    goto out;
-			else if ((ent != NULL) &&
-                                 ((ent->flags & XML_ENT_PARSED) == 0) &&
-                                 ((ent->flags & XML_ENT_EXPANDING) == 0)) {
-			    xmlNodePtr temp;
+                        node->parent = parent;
+                        node->last = (xmlNodePtr) ent;
+                        if (ent != NULL) {
+                            node->children = (xmlNodePtr) ent;
+                            node->content = ent->content;
+                        }
 
-                            /*
-                             * The entity should have been checked already,
-                             * but set the flag anyway to avoid recursion.
-                             */
-                            if (node->content != NULL) {
-                                ent->flags |= XML_ENT_EXPANDING;
-                                ent->children = xmlStringGetNodeList(doc,
-                                        node->content);
-                                ent->flags &= ~XML_ENT_EXPANDING;
-                                if (ent->children == NULL) {
-                                    xmlFreeNode(node);
-                                    goto out;
-                                }
-                            }
-                            ent->flags |= XML_ENT_PARSED;
-			    temp = ent->children;
-			    while (temp) {
-				temp->parent = (xmlNodePtr)ent;
-				ent->last = temp;
-				temp = temp->next;
-			    }
-			}
 			if (last == NULL) {
-			    last = head = node;
+			    head = node;
 			} else {
-			    last = xmlAddNextSibling(last, node);
+                            last->next = node;
+                            node->prev = last;
 			}
+                        last = node;
 		    }
 		    xmlFree(val);
                     val = NULL;
 		}
 		cur++;
+                remaining--;
 		q = cur;
 	    }
 	    if (charval != 0) {
 		xmlChar buffer[10];
 		int l;
 
+                if (charval >= 0x110000)
+                    charval = 0xFFFD; /* replacement character */
+
 		l = xmlCopyCharMultiByte(buffer, charval);
 		buffer[l] = 0;
 
 		if (xmlBufCat(buf, buffer))
 		    goto out;
-		charval = 0;
 	    }
-	} else
+	} else {
 	    cur++;
+            remaining--;
+        }
     }
 
     if (cur != q) {
@@ -1400,19 +1390,38 @@
 	node = xmlNewDocText(doc, NULL);
 	if (node == NULL)
             goto out;
+        node->parent = parent;
 	node->content = xmlBufDetach(buf);
 
 	if (last == NULL) {
 	    head = node;
 	} else {
-	    xmlAddNextSibling(last, node);
+            last->next = node;
+            node->prev = last;
 	}
+        last = node;
     } else if (head == NULL) {
         head = xmlNewDocText(doc, BAD_CAST "");
+        if (head == NULL)
+            goto out;
+        head->parent = parent;
+        last = head;
     }
 
-    ret = head;
-    head = NULL;
+    xmlBufFree(buf);
+
+done:
+    if (parent != NULL) {
+        if (parent->children != NULL)
+            xmlFreeNodeList(parent->children);
+        parent->children = head;
+        parent->last = last;
+    }
+
+    if (listPtr != NULL)
+        *listPtr = head;
+
+    return(0);
 
 out:
     xmlBufFree(buf);
@@ -1420,405 +1429,209 @@
         xmlFree(val);
     if (head != NULL)
         xmlFreeNodeList(head);
+    return(-1);
+}
+
+/**
+ * xmlNodeParseContent:
+ * @node:  an element or attribute
+ * @content:  text content with XML references
+ * @len:  maximum length of content
+ *
+ * Parse content and replace the node's children with the resulting
+ * node list.
+ *
+ * @content is expected to be a valid XML attribute value possibly
+ * containing character and entity references. Syntax errors
+ * and references to undeclared entities are ignored silently.
+ * Only references are handled, nested elements, comments or PIs are
+ * not.
+ *
+ * Returns 0 on success, -1 if a memory allocation failed.
+ */
+int
+xmlNodeParseContent(xmlNodePtr node, const xmlChar *content, int len) {
+    return(xmlNodeParseContentInternal(node->doc, node, content, len, NULL));
+}
+
+/**
+ * xmlStringLenGetNodeList:
+ * @doc:  a document (optional)
+ * @value:  an attribute value
+ * @len:  maximum length of the attribute value
+ *
+ * DEPRECATED: Use xmlNodeSetContentLen.
+ *
+ * See xmlStringGetNodeList.
+ *
+ * Returns a pointer to the first child or NULL if a memory
+ * allocation failed.
+ */
+xmlNodePtr
+xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) {
+    xmlNodePtr ret;
+
+    xmlNodeParseContentInternal(doc, NULL, value, len, &ret);
     return(ret);
 }
 
 /**
  * xmlStringGetNodeList:
- * @doc:  the document
- * @value:  the value of the attribute
+ * @doc:  a document (optional)
+ * @value:  an attribute value
  *
- * Parse the value string and build the node list associated. Should
- * produce a flat tree with only TEXTs and ENTITY_REFs.
- * Returns a pointer to the first child
+ * DEPRECATED: Use xmlNodeSetContent.
+ *
+ * Parse an attribute value and build a node list containing only
+ * text and entity reference nodes. The resulting nodes will be
+ * associated with the document if provided. The document is also
+ * used to look up entities.
+ *
+ * The input is not validated. Syntax errors or references to
+ * undeclared entities will be ignored silently with unspecified
+ * results.
+ *
+ * Returns a pointer to the first child or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) {
-    xmlNodePtr ret = NULL, head = NULL, last = NULL;
-    xmlNodePtr node;
-    xmlChar *val = NULL;
-    const xmlChar *cur = value;
-    const xmlChar *q;
-    xmlEntityPtr ent;
-    xmlBufPtr buf;
+    xmlNodePtr ret;
 
-    /*
-     * 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);
-    if (buf == NULL) return(NULL);
-    xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
-
-    q = cur;
-    while (*cur != 0) {
-	if (cur[0] == '&') {
-	    int charval = 0;
-	    xmlChar tmp;
-
-	    /*
-	     * Save the current text.
-	     */
-            if (cur != q) {
-		if (xmlBufAdd(buf, q, cur - q))
-		    goto out;
-	    }
-	    q = cur;
-	    if ((cur[1] == '#') && (cur[2] == 'x')) {
-		cur += 3;
-		tmp = *cur;
-		while (tmp != ';') { /* Non input consuming loop */
-		    if ((tmp >= '0') && (tmp <= '9'))
-			charval = charval * 16 + (tmp - '0');
-		    else if ((tmp >= 'a') && (tmp <= 'f'))
-			charval = charval * 16 + (tmp - 'a') + 10;
-		    else if ((tmp >= 'A') && (tmp <= 'F'))
-			charval = charval * 16 + (tmp - 'A') + 10;
-		    else {
-			charval = 0;
-			break;
-		    }
-		    cur++;
-		    tmp = *cur;
-		}
-		if (tmp == ';')
-		    cur++;
-		q = cur;
-	    } else if  (cur[1] == '#') {
-		cur += 2;
-		tmp = *cur;
-		while (tmp != ';') { /* Non input consuming loops */
-                    /* Don't check for integer overflow, see above. */
-		    if ((tmp >= '0') && (tmp <= '9'))
-			charval = charval * 10 + (tmp - '0');
-		    else {
-			charval = 0;
-			break;
-		    }
-		    cur++;
-		    tmp = *cur;
-		}
-		if (tmp == ';')
-		    cur++;
-		q = cur;
-	    } else {
-		/*
-		 * Read the entity string
-		 */
-		cur++;
-		q = cur;
-		while ((*cur != 0) && (*cur != ';')) cur++;
-		if (*cur == 0)
-		    break;
-		if (cur != q) {
-		    /*
-		     * Predefined entities don't generate nodes
-		     */
-		    val = xmlStrndup(q, cur - q);
-                    if (val == NULL)
-                        goto out;
-		    ent = xmlGetDocEntity(doc, val);
-		    if ((ent != NULL) &&
-			(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
-
-			if (xmlBufCat(buf, ent->content))
-			    goto out;
-
-		    } else {
-			/*
-			 * Flush buffer so far
-			 */
-			if (!xmlBufIsEmpty(buf)) {
-			    node = xmlNewDocText(doc, NULL);
-                            if (node == NULL)
-                                goto out;
-			    node->content = xmlBufDetach(buf);
-
-			    if (last == NULL) {
-				last = head = node;
-			    } else {
-				last = xmlAddNextSibling(last, node);
-			    }
-			}
-
-			/*
-			 * Create a new REFERENCE_REF node
-			 */
-			node = xmlNewReference(doc, val);
-			if (node == NULL)
-			    goto out;
-			if ((ent != NULL) &&
-                            ((ent->flags & XML_ENT_PARSED) == 0) &&
-                            ((ent->flags & XML_ENT_EXPANDING) == 0)) {
-			    xmlNodePtr temp;
-
-                            /*
-                             * The entity should have been checked already,
-                             * but set the flag anyway to avoid recursion.
-                             */
-                            if (node->content != NULL) {
-                                ent->flags |= XML_ENT_EXPANDING;
-                                ent->children = xmlStringGetNodeList(doc,
-                                        node->content);
-                                ent->flags &= ~XML_ENT_EXPANDING;
-                                if (ent->children == NULL) {
-                                    xmlFreeNode(node);
-                                    goto out;
-                                }
-                            }
-                            ent->flags |= XML_ENT_PARSED;
-			    temp = ent->children;
-			    while (temp) {
-				temp->parent = (xmlNodePtr)ent;
-				ent->last = temp;
-				temp = temp->next;
-			    }
-			}
-			if (last == NULL) {
-			    last = head = node;
-			} else {
-			    last = xmlAddNextSibling(last, node);
-			}
-		    }
-		    xmlFree(val);
-                    val = NULL;
-		}
-		cur++;
-		q = cur;
-	    }
-	    if (charval != 0) {
-		xmlChar buffer[10];
-		int len;
-
-		len = xmlCopyCharMultiByte(buffer, charval);
-		buffer[len] = 0;
-
-		if (xmlBufCat(buf, buffer))
-		    goto out;
-		charval = 0;
-	    }
-	} else
-	    cur++;
-    }
-    if ((cur != q) || (head == NULL)) {
-        /*
-	 * Handle the last piece of text.
-	 */
-	xmlBufAdd(buf, q, cur - q);
-    }
-
-    if (xmlBufIsEmpty(buf) <= 0) {
-	node = xmlNewDocText(doc, NULL);
-        if (node == NULL)
-            goto out;
-	node->content = xmlBufDetach(buf);
-        if (node->content == NULL) {
-            xmlFreeNode(node);
-            goto out;
-        }
-
-	if (last == NULL) {
-	    head = node;
-	} else {
-	    xmlAddNextSibling(last, node);
-	}
-    } else if (head == NULL) {
-        head = xmlNewDocText(doc, BAD_CAST "");
-    }
-
-    ret = head;
-    head = NULL;
-
-out:
-    xmlBufFree(buf);
-    if (val != NULL) xmlFree(val);
-    if (head != NULL) xmlFreeNodeList(head);
+    xmlNodeParseContentInternal(doc, NULL, value, -1, &ret);
     return(ret);
 }
 
 /**
- * xmlNodeListGetString:
- * @doc:  the document
- * @list:  a Node list
- * @inLine:  should we replace entity contents or show their external form
+ * xmlNodeListGetStringInternal:
+ * @doc:  a document (optional)
+ * @node:  a node list
+ * @escMode: escape mode (0 = no, 1 = elem, 2 = attr, 3 = raw)
  *
- * Build the string equivalent to the text contained in the Node list
- * made of TEXTs and ENTITY_REFs
- *
- * Returns a pointer to the string copy, the caller must free it with xmlFree().
+ * Returns a pointer to the string.
  */
-xmlChar *
-xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
-{
-    const xmlNode *node = list;
-    xmlChar *ret = NULL;
-    xmlEntityPtr ent;
-    int attr;
+static xmlChar *
+xmlNodeListGetStringInternal(xmlDocPtr doc, const xmlNode *node, int escMode) {
+    xmlBufPtr buf;
+    xmlChar *ret;
 
-    if (list == NULL)
-        return xmlStrdup(BAD_CAST "");
-    if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE))
-        attr = 1;
-    else
-        attr = 0;
+    if (node == NULL)
+        return(xmlStrdup(BAD_CAST ""));
+
+    if ((escMode == 0) &&
+        ((node->type == XML_TEXT_NODE) ||
+         (node->type == XML_CDATA_SECTION_NODE)) &&
+        (node->next == NULL)) {
+        if (node->content == NULL)
+            return(xmlStrdup(BAD_CAST ""));
+        return(xmlStrdup(node->content));
+    }
+
+    buf = xmlBufCreateSize(64);
+    if (buf == NULL)
+        return(NULL);
 
     while (node != NULL) {
         if ((node->type == XML_TEXT_NODE) ||
             (node->type == XML_CDATA_SECTION_NODE)) {
-            if (inLine) {
-                ret = xmlStrcat(ret, node->content);
-                if (ret == NULL)
-                    goto error;
-            } else {
-                xmlChar *buffer;
+            if (node->content != NULL) {
+                if (escMode == 0) {
+                    xmlBufCat(buf, node->content);
+                } else {
+                    xmlChar *encoded;
 
-		if (attr)
-		    buffer = xmlEncodeAttributeEntities(doc, node->content);
-		else
-		    buffer = xmlEncodeEntitiesReentrant(doc, node->content);
-                if (buffer == NULL)
-                    goto error;
-                ret = xmlStrcat(ret, buffer);
-                xmlFree(buffer);
-                if (ret == NULL)
-                    goto error;
+                    if (escMode == 1)
+                        encoded = xmlEncodeEntitiesReentrant(doc,
+                                                             node->content);
+                    else if (escMode == 2)
+                        encoded = xmlEncodeAttributeEntities(doc,
+                                                             node->content);
+                    else
+                        encoded = xmlEncodeSpecialChars(doc, node->content);
+                    if (encoded == NULL)
+                        goto error;
+                    xmlBufCat(buf, encoded);
+                    xmlFree(encoded);
+                }
             }
         } else if (node->type == XML_ENTITY_REF_NODE) {
-            if (inLine) {
-                ent = xmlGetDocEntity(doc, node->name);
-                if (ent != NULL) {
-                    if (ent->children != NULL) {
-                        xmlChar *buffer;
-
-                        /* an entity content can be any "well balanced chunk",
-                         * i.e. the result of the content [43] production:
-                         * http://www.w3.org/TR/REC-xml#NT-content.
-                         * So it can contain text, CDATA section or nested
-                         * entity reference nodes (among others).
-                         * -> we recursive  call xmlNodeListGetString()
-                         * which handles these types */
-                        buffer = xmlNodeListGetString(doc, ent->children, 1);
-                        if (buffer == NULL)
-                            goto error;
-                        ret = xmlStrcat(ret, buffer);
-                        xmlFree(buffer);
-                        if (ret == NULL)
-                            goto error;
-                    }
-                } else if (node->content != NULL) {
-                    ret = xmlStrcat(ret, node->content);
-                    if (ret == NULL)
-                        goto error;
-                }
+            if (escMode == 0) {
+                xmlBufGetNodeContent(buf, node);
             } else {
-                xmlChar buf[2];
-
-                buf[0] = '&';
-                buf[1] = 0;
-                ret = xmlStrncat(ret, buf, 1);
-                ret = xmlStrcat(ret, node->name);
-                buf[0] = ';';
-                buf[1] = 0;
-                ret = xmlStrncat(ret, buf, 1);
-                if (ret == NULL)
-                    goto error;
+                xmlBufAdd(buf, BAD_CAST "&", 1);
+                xmlBufCat(buf, node->name);
+                xmlBufAdd(buf, BAD_CAST ";", 1);
             }
         }
+
         node = node->next;
     }
-    if (ret == NULL)
-        ret = xmlStrdup(BAD_CAST "");
-    return (ret);
+
+    ret = xmlBufDetach(buf);
+    xmlBufFree(buf);
+    return(ret);
 
 error:
-    xmlFree(ret);
+    xmlBufFree(buf);
     return(NULL);
 }
 
+/**
+ * xmlNodeListGetString:
+ * @doc:  a document (optional)
+ * @list:  a node list of attribute children (optional)
+ * @inLine:  whether entity references are substituted
+ *
+ * Serializes attribute children (text and entity reference nodes)
+ * into a string. An empty list produces an empty string.
+ *
+ * If @inLine is true, entity references will be substituted.
+ * Otherwise, entity references will be kept and special characters
+ * like '&' as well as non-ASCII chars will be escaped. See
+ * xmlNodeListGetRawString for an alternative option.
+ *
+ * Returns a string or NULL if a memory allocation failed.
+ */
+xmlChar *
+xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine)
+{
+    int escMode;
+
+    if (inLine) {
+        escMode = 0;
+    } else {
+        if ((list != NULL) &&
+            (list->parent != NULL) &&
+            (list->parent->type == XML_ATTRIBUTE_NODE))
+            escMode = 2;
+        else
+            escMode = 1;
+    }
+
+    return(xmlNodeListGetStringInternal(doc, list, escMode));
+}
+
 #ifdef LIBXML_TREE_ENABLED
 /**
  * xmlNodeListGetRawString:
- * @doc:  the document
- * @list:  a Node list
- * @inLine:  should we replace entity contents or show their external form
+ * @doc:  a document (optional)
+ * @list:  a node list of attribute children (optional)
+ * @inLine:  whether entity references are substituted
  *
- * Builds the string equivalent to the text contained in the Node list
- * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
- * this function doesn't do any character encoding handling.
+ * Serializes attribute children (text and entity reference nodes)
+ * into a string. An empty list produces an empty string.
  *
- * Returns a pointer to the string copy, the caller must free it with xmlFree().
+ * If @inLine is true, entity references will be substituted.
+ * Otherwise, entity references will be kept and special characters
+ * like '&' will be escaped.
+ *
+ * Returns a string or NULL if a memory allocation failed.
  */
 xmlChar *
 xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine)
 {
-    const xmlNode *node = list;
-    xmlChar *ret = NULL;
-    xmlEntityPtr ent;
-
-    if (list == NULL)
-        return xmlStrdup(BAD_CAST "");
-
-    while (node != NULL) {
-        if ((node->type == XML_TEXT_NODE) ||
-            (node->type == XML_CDATA_SECTION_NODE)) {
-            if (inLine) {
-                ret = xmlStrcat(ret, node->content);
-            } else {
-                xmlChar *buffer;
-
-                buffer = xmlEncodeSpecialChars(doc, node->content);
-                if (buffer != NULL) {
-                    ret = xmlStrcat(ret, buffer);
-                    xmlFree(buffer);
-                }
-            }
-        } else if (node->type == XML_ENTITY_REF_NODE) {
-            if (inLine) {
-                ent = xmlGetDocEntity(doc, node->name);
-                if (ent != NULL) {
-                    xmlChar *buffer;
-
-                    /* an entity content can be any "well balanced chunk",
-                     * i.e. the result of the content [43] production:
-                     * http://www.w3.org/TR/REC-xml#NT-content.
-                     * So it can contain text, CDATA section or nested
-                     * entity reference nodes (among others).
-                     * -> we recursive  call xmlNodeListGetRawString()
-                     * which handles these types */
-                    buffer =
-                        xmlNodeListGetRawString(doc, ent->children, 1);
-                    if (buffer != NULL) {
-                        ret = xmlStrcat(ret, buffer);
-                        xmlFree(buffer);
-                    }
-                } else {
-                    ret = xmlStrcat(ret, node->content);
-                }
-            } else {
-                xmlChar buf[2];
-
-                buf[0] = '&';
-                buf[1] = 0;
-                ret = xmlStrncat(ret, buf, 1);
-                ret = xmlStrcat(ret, node->name);
-                buf[0] = ';';
-                buf[1] = 0;
-                ret = xmlStrncat(ret, buf, 1);
-            }
-        }
-        node = node->next;
-    }
-    if (ret == NULL)
-        ret = xmlStrdup(BAD_CAST "");
-    return (ret);
+    int escMode = inLine ? 0 : 3;
+    return(xmlNodeListGetStringInternal((xmlDocPtr) doc, list, escMode));
 }
 #endif /* LIBXML_TREE_ENABLED */
 
@@ -1884,12 +1697,16 @@
                 cur->last = tmp;
             tmp = tmp->next;
         }
-    }
 
-    if ((value != NULL) && (node != NULL) &&
-        (xmlIsID(node->doc, node, cur) == 1) &&
-        (xmlAddIDSafe(node->doc, value, cur, 0, NULL) < 0))
-        goto error;
+        if (doc != NULL) {
+            int res = xmlIsID(doc, node, cur);
+
+            if (res < 0)
+                goto error;
+            if ((res == 1) && (xmlAddIDSafe(cur, value) < 0))
+                goto error;
+        }
+    }
 
     /*
      * Add it at the end to preserve parsing order ...
@@ -1920,12 +1737,20 @@
     defined(LIBXML_SCHEMAS_ENABLED)
 /**
  * xmlNewProp:
- * @node:  the holding node
+ * @node:  the parent node (optional)
  * @name:  the name of the attribute
- * @value:  the value of the attribute
+ * @value:  the value of the attribute (optional)
  *
- * Create a new property carried by a node.
- * Returns a pointer to the attribute
+ * Create an attribute node.
+ *
+ * If provided, @value should be a raw, unescaped string.
+ *
+ * If @node is provided, the created attribute will be appended without
+ * checking for duplicate names. It is an error if @node is not an
+ * element.
+ *
+ * Returns a pointer to the attribute or NULL if arguments are invalid
+ * or a memory allocation failed.
  */
 xmlAttrPtr
 xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
@@ -1940,13 +1765,21 @@
 
 /**
  * xmlNewNsProp:
- * @node:  the holding node
- * @ns:  the namespace
- * @name:  the name of the attribute
- * @value:  the value of the attribute
+ * @node:  the parent node (optional)
+ * @ns:  the namespace (optional)
+ * @name:  the local name of the attribute
+ * @value:  the value of the attribute (optional)
  *
- * Create a new property tagged with a namespace and carried by a node.
- * Returns a pointer to the attribute
+ * Create an attribute object.
+ *
+ * If provided, @value should be a raw, unescaped string.
+ *
+ * If @node is provided, the created attribute will be appended without
+ * checking for duplicate names. It is an error if @node is not an
+ * element.
+ *
+ * Returns a pointer to the attribute or NULL if arguments are invalid
+ * or a memory allocation failed.
  */
 xmlAttrPtr
 xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
@@ -1961,13 +1794,17 @@
 
 /**
  * xmlNewNsPropEatName:
- * @node:  the holding node
- * @ns:  the namespace
- * @name:  the name of the attribute
- * @value:  the value of the attribute
+ * @node:  the parent node (optional)
+ * @ns:  the namespace (optional)
+ * @name:  the local name of the attribute
+ * @value:  the value of the attribute (optional)
  *
- * Create a new property tagged with a namespace and carried by a node.
- * Returns a pointer to the attribute
+ * Like xmlNewNsProp, but the @name string will be used directly
+ * without making a copy. Takes ownership of @name which will also
+ * be freed on error.
+ *
+ * Returns a pointer to the attribute or NULL if arguments are invalid
+ * or a memory allocation failed.
  */
 xmlAttrPtr
 xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
@@ -1982,17 +1819,19 @@
 
 /**
  * xmlNewDocProp:
- * @doc:  the document
+ * @doc:  the target document (optional)
  * @name:  the name of the attribute
- * @value:  the value of the attribute
+ * @value:  attribute value with XML references (optional)
  *
- * Create a new property carried by a document.
- * NOTE: @value is supposed to be a piece of XML CDATA, so it allows entity
- *       references, but XML special chars need to be escaped first by using
- *       xmlEncodeEntitiesReentrant(). Use xmlNewProp() if you don't need
- *       entities support.
+ * Create an attribute object.
  *
- * Returns a pointer to the attribute
+ * If provided, @value is expected to be a valid XML attribute value
+ * possibly containing character and entity references. Syntax errors
+ * and references to undeclared entities are ignored silently.
+ * If you want to pass a raw string, see xmlNewProp.
+ *
+ * Returns a pointer to the attribute or NULL if arguments are invalid
+ * or a memory allocation failed.
  */
 xmlAttrPtr
 xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
@@ -2019,18 +1858,8 @@
         goto error;
     cur->doc = doc;
     if (value != NULL) {
-	xmlNodePtr tmp;
-
-	cur->children = xmlStringGetNodeList(doc, value);
-	cur->last = NULL;
-
-	tmp = cur->children;
-	while (tmp != NULL) {
-	    tmp->parent = (xmlNodePtr) cur;
-	    if (tmp->next == NULL)
-		cur->last = tmp;
-	    tmp = tmp->next;
-	}
+	if (xmlNodeParseContent((xmlNodePtr) cur, value, -1) < 0)
+            goto error;
     }
 
     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
@@ -2044,9 +1873,9 @@
 
 /**
  * xmlFreePropList:
- * @cur:  the first property in the list
+ * @cur:  the first attribute in the list
  *
- * Free a property and all its siblings, all the children are freed too.
+ * Free an attribute list including all children.
  */
 void
 xmlFreePropList(xmlAttrPtr cur) {
@@ -2063,7 +1892,7 @@
  * xmlFreeProp:
  * @cur:  an attribute
  *
- * Free one attribute, all the content is freed too
+ * Free an attribute including all children.
  */
 void
 xmlFreeProp(xmlAttrPtr cur) {
@@ -2088,10 +1917,14 @@
  * xmlRemoveProp:
  * @cur:  an attribute
  *
- * Unlink and free one attribute, all the content is freed too
- * Note this doesn't work for namespace definition attributes
+ * Unlink and free an attribute including all children.
  *
- * Returns 0 if success and -1 in case of error.
+ * Note this doesn't work for namespace declarations.
+ *
+ * The attribute must have a non-NULL parent pointer.
+ *
+ * Returns 0 on success or -1 if the attribute was not found or
+ * arguments are invalid.
  */
 int
 xmlRemoveProp(xmlAttrPtr cur) {
@@ -2125,12 +1958,14 @@
 
 /**
  * xmlNewDocPI:
- * @doc:  the target document
- * @name:  the processing instruction name
- * @content:  the PI content
+ * @doc:  the target document (optional)
+ * @name:  the processing instruction target
+ * @content:  the PI content (optional)
  *
- * Creation of a processing instruction element.
- * Returns a pointer to the new node object.
+ * Create a processing instruction object.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) {
@@ -2173,14 +2008,15 @@
 
 /**
  * xmlNewPI:
- * @name:  the processing instruction name
- * @content:  the PI content
+ * @name:  the processing instruction target
+ * @content:  the PI content (optional)
  *
- * Creation of a processing instruction element.
+ * Create a processing instruction node.
  *
  * Use of this function is DISCOURAGED in favor of xmlNewDocPI.
  *
- * Returns a pointer to the new node object.
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewPI(const xmlChar *name, const xmlChar *content) {
@@ -2189,117 +2025,122 @@
 
 /**
  * xmlNewNode:
- * @ns:  namespace if any
+ * @ns:  namespace (optional)
  * @name:  the node name
  *
- * Creation of a new node element. @ns is optional (NULL).
+ * Create an element node.
  *
  * Use of this function is DISCOURAGED in favor of xmlNewDocNode.
  *
- * Returns a pointer to the new node object. Uses xmlStrdup() to make
- * copy of @name.
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
-    xmlNodePtr cur;
-
-    if (name == NULL) {
-	return(NULL);
-    }
-
-    /*
-     * Allocate a new node and fill the fields.
-     */
-    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
-    if (cur == NULL)
-	return(NULL);
-    memset(cur, 0, sizeof(xmlNode));
-    cur->type = XML_ELEMENT_NODE;
-
-    cur->name = xmlStrdup(name);
-    if (cur->name == NULL)
-        goto error;
-    cur->ns = ns;
-
-    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
-	xmlRegisterNodeDefaultValue(cur);
-    return(cur);
-
-error:
-    xmlFreeNode(cur);
-    return(NULL);
+    return(xmlNewDocNode(NULL, ns, name, NULL));
 }
 
 /**
  * xmlNewNodeEatName:
- * @ns:  namespace if any
+ * @ns:  namespace (optional)
  * @name:  the node name
  *
- * Creation of a new node element. @ns is optional (NULL).
+ * Create an element node.
  *
  * Use of this function is DISCOURAGED in favor of xmlNewDocNodeEatName.
  *
- * Returns a pointer to the new node object, with pointer @name as
- * new node's name. Use xmlNewNode() if a copy of @name string is
- * is needed as new node's name.
+ * Like xmlNewNode, but the @name string will be used directly
+ * without making a copy. Takes ownership of @name which will also
+ * be freed on error.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) {
+    return(xmlNewDocNodeEatName(NULL, ns, name, NULL));
+}
+
+static xmlNodePtr
+xmlNewElem(xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name,
+           const xmlChar *content) {
     xmlNodePtr cur;
 
-    if (name == NULL) {
-	return(NULL);
-    }
-
-    /*
-     * Allocate a new node and fill the fields.
-     */
     cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
     if (cur == NULL)
 	return(NULL);
     memset(cur, 0, sizeof(xmlNode));
-    cur->type = XML_ELEMENT_NODE;
 
+    cur->type = XML_ELEMENT_NODE;
+    cur->doc = doc;
     cur->name = name;
     cur->ns = ns;
 
+    if (content != NULL) {
+        if (xmlNodeParseContent(cur, content, -1) < 0) {
+            /* Don't free name on error */
+            xmlFree(cur);
+            return(NULL);
+        }
+    }
+
     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
 	xmlRegisterNodeDefaultValue((xmlNodePtr)cur);
+
     return(cur);
 }
 
 /**
  * xmlNewDocNode:
- * @doc:  the document
- * @ns:  namespace if any
+ * @doc:  the target document
+ * @ns:  namespace (optional)
  * @name:  the node name
- * @content:  the XML text content if any
+ * @content:  text content with XML references (optional)
  *
- * Creation of a new node element within a document. @ns and @content
- * are optional (NULL).
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
- *       references, but XML special chars need to be escaped first by using
- *       xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
- *       need entities support.
+ * Create an element node.
  *
- * Returns a pointer to the new node object.
+ * If provided, @content is expected to be a valid XML attribute value
+ * possibly containing character and entity references. Syntax errors
+ * and references to undeclared entities are ignored silently.
+ * Only references are handled, nested elements, comments or PIs are
+ * not. See xmlNewDocRawNode for an alternative.
+ *
+ * General notes on object creation:
+ *
+ * Each node and all its children are associated with the same
+ * document. The document should be provided when creating nodes to
+ * avoid a performance penalty when adding the node to a document
+ * tree. Note that a document only owns nodes reachable from the root
+ * node. Unlinked subtrees must be freed manually.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
               const xmlChar *name, const xmlChar *content) {
     xmlNodePtr cur;
+    xmlChar *copy;
 
-    if ((doc != NULL) && (doc->dict != NULL))
-        cur = xmlNewNodeEatName(ns, (xmlChar *)
-	                        xmlDictLookup(doc->dict, name, -1));
-    else
-	cur = xmlNewNode(ns, name);
-    if (cur != NULL) {
-        cur->doc = doc;
-	if (content != NULL) {
-	    cur->children = xmlStringGetNodeList(doc, content);
-	    UPDATE_LAST_CHILD_AND_PARENT(cur)
-	}
+    if (name == NULL)
+        return(NULL);
+
+    if ((doc != NULL) && (doc->dict != NULL)) {
+        const xmlChar *dictName = xmlDictLookup(doc->dict, name, -1);
+
+        if (dictName == NULL)
+            return(NULL);
+        return(xmlNewElem(doc, ns, dictName, content));
+    }
+
+    copy = xmlStrdup(name);
+    if (copy == NULL)
+        return(NULL);
+
+    cur = xmlNewElem(doc, ns, copy, content);
+    if (cur == NULL) {
+        xmlFree(copy);
+        return(NULL);
     }
 
     return(cur);
@@ -2307,58 +2148,56 @@
 
 /**
  * xmlNewDocNodeEatName:
- * @doc:  the document
- * @ns:  namespace if any
+ * xmlNewDocNode:
+ * @doc:  the target document
+ * @ns:  namespace (optional)
  * @name:  the node name
- * @content:  the XML text content if any
+ * @content:  text content with XML references (optional)
  *
- * Creation of a new node element within a document. @ns and @content
- * are optional (NULL).
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
- *       references, but XML special chars need to be escaped first by using
- *       xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
- *       need entities support.
+ * Create an element node.
  *
- * Returns a pointer to the new node object.
+ * Like xmlNewDocNode, but the @name string will be used directly
+ * without making a copy. Takes ownership of @name which will also
+ * be freed on error.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns,
-              xmlChar *name, const xmlChar *content) {
+                     xmlChar *name, const xmlChar *content) {
     xmlNodePtr cur;
 
-    cur = xmlNewNodeEatName(ns, name);
-    if (cur != NULL) {
-        cur->doc = doc;
-	if (content != NULL) {
-	    cur->children = xmlStringGetNodeList(doc, content);
-            if (cur->children == NULL) {
-                xmlFreeNode(cur);
-                return(NULL);
-            }
-	    UPDATE_LAST_CHILD_AND_PARENT(cur)
-	}
-    } else {
-        /* if name don't come from the doc dictionary free it here */
-        if ((name != NULL) &&
-            ((doc == NULL) || (doc->dict == NULL) ||
-	     (!(xmlDictOwns(doc->dict, name)))))
-	    xmlFree(name);
+    if (name == NULL)
+        return(NULL);
+
+    cur = xmlNewElem(doc, ns, name, content);
+    if (cur == NULL) {
+        /* if name doesn't come from the doc dictionary free it here */
+        if ((doc == NULL) ||
+            (doc->dict == NULL) ||
+            (!xmlDictOwns(doc->dict, name)))
+            xmlFree(name);
+        return(NULL);
     }
+
     return(cur);
 }
 
 #ifdef LIBXML_TREE_ENABLED
 /**
  * xmlNewDocRawNode:
- * @doc:  the document
- * @ns:  namespace if any
+ * @doc:  the target document
+ * @ns:  namespace (optional)
  * @name:  the node name
- * @content:  the text content if any
+ * @content:  raw text content (optional)
  *
- * Creation of a new node element within a document. @ns and @content
- * are optional (NULL).
+ * Create an element node.
  *
- * Returns a pointer to the new node object.
+ * If provided, @value should be a raw, unescaped string.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
@@ -2369,8 +2208,17 @@
     if (cur != NULL) {
         cur->doc = doc;
 	if (content != NULL) {
-	    cur->children = xmlNewDocText(doc, content);
-	    UPDATE_LAST_CHILD_AND_PARENT(cur)
+            xmlNodePtr text;
+
+	    text = xmlNewDocText(doc, content);
+            if (text == NULL) {
+                xmlFreeNode(cur);
+                return(NULL);
+            }
+
+            cur->children = text;
+            cur->last = text;
+            text->parent = cur;
 	}
     }
     return(cur);
@@ -2378,10 +2226,12 @@
 
 /**
  * xmlNewDocFragment:
- * @doc:  the document owning the fragment
+ * @doc:  the target document (optional)
  *
- * Creation of a new Fragment node.
- * Returns a pointer to the new node object.
+ * Create a document fragment node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlNewDocFragment(xmlDocPtr doc) {
@@ -2406,13 +2256,14 @@
 
 /**
  * xmlNewText:
- * @content:  the text content
+ * @content:  raw text content (optional)
  *
- * Creation of a new text node.
+ * Create a text node.
  *
  * Use of this function is DISCOURAGED in favor of xmlNewDocText.
  *
- * Returns a pointer to the new node object.
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlNewText(const xmlChar *content) {
@@ -2447,62 +2298,52 @@
 /**
  * xmlNewTextChild:
  * @parent:  the parent node
- * @ns:  a namespace if any
+ * @ns:  a namespace (optional)
  * @name:  the name of the child
- * @content:  the text content of the child if any.
+ * @content:  raw text content of the child (optional)
  *
- * Creation of a new child element, added at the end of @parent children list.
- * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
- * created element inherits the namespace of @parent. If @content is non NULL,
- * a child TEXT node will be created containing the string @content.
- * NOTE: Use xmlNewChild() if @content will contain entities that need to be
- * preserved. Use this function, xmlNewTextChild(), if you need to ensure that
- * reserved XML chars that might appear in @content, such as the ampersand,
- * greater-than or less-than signs, are automatically replaced by their XML
- * escaped entity representations.
+ * Create a new child element and append it to a parent element.
  *
- * Returns a pointer to the new node object.
+ * If @ns is NULL, the newly created element inherits the namespace
+ * of the parent.
+ *
+ * If @content is provided, a text node will be added to the child
+ * element, see xmlNewDocRawNode.
+ *
+ * Returns a pointer to the new node object or NULL if arguments
+ * are invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
             const xmlChar *name, const xmlChar *content) {
     xmlNodePtr cur, prev;
 
-    if (parent == NULL) {
+    if ((parent == NULL) || (name == NULL))
 	return(NULL);
+
+    switch (parent->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+            break;
+
+        case XML_ELEMENT_NODE:
+            if (ns == NULL)
+                ns = parent->ns;
+            break;
+
+        default:
+            return(NULL);
     }
 
-    if (name == NULL) {
-	return(NULL);
-    }
-
-    /*
-     * Allocate a new node
-     */
-    if (parent->type == XML_ELEMENT_NODE) {
-	if (ns == NULL)
-	    cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
-	else
-	    cur = xmlNewDocRawNode(parent->doc, ns, name, content);
-    } else if ((parent->type == XML_DOCUMENT_NODE) ||
-	       (parent->type == XML_HTML_DOCUMENT_NODE)) {
-	if (ns == NULL)
-	    cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content);
-	else
-	    cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content);
-    } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
-	    cur = xmlNewDocRawNode( parent->doc, ns, name, content);
-    } else {
-	return(NULL);
-    }
-    if (cur == NULL) return(NULL);
+    cur = xmlNewDocRawNode(parent->doc, ns, name, content);
+    if (cur == NULL)
+        return(NULL);
 
     /*
      * add the new element at the end of the children list.
      */
-    cur->type = XML_ELEMENT_NODE;
     cur->parent = parent;
-    cur->doc = parent->doc;
     if (parent->children == NULL) {
         parent->children = cur;
 	parent->last = cur;
@@ -2519,11 +2360,19 @@
 
 /**
  * xmlNewCharRef:
- * @doc: the document
- * @name:  the char ref string, starting with # or "&# ... ;"
+ * @doc: the target document (optional)
+ * @name:  the entity name
  *
- * Creation of a new character reference node.
- * Returns a pointer to the new node object.
+ * This function is MISNAMED. It doesn't create a character reference
+ * but an entity reference.
+ *
+ * Create an empty entity reference node. This function doesn't attempt
+ * to look up the entity in @doc.
+ *
+ * Entity names like '&entity;' are handled as well.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
@@ -2566,11 +2415,16 @@
 
 /**
  * xmlNewReference:
- * @doc: the document
- * @name:  the reference name, or the reference string with & and ;
+ * @doc: the target document (optional)
+ * @name:  the entity name
  *
- * Creation of a new reference node.
- * Returns a pointer to the new node object.
+ * Create a new entity reference node, linking the result with the
+ * entity in @doc if found.
+ *
+ * Entity names like '&entity;' are handled as well.
+ *
+ * Returns a pointer to the new node object or NULL if arguments are
+ * invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewReference(const xmlDoc *doc, const xmlChar *name) {
@@ -2626,11 +2480,13 @@
 
 /**
  * xmlNewDocText:
- * @doc: the document
- * @content:  the text content
+ * @doc:  the target document
+ * @content:  raw text content (optional)
  *
- * Creation of a new text node within a document.
- * Returns a pointer to the new node object.
+ * Create a new text node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
@@ -2643,13 +2499,13 @@
 
 /**
  * xmlNewTextLen:
- * @content:  the text content
- * @len:  the text len.
+ * @content:  raw text content (optional)
+ * @len:  size of text content
  *
  * Use of this function is DISCOURAGED in favor of xmlNewDocTextLen.
  *
- * Creation of a new text node with an extra parameter for the content's length
- * Returns a pointer to the new node object.
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlNewTextLen(const xmlChar *content, int len) {
@@ -2667,6 +2523,10 @@
     cur->name = xmlStringText;
     if (content != NULL) {
 	cur->content = xmlStrndup(content, len);
+        if (cur->content == NULL) {
+            xmlFreeNode(cur);
+            return(NULL);
+        }
     }
 
     if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
@@ -2676,13 +2536,14 @@
 
 /**
  * xmlNewDocTextLen:
- * @doc: the document
- * @content:  the text content
- * @len:  the text len.
+ * @doc:  the target document
+ * @content:  raw text content (optional)
+ * @len:  size of text content
  *
- * Creation of a new text node with an extra content length parameter. The
- * text node pertain to a given document.
- * Returns a pointer to the new node object.
+ * Create a new text node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
@@ -2695,12 +2556,14 @@
 
 /**
  * xmlNewComment:
- * @content:  the comment content
+ * @content:  the comment content (optional)
  *
  * Use of this function is DISCOURAGED in favor of xmlNewDocComment.
  *
- * Creation of a new node containing a comment.
- * Returns a pointer to the new node object.
+ * Create a comment node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlNewComment(const xmlChar *content) {
@@ -2733,12 +2596,14 @@
 
 /**
  * xmlNewCDataBlock:
- * @doc:  the document
- * @content:  the CDATA block content content
- * @len:  the length of the block
+ * @doc:  the target document (optional)
+ * @content:  raw text content (optional)
+ * @len:  size of text content
  *
- * Creation of a new node containing a CDATA block.
- * Returns a pointer to the new node object.
+ * Create a CDATA section node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
@@ -2772,8 +2637,10 @@
  * @doc:  the document
  * @content:  the comment content
  *
- * Creation of a new node containing a comment within a document.
- * Returns a pointer to the new node object.
+ * Create a comment node.
+ *
+ * Returns a pointer to the new node object or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
@@ -2784,166 +2651,231 @@
     return(cur);
 }
 
-static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) {
-    const xmlChar *newValue = oldValue;
-    if (oldValue) {
-        int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1);
-        if (oldDictOwnsOldValue) {
+static int
+xmlNodeSetDoc(xmlNodePtr node, xmlDocPtr doc) {
+    xmlDocPtr oldDoc;
+    xmlDictPtr oldDict, newDict;
+    int ret = 0;
+
+    /*
+     * Remove name and content from old dictionary
+     */
+
+    oldDoc = node->doc;
+    oldDict = oldDoc ? oldDoc->dict : NULL;
+    newDict = doc ? doc->dict : NULL;
+
+    if ((oldDict != NULL) && (oldDict != newDict)) {
+        if ((node->name != NULL) &&
+            ((node->type == XML_ELEMENT_NODE) ||
+             (node->type == XML_ATTRIBUTE_NODE) ||
+             (node->type == XML_PI_NODE) ||
+             (node->type == XML_ENTITY_REF_NODE)) &&
+            (xmlDictOwns(oldDict, node->name))) {
             if (newDict)
-                newValue = xmlDictLookup(newDict, oldValue, -1);
+                node->name = xmlDictLookup(newDict, node->name, -1);
             else
-                newValue = xmlStrdup(oldValue);
+                node->name = xmlStrdup(node->name);
+            if (node->name == NULL)
+                ret = -1;
+        }
+
+        if ((node->content != NULL) &&
+            ((node->type == XML_TEXT_NODE) ||
+             (node->type == XML_CDATA_SECTION_NODE)) &&
+            (xmlDictOwns(oldDict, node->content))) {
+            node->content = xmlStrdup(node->content);
+            if (node->content == NULL)
+                ret = -1;
         }
     }
-    return newValue;
+
+    /*
+     * Handle IDs
+     *
+     * TODO: ID attributes should also be added to the new
+     * document, but it's not clear how to handle clashes.
+     */
+    if (node->type == XML_ATTRIBUTE_NODE) {
+        xmlAttrPtr attr = (xmlAttrPtr) node;
+
+        if (attr->atype == XML_ATTRIBUTE_ID)
+            xmlRemoveID(oldDoc, attr);
+    }
+
+    /*
+     * Handle entity references
+     */
+    if (node->type == XML_ENTITY_REF_NODE) {
+        node->children = NULL;
+        node->last = NULL;
+        node->content = NULL;
+
+        if ((doc != NULL) &&
+            ((doc->intSubset != NULL) || (doc->extSubset != NULL))) {
+            xmlEntityPtr ent;
+
+            /*
+            * Assign new entity node if available
+            */
+            ent = xmlGetDocEntity(doc, node->name);
+            if (ent != NULL) {
+                node->children = (xmlNodePtr) ent;
+                node->last = (xmlNodePtr) ent;
+                node->content = ent->content;
+            }
+        }
+    }
+
+    /*
+     * Set new document
+     */
+    node->doc = doc;
+
+    return(ret);
 }
 
 /**
  * xmlSetTreeDoc:
- * @tree:  the top element
- * @doc:  the document
+ * @tree:  root of a subtree
+ * @doc:  new document
  *
- * update all nodes under the tree to point to the right document
+ * This is an internal function which shouldn't be used. It is
+ * invoked by functions like xmlAddChild, xmlAddSibling or
+ * xmlReplaceNode. @tree must be the root node of an unlinked
+ * subtree.
+ *
+ * Associate all nodes in a tree with a new document.
+ *
+ * Also copy strings from the old document's dictionary and
+ * remove ID attributes from the old ID table.
+ *
+ * Returns 0 on success. If a memory allocation fails, returns -1.
+ * The whole tree will be updated on failure but some strings
+ * may be lost.
  */
-void
+int
 xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
-    xmlAttrPtr prop;
+    int ret = 0;
 
     if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
-	return;
-    if (tree->doc != doc) {
-        xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL;
-        xmlDictPtr newDict = doc ? doc->dict : NULL;
+	return(0);
+    if (tree->doc == doc)
+        return(0);
 
-	if(tree->type == XML_ELEMENT_NODE) {
-	    prop = tree->properties;
-	    while (prop != NULL) {
-                if (prop->atype == XML_ATTRIBUTE_ID) {
-                    xmlRemoveID(tree->doc, prop);
-                }
+    if (tree->type == XML_ELEMENT_NODE) {
+        xmlAttrPtr prop = tree->properties;
 
-                if (prop->doc != doc) {
-                    xmlDictPtr oldPropDict = prop->doc ? prop->doc->dict : NULL;
-                    /* TODO: malloc check */
-                    prop->name = _copyStringForNewDictIfNeeded(oldPropDict, newDict, prop->name);
-                    prop->doc = doc;
-                }
-		xmlSetListDoc(prop->children, doc);
+        while (prop != NULL) {
+            if (prop->children != NULL) {
+                if (xmlSetListDoc(prop->children, doc) < 0)
+                    ret = -1;
+            }
 
-                /*
-                 * TODO: ID attributes should be also added to the new
-                 * document, but this breaks things like xmlReplaceNode.
-                 * The underlying problem is that xmlRemoveID is only called
-                 * if a node is destroyed, not if it's unlinked.
-                 */
-#if 0
-                if (xmlIsID(doc, tree, prop)) {
-                    xmlChar *idVal = xmlNodeListGetString(doc, prop->children,
-                                                          1);
-                    xmlAddID(NULL, doc, idVal, prop);
-                }
-#endif
+            if (xmlNodeSetDoc((xmlNodePtr) prop, doc) < 0)
+                ret = -1;
 
-		prop = prop->next;
-	    }
-	}
-        if (tree->type == XML_ENTITY_REF_NODE) {
-            /*
-             * Clear 'children' which points to the entity declaration
-             * from the original document.
-             */
-            tree->children = NULL;
-        } else if (tree->children != NULL) {
-	    xmlSetListDoc(tree->children, doc);
+            prop = prop->next;
         }
-
-        /* TODO: malloc check */
-        tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name);
-        tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content);
-        /* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */
-	tree->doc = doc;
     }
+
+    if ((tree->children != NULL) &&
+        (tree->type != XML_ENTITY_REF_NODE)) {
+        if (xmlSetListDoc(tree->children, doc) < 0)
+            ret = -1;
+    }
+
+    if (xmlNodeSetDoc(tree, doc) < 0)
+        ret = -1;
+
+    return(ret);
 }
 
 /**
  * xmlSetListDoc:
- * @list:  the first element
- * @doc:  the document
+ * @list:  a node list
+ * @doc:  new document
  *
- * update all nodes in the list to point to the right document
+ * Associate all subtrees in @list with a new document.
+ *
+ * Internal function, see xmlSetTreeDoc.
+ *
+ * Returns 0 on success. If a memory allocation fails, returns -1.
+ * All subtrees will be updated on failure but some strings
+ * may be lost.
  */
-void
+int
 xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
     xmlNodePtr cur;
+    int ret = 0;
 
     if ((list == NULL) || (list->type == XML_NAMESPACE_DECL))
-	return;
+	return(0);
+
     cur = list;
     while (cur != NULL) {
-	if (cur->doc != doc)
-	    xmlSetTreeDoc(cur, doc);
+	if (cur->doc != doc) {
+	    if (xmlSetTreeDoc(cur, doc) < 0)
+                ret = -1;
+        }
 	cur = cur->next;
     }
+
+    return(ret);
 }
 
 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
 /**
  * xmlNewChild:
  * @parent:  the parent node
- * @ns:  a namespace if any
+ * @ns:  a namespace (optional)
  * @name:  the name of the child
- * @content:  the XML content of the child if any.
+ * @content:  text content with XML references (optional)
  *
- * Creation of a new child element, added at the end of @parent children list.
- * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly
- * created element inherits the namespace of @parent. If @content is non NULL,
- * a child list containing the TEXTs and ENTITY_REFs node will be created.
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
- *       references. XML special chars must be escaped first by using
- *       xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used.
+ * Create a new child element and append it to a parent element.
  *
- * Returns a pointer to the new node object.
+ * If @ns is NULL, the newly created element inherits the namespace
+ * of the parent.
+ *
+ * If provided, @content is expected to be a valid XML attribute
+ * value possibly containing character and entity references. Text
+ * and entity reference node will be added to the child element,
+ * see xmlNewDocNode.
+ *
+ * Returns a pointer to the new node object or NULL if arguments
+ * are invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
             const xmlChar *name, const xmlChar *content) {
     xmlNodePtr cur, prev;
 
-    if (parent == NULL) {
+    if ((parent == NULL) || (name == NULL))
 	return(NULL);
+
+    switch (parent->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+            break;
+
+        case XML_ELEMENT_NODE:
+            if (ns == NULL)
+                ns = parent->ns;
+            break;
+
+        default:
+            return(NULL);
     }
 
-    if (name == NULL) {
-	return(NULL);
-    }
-
-    /*
-     * Allocate a new node
-     */
-    if (parent->type == XML_ELEMENT_NODE) {
-	if (ns == NULL)
-	    cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
-	else
-	    cur = xmlNewDocNode(parent->doc, ns, name, content);
-    } else if ((parent->type == XML_DOCUMENT_NODE) ||
-	       (parent->type == XML_HTML_DOCUMENT_NODE)) {
-	if (ns == NULL)
-	    cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content);
-	else
-	    cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content);
-    } else if (parent->type == XML_DOCUMENT_FRAG_NODE) {
-	    cur = xmlNewDocNode( parent->doc, ns, name, content);
-    } else {
-	return(NULL);
-    }
-    if (cur == NULL) return(NULL);
+    cur = xmlNewDocNode(parent->doc, ns, name, content);
+    if (cur == NULL)
+        return(NULL);
 
     /*
      * add the new element at the end of the children list.
      */
-    cur->type = XML_ELEMENT_NODE;
     cur->parent = parent;
-    cur->doc = parent->doc;
     if (parent->children == NULL) {
         parent->children = cur;
 	parent->last = cur;
@@ -2958,263 +2890,252 @@
 }
 #endif /* LIBXML_TREE_ENABLED */
 
-/**
- * xmlAddPropSibling:
- * @prev:  the attribute to which @prop is added after
- * @cur:   the base attribute passed to calling function
- * @prop:  the new attribute
- *
- * Add a new attribute after @prev using @cur as base attribute.
- * When inserting before @cur, @prev is passed as @cur->prev.
- * When inserting after @cur, @prev is passed as @cur.
- * If an existing attribute is found it is destroyed prior to adding @prop.
- *
- * See the note regarding namespaces in xmlAddChild.
- *
- * Returns the attribute being inserted or NULL in case of error.
- */
+static void
+xmlTextSetContent(xmlNodePtr text, xmlChar *content) {
+    if ((text->content != NULL) &&
+        (text->content != (xmlChar *) &text->properties)) {
+        xmlDocPtr doc = text->doc;
+
+        if ((doc == NULL) ||
+            (doc->dict == NULL) ||
+            (!xmlDictOwns(doc->dict, text->content)))
+            xmlFree(text->content);
+    }
+
+    text->content = content;
+    text->properties = NULL;
+}
+
+static int
+xmlTextAddContent(xmlNodePtr text, const xmlChar *content, int len) {
+    xmlChar *merged;
+
+    if (content == NULL)
+        return(0);
+
+    merged = xmlStrncatNew(text->content, content, len);
+    if (merged == NULL)
+        return(-1);
+
+    xmlTextSetContent(text, merged);
+    return(0);
+}
+
 static xmlNodePtr
-xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) {
-	xmlAttrPtr attr;
+xmlInsertProp(xmlDocPtr doc, xmlNodePtr cur, xmlNodePtr parent,
+              xmlNodePtr prev, xmlNodePtr next) {
+    xmlAttrPtr attr;
 
-	if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) ||
-	    (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) ||
-	    ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)))
-		return(NULL);
+    if (((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)) ||
+        ((next != NULL) && (next->type != XML_ATTRIBUTE_NODE)))
+        return(NULL);
 
-	/* check if an attribute with the same name exists */
-	if (prop->ns == NULL)
-		attr = xmlHasNsProp(cur->parent, prop->name, NULL);
-	else
-		attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href);
+    /* check if an attribute with the same name exists */
+    attr = xmlGetPropNodeInternal(parent, cur->name,
+                                  cur->ns ? cur->ns->href : NULL, 0);
 
-	if (prop->doc != cur->doc) {
-		xmlSetTreeDoc(prop, cur->doc);
+    xmlUnlinkNode(cur);
+
+    if (cur->doc != doc) {
+        if (xmlSetTreeDoc(cur, doc) < 0)
+            return(NULL);
+    }
+
+    cur->parent = parent;
+    cur->prev = prev;
+    cur->next = next;
+
+    if (prev == NULL) {
+        if (parent != NULL)
+            parent->properties = (xmlAttrPtr) cur;
+    } else {
+        prev->next = cur;
+    }
+    if (next != NULL) {
+        next->prev = cur;
+    }
+
+    if ((attr != NULL) && (attr != (xmlAttrPtr) cur)) {
+        /* different instance, destroy it (attributes must be unique) */
+        xmlRemoveProp((xmlAttrPtr) attr);
+    }
+
+    return cur;
+}
+
+static xmlNodePtr
+xmlInsertNode(xmlDocPtr doc, xmlNodePtr cur, xmlNodePtr parent,
+              xmlNodePtr prev, xmlNodePtr next) {
+    if (cur->type == XML_ATTRIBUTE_NODE)
+	return xmlInsertProp(doc, cur, parent, prev, next);
+
+    xmlUnlinkNode(cur);
+
+    /*
+     * Coalesce text nodes
+     */
+    if (cur->type == XML_TEXT_NODE) {
+	if ((prev != NULL) && (prev->type == XML_TEXT_NODE) &&
+            (prev->name == cur->name)) {
+            if (xmlTextAddContent(prev, cur->content, -1) < 0)
+                return(NULL);
+	    xmlFreeNode(cur);
+	    return(prev);
 	}
-	prop->parent = cur->parent;
-	prop->prev = prev;
-	if (prev != NULL) {
-		prop->next = prev->next;
-		prev->next = prop;
-		if (prop->next)
-			prop->next->prev = prop;
-	} else {
-		prop->next = cur;
-		cur->prev = prop;
+
+	if ((next != NULL) && (next->type == XML_TEXT_NODE) &&
+            (next->name == cur->name)) {
+            if (cur->content != NULL) {
+	        xmlChar *merged;
+
+                merged = xmlStrncatNew(cur->content, next->content, -1);
+                if (merged == NULL)
+                    return(NULL);
+                xmlTextSetContent(next, merged);
+            }
+
+	    xmlFreeNode(cur);
+	    return(next);
 	}
-	if (prop->prev == NULL && prop->parent != NULL)
-		prop->parent->properties = (xmlAttrPtr) prop;
-	if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) {
-		/* different instance, destroy it (attributes must be unique) */
-		xmlRemoveProp((xmlAttrPtr) attr);
-	}
-	return prop;
+    }
+
+    if (cur->doc != doc) {
+	if (xmlSetTreeDoc(cur, doc) < 0)
+            return(NULL);
+    }
+
+    cur->parent = parent;
+    cur->prev = prev;
+    cur->next = next;
+
+    if (prev == NULL) {
+        if (parent != NULL)
+            parent->children = cur;
+    } else {
+        prev->next = cur;
+    }
+    if (next == NULL) {
+        if (parent != NULL)
+            parent->last = cur;
+    } else {
+        next->prev = cur;
+    }
+
+    return(cur);
 }
 
 /**
  * xmlAddNextSibling:
- * @cur:  the child node
- * @elem:  the new node
+ * @prev:  the target node
+ * @cur:  the new node
  *
- * Add a new node @elem as the next sibling of @cur
- * If the new node was already inserted in a document it is
- * first unlinked from its existing context.
- * As a result of text merging @elem may be freed.
- * If the new node is ATTRIBUTE, it is added into properties instead of children.
- * If there is an attribute with equal name, it is first destroyed.
+ * Unlinks @cur and inserts it as next sibling after @prev.
  *
- * See the note regarding namespaces in xmlAddChild.
+ * If @cur is a text node, it may be merged with an adjacent text
+ * node and freed. In this case the text node containing the merged
+ * content is returned.
  *
- * Returns the new node or NULL in case of error.
+ * If @cur is an attribute node, it is inserted after attribute
+ * @prev. If the attribute list contains an attribute with a name
+ * matching @cur, the old attribute is destroyed.
+ *
+ * See the notes in xmlAddChild.
+ *
+ * Returns @cur or a sibling if @cur was merged. Returns NULL
+ * if arguments are invalid or a memory allocation failed.
  */
 xmlNodePtr
-xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
-    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
+xmlAddNextSibling(xmlNodePtr prev, xmlNodePtr cur) {
+    if ((prev == NULL) || (prev->type == XML_NAMESPACE_DECL) ||
+        (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) ||
+        (cur == prev))
 	return(NULL);
-    }
-    if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
-	return(NULL);
-    }
 
-    if (cur == elem) {
-	return(NULL);
-    }
+    if (cur == prev->next)
+        return(cur);
 
-    xmlUnlinkNode(elem);
-
-    if (elem->type == XML_TEXT_NODE) {
-	if (cur->type == XML_TEXT_NODE) {
-	    xmlNodeAddContent(cur, elem->content);
-	    xmlFreeNode(elem);
-	    return(cur);
-	}
-	if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) &&
-            (cur->name == cur->next->name)) {
-	    xmlChar *tmp;
-
-            /* TODO: malloc check */
-	    tmp = xmlStrdup(elem->content);
-	    tmp = xmlStrcat(tmp, cur->next->content);
-	    xmlNodeSetContent(cur->next, tmp);
-	    xmlFree(tmp);
-	    xmlFreeNode(elem);
-	    return(cur->next);
-	}
-    } else if (elem->type == XML_ATTRIBUTE_NODE) {
-		return xmlAddPropSibling(cur, cur, elem);
-    }
-
-    if (elem->doc != cur->doc) {
-	xmlSetTreeDoc(elem, cur->doc);
-    }
-    elem->parent = cur->parent;
-    elem->prev = cur;
-    elem->next = cur->next;
-    cur->next = elem;
-    if (elem->next != NULL)
-	elem->next->prev = elem;
-    if ((elem->parent != NULL) && (elem->parent->last == cur))
-	elem->parent->last = elem;
-    return(elem);
+    return(xmlInsertNode(prev->doc, cur, prev->parent, prev, prev->next));
 }
 
 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \
     defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED)
 /**
  * xmlAddPrevSibling:
- * @cur:  the child node
- * @elem:  the new node
+ * @next:  the target node
+ * @cur:  the new node
  *
- * Add a new node @elem as the previous sibling of @cur
- * merging adjacent TEXT nodes (@elem may be freed)
- * If the new node was already inserted in a document it is
- * first unlinked from its existing context.
- * If the new node is ATTRIBUTE, it is added into properties instead of children.
- * If there is an attribute with equal name, it is first destroyed.
+ * Unlinks @cur and inserts it as previous sibling before @next.
  *
- * See the note regarding namespaces in xmlAddChild.
+ * If @cur is a text node, it may be merged with an adjacent text
+ * node and freed. In this case the text node containing the merged
+ * content is returned.
  *
- * Returns the new node or NULL in case of error.
+ * If @cur is an attribute node, it is inserted before attribute
+ * @next. If the attribute list contains an attribute with a name
+ * matching @cur, the old attribute is destroyed.
+ *
+ * See the notes in xmlAddChild.
+ *
+ * Returns @cur or a sibling if @cur was merged. Returns NULL
+ * if arguments are invalid or a memory allocation failed.
  */
 xmlNodePtr
-xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
-    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
+xmlAddPrevSibling(xmlNodePtr next, xmlNodePtr cur) {
+    if ((next == NULL) || (next->type == XML_NAMESPACE_DECL) ||
+        (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) ||
+        (cur == next))
 	return(NULL);
-    }
-    if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
-	return(NULL);
-    }
 
-    if (cur == elem) {
-	return(NULL);
-    }
+    if (cur == next->prev)
+        return(cur);
 
-    xmlUnlinkNode(elem);
-
-    if (elem->type == XML_TEXT_NODE) {
-	if (cur->type == XML_TEXT_NODE) {
-	    xmlChar *tmp;
-
-            /* TODO: malloc check */
-	    tmp = xmlStrdup(elem->content);
-	    tmp = xmlStrcat(tmp, cur->content);
-	    xmlNodeSetContent(cur, tmp);
-	    xmlFree(tmp);
-	    xmlFreeNode(elem);
-	    return(cur);
-	}
-	if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) &&
-            (cur->name == cur->prev->name)) {
-	    xmlNodeAddContent(cur->prev, elem->content);
-	    xmlFreeNode(elem);
-	    return(cur->prev);
-	}
-    } else if (elem->type == XML_ATTRIBUTE_NODE) {
-		return xmlAddPropSibling(cur->prev, cur, elem);
-    }
-
-    if (elem->doc != cur->doc) {
-	xmlSetTreeDoc(elem, cur->doc);
-    }
-    elem->parent = cur->parent;
-    elem->next = cur;
-    elem->prev = cur->prev;
-    cur->prev = elem;
-    if (elem->prev != NULL)
-	elem->prev->next = elem;
-    if ((elem->parent != NULL) && (elem->parent->children == cur)) {
-		elem->parent->children = elem;
-    }
-    return(elem);
+    return(xmlInsertNode(next->doc, cur, next->parent, next->prev, next));
 }
 #endif /* LIBXML_TREE_ENABLED */
 
 /**
  * xmlAddSibling:
- * @cur:  the child node
- * @elem:  the new node
+ * @node:  the target node
+ * @cur:  the new node
  *
- * Add a new element @elem to the list of siblings of @cur
- * merging adjacent TEXT nodes (@elem may be freed)
- * If the new element was already inserted in a document it is
- * first unlinked from its existing context.
+ * Unlinks @cur and inserts it as last sibling of @node.
  *
- * See the note regarding namespaces in xmlAddChild.
+ * If @cur is a text node, it may be merged with an adjacent text
+ * node and freed. In this case the text node containing the merged
+ * content is returned.
  *
- * Returns the new element or NULL in case of error.
+ * If @cur is an attribute node, it is appended to the attribute
+ * list containing @node. If the attribute list contains an attribute
+ * with a name matching @cur, the old attribute is destroyed.
+ *
+ * See the notes in xmlAddChild.
+ *
+ * Returns @cur or a sibling if @cur was merged. Returns NULL
+ * if arguments are invalid or a memory allocation failed.
  */
 xmlNodePtr
-xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
-    xmlNodePtr parent;
-
-    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
+xmlAddSibling(xmlNodePtr node, xmlNodePtr cur) {
+    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
+        (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) ||
+        (cur == node))
 	return(NULL);
-    }
-
-    if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) {
-	return(NULL);
-    }
-
-    if (cur == elem) {
-	return(NULL);
-    }
 
     /*
      * Constant time is we can rely on the ->parent->last to find
      * the last sibling.
      */
-    if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) &&
-	(cur->parent->children != NULL) &&
-	(cur->parent->last != NULL) &&
-	(cur->parent->last->next == NULL)) {
-	cur = cur->parent->last;
+    if ((node->type != XML_ATTRIBUTE_NODE) && (node->parent != NULL)) {
+        if (node->parent->last != NULL)
+	    node = node->parent->last;
     } else {
-	while (cur->next != NULL) cur = cur->next;
+	while (node->next != NULL)
+            node = node->next;
     }
 
-    xmlUnlinkNode(elem);
+    if (cur == node)
+        return(cur);
 
-    if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) &&
-        (cur->name == elem->name)) {
-	xmlNodeAddContent(cur, elem->content);
-	xmlFreeNode(elem);
-	return(cur);
-    } else if (elem->type == XML_ATTRIBUTE_NODE) {
-		return xmlAddPropSibling(cur, cur, elem);
-    }
-
-    if (elem->doc != cur->doc) {
-	xmlSetTreeDoc(elem, cur->doc);
-    }
-    parent = cur->parent;
-    elem->prev = cur;
-    elem->next = NULL;
-    elem->parent = parent;
-    cur->next = elem;
-    if (parent != NULL)
-	parent->last = elem;
-
-    return(elem);
+    return(xmlInsertNode(node->doc, cur, node->parent, node, NULL));
 }
 
 /**
@@ -3222,16 +3143,17 @@
  * @parent:  the parent node
  * @cur:  the first node in the list
  *
- * Add a list of node at the end of the child list of the parent
- * merging adjacent TEXT nodes (@cur may be freed)
+ * Append a node list to another node.
  *
- * See the note regarding namespaces in xmlAddChild.
+ * See xmlAddChild.
  *
  * Returns the last child or NULL in case of error.
  */
 xmlNodePtr
 xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
+    xmlNodePtr iter;
     xmlNodePtr prev;
+    int oom;
 
     if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) {
 	return(NULL);
@@ -3241,9 +3163,15 @@
 	return(NULL);
     }
 
-    if ((cur->doc != NULL) && (parent->doc != NULL) &&
-        (cur->doc != parent->doc)) {
+    oom = 0;
+    for (iter = cur; iter != NULL; iter = iter->next) {
+	if (iter->doc != parent->doc) {
+	    if (xmlSetTreeDoc(iter, parent->doc) < 0)
+                oom = 1;
+	}
     }
+    if (oom)
+        return(NULL);
 
     /*
      * add the first element at the end of the children list.
@@ -3252,40 +3180,36 @@
     if (parent->children == NULL) {
         parent->children = cur;
     } else {
+        prev = parent->last;
+
 	/*
 	 * If cur and parent->last both are TEXT nodes, then merge them.
 	 */
 	if ((cur->type == XML_TEXT_NODE) &&
-	    (parent->last->type == XML_TEXT_NODE) &&
-	    (cur->name == parent->last->name)) {
-	    xmlNodeAddContent(parent->last, cur->content);
+	    (prev->type == XML_TEXT_NODE) &&
+	    (cur->name == prev->name)) {
+            xmlNodePtr next;
+
+            if (xmlTextAddContent(prev, cur->content, -1) < 0)
+                return(NULL);
+            next = cur->next;
+	    xmlFreeNode(cur);
 	    /*
 	     * if it's the only child, nothing more to be done.
 	     */
-	    if (cur->next == NULL) {
-		xmlFreeNode(cur);
-		return(parent->last);
-	    }
-	    prev = cur;
-	    cur = cur->next;
-	    xmlFreeNode(prev);
+	    if (next == NULL)
+		return(prev);
+	    cur = next;
 	}
-        prev = parent->last;
+
 	prev->next = cur;
 	cur->prev = prev;
     }
     while (cur->next != NULL) {
 	cur->parent = parent;
-	if (cur->doc != parent->doc) {
-	    xmlSetTreeDoc(cur, parent->doc);
-	}
         cur = cur->next;
     }
     cur->parent = parent;
-    /* the parent may not be linked to a doc ! */
-    if (cur->doc != parent->doc) {
-        xmlSetTreeDoc(cur, parent->doc);
-    }
     parent->last = cur;
 
     return(cur);
@@ -3296,18 +3220,41 @@
  * @parent:  the parent node
  * @cur:  the child node
  *
- * Add a new node to @parent, at the end of the child (or property) list
- * merging adjacent TEXT nodes (in which case @cur is freed)
- * If the new node is ATTRIBUTE, it is added into properties instead of children.
- * If there is an attribute with equal name, it is first destroyed.
+ * Append @cur to the children of @parent.
  *
- * All tree manipulation functions can safely move nodes within a document.
- * But when moving nodes from one document to another, references to
- * namespaces in element or attribute nodes are NOT fixed. In this case,
- * you MUST call xmlReconciliateNs after the move operation to avoid
- * memory errors.
+ * Unlike functions like xmlAddSibling, this function doesn't unlink
+ * @cur before appending. It is an error if @cur has siblings or a
+ * parent. This behavior might change in future releases.
  *
- * Returns the child or NULL in case of error.
+ * If @cur is a text node, it may be merged with an adjacent text
+ * node and freed. In this case the text node containing the merged
+ * content is returned.
+ *
+ * If @cur is an attribute node, it is appended to the attributes of
+ * @parent. If the attribute list contains an attribute with a name
+ * matching @elem, the old attribute is destroyed.
+ *
+ * General notes:
+ *
+ * Move operations like xmlAddChild can cause element or attribute
+ * nodes to reference namespaces that aren't declared in one of
+ * their ancestors. This can lead to use-after-free errors if the
+ * elements containing the declarations are freed later, especially
+ * when moving nodes from one document to another. You should
+ * consider calling xmlReconciliateNs after a move operation to
+ * normalize namespaces. Another option is to call
+ * xmlDOMWrapAdoptNode with the target parent before moving a node.
+ *
+ * For the most part, move operations don't check whether the
+ * resulting tree structure is valid. Users must make sure that
+ * parent nodes only receive children of valid types. Inserted
+ * child nodes must never be an ancestor of the parent node to
+ * avoid cycles in the tree structure. In general, only
+ * document, document fragments, elements and attributes
+ * should be used as parent nodes.
+ *
+ * Returns @elem or a sibling if @elem was merged. Returns NULL
+ * if arguments are invalid or a memory allocation failed.
  */
 xmlNodePtr
 xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
@@ -3317,86 +3264,75 @@
 	return(NULL);
     }
 
-    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) {
+    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL) ||
+        (cur->next != NULL) || (cur->prev != NULL) ||
+        ((cur->parent != NULL && cur->parent != parent))) {
 	return(NULL);
     }
 
     if (parent == cur) {
 	return(NULL);
     }
+
+    /*
+     * Handle text parent
+     */
+    if (parent->type == XML_TEXT_NODE) {
+        if (xmlTextAddContent(parent, cur->content, -1) < 0)
+            return(NULL);
+        xmlFreeNode(cur);
+        return(parent);
+    }
+
     /*
      * If cur is a TEXT node, merge its content with adjacent TEXT nodes
      * cur is then freed.
      */
     if (cur->type == XML_TEXT_NODE) {
-	if ((parent->type == XML_TEXT_NODE) &&
-	    (parent->content != NULL) &&
-	    (parent->name == cur->name)) {
-	    if (xmlNodeAddContent(parent, cur->content) != 0) {
-                xmlFreeNode(cur);
+        xmlNodePtr last = parent->last;
+
+	if ((last != NULL) && (last->type == XML_TEXT_NODE) &&
+	    (last->name == cur->name) &&
+            (last != cur)) {
+            if (xmlTextAddContent(last, cur->content, -1) < 0)
                 return(NULL);
-            }
 	    xmlFreeNode(cur);
-	    return(parent);
+	    return(last);
 	}
-	if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
-	    (parent->last->name == cur->name) &&
-	    (parent->last != cur)) {
-	    if (xmlNodeAddContent(parent->last, cur->content) != 0) {
-                xmlFreeNode(cur);
-                return(NULL);
-            }
-	    xmlFreeNode(cur);
-	    return(parent->last);
-	}
+    } else if (cur->type == XML_ATTRIBUTE_NODE) {
+        if (parent->type != XML_ELEMENT_NODE)
+            return(NULL);
     }
 
     /*
      * add the new element at the end of the children list.
      */
     prev = cur->parent;
-    cur->parent = parent;
     if (cur->doc != parent->doc) {
-	xmlSetTreeDoc(cur, parent->doc);
+	if (xmlSetTreeDoc(cur, parent->doc) < 0)
+            return(NULL);
     }
+    cur->parent = parent;
     /* this check prevents a loop on tree-traversions if a developer
      * tries to add a node to its parent multiple times
      */
     if (prev == parent)
 	return(cur);
 
-    /*
-     * Coalescing
-     */
-    if ((parent->type == XML_TEXT_NODE) &&
-	(parent->content != NULL) &&
-	(parent != cur)) {
-	if (xmlNodeAddContent(parent, cur->content) != 0) {
-            xmlFreeNode(cur);
-            return(NULL);
-        }
-	xmlFreeNode(cur);
-	return(parent);
-    }
     if (cur->type == XML_ATTRIBUTE_NODE) {
-		if (parent->type != XML_ELEMENT_NODE)
-			return(NULL);
 	if (parent->properties != NULL) {
 	    /* check if an attribute with the same name exists */
 	    xmlAttrPtr lastattr;
 
-	    if (cur->ns == NULL)
-		lastattr = xmlHasNsProp(parent, cur->name, NULL);
-	    else
-		lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href);
-	    if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) {
+            lastattr = xmlGetPropNodeInternal(parent, cur->name,
+                    cur->ns ? cur->ns->href : NULL, 0);
+	    if (lastattr != NULL) {
+                if (lastattr == (xmlAttrPtr) cur)
+                    return(cur);
 		/* different instance, destroy it (attributes must be unique) */
-			xmlUnlinkNode((xmlNodePtr) lastattr);
+                xmlUnlinkNode((xmlNodePtr) lastattr);
 		xmlFreeProp(lastattr);
 	    }
-		if (lastattr == (xmlAttrPtr) cur)
-			return(cur);
-
 	}
 	if (parent->properties == NULL) {
 	    parent->properties = (xmlAttrPtr) cur;
@@ -3427,8 +3363,9 @@
  * xmlGetLastChild:
  * @parent:  the parent node
  *
- * Search the last child of a node.
- * Returns the last child or NULL if none.
+ * Find the last child of a node.
+ *
+ * Returns the last child or NULL if parent has no children.
  */
 xmlNodePtr
 xmlGetLastChild(const xmlNode *parent) {
@@ -3447,13 +3384,12 @@
  * xmlChildElementCount:
  * @parent: the parent node
  *
- * Finds the current number of child nodes of that element which are
- * element nodes.
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Count the number of child nodes which are elements.
  *
- * Returns the count of element child or 0 if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the number of element children or 0 if arguments are
+ * invalid.
  */
 unsigned long
 xmlChildElementCount(xmlNodePtr parent) {
@@ -3464,10 +3400,10 @@
         return(0);
     switch (parent->type) {
         case XML_ELEMENT_NODE:
-        case XML_ENTITY_NODE:
         case XML_DOCUMENT_NODE:
         case XML_DOCUMENT_FRAG_NODE:
         case XML_HTML_DOCUMENT_NODE:
+        case XML_ENTITY_DECL:
             cur = parent->children;
             break;
         default:
@@ -3485,12 +3421,11 @@
  * xmlFirstElementChild:
  * @parent: the parent node
  *
- * Finds the first child node of that element which is a Element node
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Find the first child node which is an element.
  *
- * Returns the first element child or NULL if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the first element or NULL if parent has no children.
  */
 xmlNodePtr
 xmlFirstElementChild(xmlNodePtr parent) {
@@ -3500,10 +3435,10 @@
         return(NULL);
     switch (parent->type) {
         case XML_ELEMENT_NODE:
-        case XML_ENTITY_NODE:
         case XML_DOCUMENT_NODE:
         case XML_DOCUMENT_FRAG_NODE:
         case XML_HTML_DOCUMENT_NODE:
+        case XML_ENTITY_DECL:
             cur = parent->children;
             break;
         default:
@@ -3521,12 +3456,11 @@
  * xmlLastElementChild:
  * @parent: the parent node
  *
- * Finds the last child node of that element which is a Element node
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Find the last child node which is an element.
  *
- * Returns the last element child or NULL if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the last element or NULL if parent has no children.
  */
 xmlNodePtr
 xmlLastElementChild(xmlNodePtr parent) {
@@ -3536,10 +3470,10 @@
         return(NULL);
     switch (parent->type) {
         case XML_ELEMENT_NODE:
-        case XML_ENTITY_NODE:
         case XML_DOCUMENT_NODE:
         case XML_DOCUMENT_FRAG_NODE:
         case XML_HTML_DOCUMENT_NODE:
+        case XML_ENTITY_DECL:
             cur = parent->last;
             break;
         default:
@@ -3557,13 +3491,11 @@
  * xmlPreviousElementSibling:
  * @node: the current node
  *
- * Finds the first closest previous sibling of the node which is an
- * element node.
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Find the closest preceding sibling which is a element.
  *
- * Returns the previous element sibling or NULL if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the sibling or NULL if no sibling was found.
  */
 xmlNodePtr
 xmlPreviousElementSibling(xmlNodePtr node) {
@@ -3574,7 +3506,6 @@
         case XML_TEXT_NODE:
         case XML_CDATA_SECTION_NODE:
         case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
         case XML_PI_NODE:
         case XML_COMMENT_NODE:
         case XML_XINCLUDE_START:
@@ -3596,13 +3527,11 @@
  * xmlNextElementSibling:
  * @node: the current node
  *
- * Finds the first closest next sibling of the node which is an
- * element node.
- * Note the handling of entities references is different than in
- * the W3C DOM element traversal spec since we don't have back reference
- * from entities content to entities references.
+ * Find the closest following sibling which is a element.
  *
- * Returns the next element sibling or NULL if not available
+ * Note that entity references are not expanded.
+ *
+ * Returns the sibling or NULL if no sibling was found.
  */
 xmlNodePtr
 xmlNextElementSibling(xmlNodePtr node) {
@@ -3613,7 +3542,6 @@
         case XML_TEXT_NODE:
         case XML_CDATA_SECTION_NODE:
         case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
         case XML_PI_NODE:
         case XML_COMMENT_NODE:
         case XML_DTD_NODE:
@@ -3638,8 +3566,7 @@
  * xmlFreeNodeList:
  * @cur:  the first node in the list
  *
- * Free a node and all its siblings, this is a recursive behaviour, all
- * the children are freed too.
+ * Free a node list including all children.
  */
 void
 xmlFreeNodeList(xmlNodePtr cur) {
@@ -3669,8 +3596,14 @@
 	if ((cur->type == XML_DOCUMENT_NODE) ||
             (cur->type == XML_HTML_DOCUMENT_NODE)) {
             xmlFreeDoc((xmlDocPtr) cur);
-        } else if (cur->type != XML_DTD_NODE) {
-
+        } else if (cur->type == XML_DTD_NODE) {
+            /*
+             * TODO: We should consider freeing the DTD if it isn't
+             * referenced from doc->intSubset or doc->extSubset.
+             */
+            cur->prev = NULL;
+            cur->next = NULL;
+        } else {
 	    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
 		xmlDeregisterNodeDefaultValue(cur);
 
@@ -3721,8 +3654,10 @@
  * xmlFreeNode:
  * @cur:  the node
  *
- * Free a node, this is a recursive behaviour, all the children are freed too.
- * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
+ * Free a node including all the children.
+ *
+ * This doesn't unlink the node from the tree. Call xmlUnlinkNode first
+ * unless @cur is a root node.
  */
 void
 xmlFreeNode(xmlNodePtr cur) {
@@ -3788,11 +3723,10 @@
  * xmlUnlinkNode:
  * @cur:  the node
  *
- * Unlink a node from it's current context, the node is not freed
- * If one need to free the node, use xmlFreeNode() routine after the
- * unlink to discard it.
- * Note that namespace nodes can't be unlinked as they do not have
- * pointer to their parent.
+ * Unlink a node from its tree.
+ *
+ * The node is not freed. Unless it is reinserted, it must be managed
+ * manually and freed eventually by calling xmlFreeNode.
  */
 void
 xmlUnlinkNode(xmlNodePtr cur) {
@@ -3858,15 +3792,20 @@
 /**
  * xmlReplaceNode:
  * @old:  the old node
- * @cur:  the node
+ * @cur:  the node (optional)
  *
- * Unlink the old node from its current context, prune the new one
- * at the same place. If @cur was already inserted in a document it is
- * first unlinked from its existing context.
+ * Unlink the old node. If @cur is provided, it is unlinked and
+ * inserted in place of @old.
  *
- * See the note regarding namespaces in xmlAddChild.
+ * It is an error if @old has no parent.
  *
- * Returns the @old node
+ * Unlike xmlAddChild, this function doesn't merge text nodes or
+ * delete duplicate attributes.
+ *
+ * See the notes in xmlAddChild.
+ *
+ * Returns @old or NULL if arguments are invalid or a memory
+ * allocation failed.
  */
 xmlNodePtr
 xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
@@ -3889,7 +3828,8 @@
 	return(old);
     }
     xmlUnlinkNode(cur);
-    xmlSetTreeDoc(cur, old->doc);
+    if (xmlSetTreeDoc(cur, old->doc) < 0)
+        return(NULL);
     cur->parent = old->parent;
     cur->next = old->next;
     if (cur->next != NULL)
@@ -3924,9 +3864,10 @@
  * xmlCopyNamespace:
  * @cur:  the namespace
  *
- * Do a copy of the namespace.
+ * Copy a namespace.
  *
- * Returns: a new #xmlNsPtr, or NULL in case of error.
+ * Returns the copied namespace or NULL if a memory allocation
+ * failed.
  */
 xmlNsPtr
 xmlCopyNamespace(xmlNsPtr cur) {
@@ -3947,9 +3888,10 @@
  * xmlCopyNamespaceList:
  * @cur:  the first namespace
  *
- * Do a copy of an namespace list.
+ * Copy a namespace list.
  *
- * Returns: a new #xmlNsPtr, or NULL in case of error.
+ * Returns the head of the copied list or NULL if a memory
+ * allocation failed.
  */
 xmlNsPtr
 xmlCopyNamespaceList(xmlNsPtr cur) {
@@ -3995,15 +3937,20 @@
 
     if ((cur->ns != NULL) && (target != NULL)) {
       xmlNsPtr ns;
+      int res;
 
-      ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
+      res = xmlSearchNsSafe(target, cur->ns->prefix, &ns);
+      if (res < 0)
+          goto error;
       if (ns == NULL) {
         /*
          * Humm, we are copying an element whose namespace is defined
          * out of the new tree scope. Search it in the original tree
          * and add it at the top of the new tree
          */
-        ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix);
+        res = xmlSearchNsSafe(cur->parent, cur->ns->prefix, &ns);
+        if (res < 0)
+          goto error;
         if (ns != NULL) {
           xmlNodePtr root = target;
           xmlNodePtr pred = NULL;
@@ -4034,7 +3981,7 @@
            * we are in trouble: we need a new reconciled namespace.
            * This is expensive
            */
-          ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns);
+          ret->ns = xmlNewReconciledNs(target, cur->ns);
           if (ret->ns == NULL)
               goto error;
         }
@@ -4073,10 +4020,10 @@
 	if (res != 0) {
 	    xmlChar *id;
 
-	    id = xmlNodeListGetString(cur->doc, cur->children, 1);
+	    id = xmlNodeGetContent((xmlNodePtr) cur);
 	    if (id == NULL)
                 goto error;
-            res = xmlAddIDSafe(target->doc, id, ret, 0, NULL);
+            res = xmlAddIDSafe(ret, id);
 	    xmlFree(id);
             if (res < 0)
                 goto error;
@@ -4094,9 +4041,14 @@
  * @target:  the element where the attribute will be grafted
  * @cur:  the attribute
  *
- * Do a copy of the attribute.
+ * Create a copy of the attribute. This function sets the parent
+ * pointer of the copy to @target but doesn't set the attribute on
+ * the target element. Users should consider to set the attribute
+ * by calling xmlAddChild afterwards or reset the parent pointer to
+ * NULL.
  *
- * Returns: a new #xmlAttrPtr, or NULL in case of error.
+ * Returns the copied attribute or NULL if a memory allocation
+ * failed.
  */
 xmlAttrPtr
 xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
@@ -4108,9 +4060,12 @@
  * @target:  the element where the attributes will be grafted
  * @cur:  the first attribute
  *
- * Do a copy of an attribute list.
+ * Create a copy of an attribute list. This function sets the
+ * parent pointers of the copied attributes to @target but doesn't
+ * set the attributes on the target element.
  *
- * Returns: a new #xmlAttrPtr, or NULL in case of error.
+ * Returns the head of the copied list or NULL if a memory
+ * allocation failed.
  */
 xmlAttrPtr
 xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
@@ -4168,7 +4123,6 @@
         case XML_ELEMENT_NODE:
         case XML_DOCUMENT_FRAG_NODE:
         case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
         case XML_PI_NODE:
         case XML_COMMENT_NODE:
         case XML_XINCLUDE_START:
@@ -4184,12 +4138,7 @@
 #ifdef LIBXML_TREE_ENABLED
 	    return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended));
 #endif /* LIBXML_TREE_ENABLED */
-        case XML_DOCUMENT_TYPE_NODE:
-        case XML_NOTATION_NODE:
-        case XML_DTD_NODE:
-        case XML_ELEMENT_DECL:
-        case XML_ATTRIBUTE_DECL:
-        case XML_ENTITY_DECL:
+        default:
             return(NULL);
     }
 
@@ -4251,6 +4200,8 @@
          */
         tmp = xmlAddChild(parent, ret);
 	/* node could have coalesced */
+        if (tmp == NULL)
+            goto error;
 	if (tmp != ret)
 	    return(tmp);
     }
@@ -4265,9 +4216,12 @@
     }
 
     if ((node->type == XML_ELEMENT_NODE) && (node->ns != NULL)) {
-        xmlNsPtr ns;
+        xmlNsPtr ns = NULL;
+        int res;
 
-	ns = xmlSearchNs(doc, ret, node->ns->prefix);
+	res = xmlSearchNsSafe(ret, node->ns->prefix, &ns);
+        if (res < 0)
+            goto error;
 	if (ns == NULL) {
 	    /*
 	     * Humm, we are copying an element whose namespace is defined
@@ -4277,14 +4231,16 @@
              * TODO: Searching the original tree seems unnecessary. We
              * already have a namespace URI.
 	     */
-	    ns = xmlSearchNs(node->doc, node, node->ns->prefix);
+	    res = xmlSearchNsSafe(node, node->ns->prefix, &ns);
+            if (res < 0)
+                goto error;
 	    if (ns != NULL) {
 	        xmlNodePtr root = ret;
 
 		while (root->parent != NULL) root = root->parent;
 		ret->ns = xmlNewNs(root, ns->href, ns->prefix);
             } else {
-                ret->ns = xmlNewReconciledNs(doc, ret, node->ns);
+                ret->ns = xmlNewReconciledNs(ret, node->ns);
 	    }
             if (ret->ns == NULL)
                 goto error;
@@ -4369,6 +4325,18 @@
     return(NULL);
 }
 
+/**
+ * xmlStaticCopyNodeList:
+ * @node:  node to copy
+ * @doc:  target document
+ * @parent:  target node (optional)
+ *
+ * Copy a node list. If @parent is provided, sets the parent pointer
+ * of the copied nodes, but doesn't update the children and last
+ * pointer of @parent.
+ *
+ * Returns a the copy or NULL in case of error.
+ */
 xmlNodePtr
 xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
     xmlNodePtr ret = NULL;
@@ -4377,23 +4345,44 @@
     int linkedSubset = 0;
 
     while (node != NULL) {
+        xmlNodePtr next = node->next;
+
 #ifdef LIBXML_TREE_ENABLED
 	if (node->type == XML_DTD_NODE ) {
 	    if (doc == NULL) {
-		node = node->next;
+		node = next;
 		continue;
 	    }
 	    if ((doc->intSubset == NULL) && (newSubset == NULL)) {
 		q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
 		if (q == NULL) goto error;
-		q->doc = doc;
+                /* Can't fail on DTD */
+		xmlSetTreeDoc(q, doc);
 		q->parent = parent;
 		newSubset = (xmlDtdPtr) q;
-		xmlAddChild(parent, q);
 	    } else {
+                /*
+                 * We don't allow multiple internal subsets in a document,
+                 * so we move the DTD instead of creating a copy.
+                 */
                 linkedSubset = 1;
 		q = (xmlNodePtr) doc->intSubset;
-		xmlAddChild(parent, q);
+                /* Unlink */
+                if (q->prev == NULL) {
+                    if (q->parent != NULL)
+                        q->parent->children = q->next;
+                } else {
+                    q->prev->next = q->next;
+                }
+                if (q->next == NULL) {
+                    if (q->parent != NULL)
+                        q->parent->last = q->prev;
+                } else {
+                    q->next->prev = q->prev;
+                }
+                q->parent = parent;
+                q->next = NULL;
+                q->prev = NULL;
 	    }
 	} else
 #endif /* LIBXML_TREE_ENABLED */
@@ -4408,13 +4397,15 @@
 	    q->prev = p;
 	    p = q;
 	}
-	node = node->next;
+	node = next;
     }
     if ((doc != NULL) && (newSubset != NULL))
         doc->intSubset = newSubset;
     return(ret);
 error:
     xmlFreeNodeList(ret);
+    if (newSubset != NULL)
+        xmlFreeDtd(newSubset);
     if (linkedSubset != 0) {
         doc->intSubset->next = NULL;
         doc->intSubset->prev = NULL;
@@ -4429,9 +4420,11 @@
  *			when applicable)
  *		if 2 copy properties and namespaces (when applicable)
  *
- * Do a copy of the node.
+ * Copy a node.
  *
- * Returns: a new #xmlNodePtr, or NULL in case of error.
+ * Use of this function is DISCOURAGED in favor of xmlDocCopyNode.
+ *
+ * Returns the copied node or NULL if a memory allocation failed.
  */
 xmlNodePtr
 xmlCopyNode(xmlNodePtr node, int extended) {
@@ -4449,9 +4442,9 @@
  *			when applicable)
  *		if 2 copy properties and namespaces (when applicable)
  *
- * Do a copy of the node to a given document.
+ * Copy a node into another document.
  *
- * Returns: a new #xmlNodePtr, or NULL in case of error.
+ * Returns the copied node or NULL if a memory allocation failed.
  */
 xmlNodePtr
 xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) {
@@ -4466,9 +4459,10 @@
  * @doc: the target document
  * @node:  the first node in the list.
  *
- * Do a recursive copy of the node list.
+ * Copy a node list and all children into a new document.
  *
- * Returns: a new #xmlNodePtr, or NULL in case of error.
+ * Returns the head of the copied list or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) {
     xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL);
@@ -4479,10 +4473,12 @@
  * xmlCopyNodeList:
  * @node:  the first node in the list.
  *
- * Do a recursive copy of the node list.
- * Use xmlDocCopyNodeList() if possible to ensure string interning.
+ * Copy a node list and all children.
  *
- * Returns: a new #xmlNodePtr, or NULL in case of error.
+ * Use of this function is DISCOURAGED in favor of xmlDocCopyNodeList.
+ *
+ * Returns the head of the copied list or NULL if a memory
+ * allocation failed.
  */
 xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
     xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
@@ -4492,11 +4488,11 @@
 #if defined(LIBXML_TREE_ENABLED)
 /**
  * xmlCopyDtd:
- * @dtd:  the dtd
+ * @dtd:  the DTD
  *
- * Do a copy of the dtd.
+ * Copy a DTD.
  *
- * Returns: a new #xmlDtdPtr, or NULL in case of error.
+ * Returns the copied DTD or NULL if a memory allocation failed.
  */
 xmlDtdPtr
 xmlCopyDtd(xmlDtdPtr dtd) {
@@ -4603,10 +4599,11 @@
  * @doc:  the document
  * @recursive:  if not zero do a recursive copy.
  *
- * Do a copy of the document info. If recursive, the content tree will
+ * Copy a document. If recursive, the content tree will
  * be copied too as well as DTD, namespaces and entities.
  *
- * Returns: a new #xmlDocPtr, or NULL in case of error.
+ * Returns the copied document or NULL if a memory allocation
+ * failed.
  */
 xmlDocPtr
 xmlCopyDoc(xmlDocPtr doc, int recursive) {
@@ -4643,8 +4640,8 @@
         ret->intSubset = xmlCopyDtd(doc->intSubset);
 	if (ret->intSubset == NULL)
             goto error;
+        /* Can't fail on DTD */
 	xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret);
-	ret->intSubset->parent = ret;
     }
 #endif
     if (doc->oldNs != NULL) {
@@ -4998,7 +4995,7 @@
  * Get the root element of the document (doc->children is a list
  * containing possibly comments, PIs, etc ...).
  *
- * Returns the #xmlNodePtr for the root or NULL
+ * Returns the root element or NULL if no element was found.
  */
 xmlNodePtr
 xmlDocGetRootElement(const xmlDoc *doc) {
@@ -5024,24 +5021,30 @@
  * Set the root element of the document (doc->children is a list
  * containing possibly comments, PIs, etc ...).
  *
- * Returns the old root element if any was found, NULL if root was NULL
+ * @root must be an element node. It is unlinked before insertion.
+ *
+ * Returns the unlinked old root element or NULL if the document
+ * didn't have a root element or a memory allocation failed.
  */
 xmlNodePtr
 xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
     xmlNodePtr old = NULL;
 
     if (doc == NULL) return(NULL);
-    if ((root == NULL) || (root->type == XML_NAMESPACE_DECL))
+    if ((root == NULL) || (root->type != XML_ELEMENT_NODE))
 	return(NULL);
-    xmlUnlinkNode(root);
-    xmlSetTreeDoc(root, doc);
-    root->parent = (xmlNodePtr) doc;
     old = doc->children;
     while (old != NULL) {
 	if (old->type == XML_ELEMENT_NODE)
 	    break;
         old = old->next;
     }
+    if (old == root)
+        return(old);
+    xmlUnlinkNode(root);
+    if (xmlSetTreeDoc(root, doc) < 0)
+        return(NULL);
+    root->parent = (xmlNodePtr) doc;
     if (old == NULL) {
 	if (doc->children == NULL) {
 	    doc->children = root;
@@ -5064,40 +5067,27 @@
  *
  * Set the language of a node, i.e. the values of the xml:lang
  * attribute.
+ *
+ * Return 0 on success, 1 if arguments are invalid, -1 if a
+ * memory allocation failed.
  */
-void
+int
 xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
     xmlNsPtr ns;
+    xmlAttrPtr attr;
+    int res;
 
-    if (cur == NULL) return;
-    switch(cur->type) {
-        case XML_TEXT_NODE:
-        case XML_CDATA_SECTION_NODE:
-        case XML_COMMENT_NODE:
-        case XML_DOCUMENT_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-        case XML_DOCUMENT_FRAG_NODE:
-        case XML_NOTATION_NODE:
-        case XML_HTML_DOCUMENT_NODE:
-        case XML_DTD_NODE:
-        case XML_ELEMENT_DECL:
-        case XML_ATTRIBUTE_DECL:
-        case XML_ENTITY_DECL:
-        case XML_PI_NODE:
-        case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
-	case XML_NAMESPACE_DECL:
-	case XML_XINCLUDE_START:
-	case XML_XINCLUDE_END:
-	    return;
-        case XML_ELEMENT_NODE:
-        case XML_ATTRIBUTE_NODE:
-	    break;
-    }
-    ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
-    if (ns == NULL)
-	return;
-    xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
+    if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
+        return(1);
+
+    res = xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns);
+    if (res != 0)
+        return(res);
+    attr = xmlSetNsProp(cur, ns, BAD_CAST "lang", lang);
+    if (attr == NULL)
+        return(-1);
+
+    return(0);
 }
 #endif /* LIBXML_TREE_ENABLED */
 
@@ -5114,15 +5104,22 @@
 xmlChar *
 xmlNodeGetLang(const xmlNode *cur) {
     xmlChar *lang;
+    int res;
 
     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
         return(NULL);
+
     while (cur != NULL) {
-        lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE);
+        res = xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
+                                  &lang);
+        if (res < 0)
+            return(NULL);
 	if (lang != NULL)
 	    return(lang);
+
 	cur = cur->parent;
     }
+
     return(NULL);
 }
 
@@ -5135,47 +5132,34 @@
  *
  * Set (or reset) the space preserving behaviour of a node, i.e. the
  * value of the xml:space attribute.
+ *
+ * Return 0 on success, 1 if arguments are invalid, -1 if a
+ * memory allocation failed.
  */
-void
+int
 xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
     xmlNsPtr ns;
+    xmlAttrPtr attr;
+    const char *string;
+    int res;
 
-    if (cur == NULL) return;
-    switch(cur->type) {
-        case XML_TEXT_NODE:
-        case XML_CDATA_SECTION_NODE:
-        case XML_COMMENT_NODE:
-        case XML_DOCUMENT_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-        case XML_DOCUMENT_FRAG_NODE:
-        case XML_NOTATION_NODE:
-        case XML_HTML_DOCUMENT_NODE:
-        case XML_DTD_NODE:
-        case XML_ELEMENT_DECL:
-        case XML_ATTRIBUTE_DECL:
-        case XML_ENTITY_DECL:
-        case XML_PI_NODE:
-        case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
-	case XML_NAMESPACE_DECL:
-	case XML_XINCLUDE_START:
-	case XML_XINCLUDE_END:
-	    return;
-        case XML_ELEMENT_NODE:
-        case XML_ATTRIBUTE_NODE:
-	    break;
-    }
-    ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
-    if (ns == NULL)
-	return;
-    switch (val) {
-    case 0:
-	xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default");
-	break;
-    case 1:
-	xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve");
-	break;
-    }
+    if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
+        return(1);
+
+    res = xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns);
+    if (res != 0)
+	return(res);
+
+    if (val == 0)
+        string = "default";
+    else
+        string = "preserve";
+
+    attr = xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST string);
+    if (attr == NULL)
+        return(-1);
+
+    return(0);
 }
 #endif /* LIBXML_TREE_ENABLED */
 
@@ -5192,11 +5176,16 @@
 int
 xmlNodeGetSpacePreserve(const xmlNode *cur) {
     xmlChar *space;
+        int res;
 
     if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
         return(-1);
+
     while (cur != NULL) {
-	space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE);
+	res = xmlNodeGetAttrValue(cur, BAD_CAST "space", XML_XML_NAMESPACE,
+                                  &space);
+        if (res < 0)
+            return(-1);
 	if (space != NULL) {
 	    if (xmlStrEqual(space, BAD_CAST "preserve")) {
 		xmlFree(space);
@@ -5208,8 +5197,10 @@
 	    }
 	    xmlFree(space);
 	}
+
 	cur = cur->parent;
     }
+
     return(-1);
 }
 
@@ -5225,52 +5216,39 @@
 xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
     xmlDocPtr doc;
     xmlDictPtr dict;
-    const xmlChar *freeme = NULL;
+    const xmlChar *copy;
+    const xmlChar *oldName;
 
     if (cur == NULL) return;
     if (name == NULL) return;
     switch(cur->type) {
-        case XML_TEXT_NODE:
-        case XML_CDATA_SECTION_NODE:
-        case XML_COMMENT_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-        case XML_DOCUMENT_FRAG_NODE:
-        case XML_NOTATION_NODE:
-        case XML_HTML_DOCUMENT_NODE:
-	case XML_NAMESPACE_DECL:
-	case XML_XINCLUDE_START:
-	case XML_XINCLUDE_END:
-	    return;
         case XML_ELEMENT_NODE:
         case XML_ATTRIBUTE_NODE:
         case XML_PI_NODE:
         case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
-        case XML_DTD_NODE:
-        case XML_DOCUMENT_NODE:
-        case XML_ELEMENT_DECL:
-        case XML_ATTRIBUTE_DECL:
-        case XML_ENTITY_DECL:
 	    break;
+        default:
+            return;
     }
+
     doc = cur->doc;
     if (doc != NULL)
 	dict = doc->dict;
     else
         dict = NULL;
-    /* TODO: malloc check */
-    if (dict != NULL) {
-        if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
-	    freeme = cur->name;
-	cur->name = xmlDictLookup(dict, name, -1);
-    } else {
-	if (cur->name != NULL)
-	    freeme = cur->name;
-	cur->name = xmlStrdup(name);
-    }
 
-    if (freeme)
-        xmlFree((xmlChar *) freeme);
+    if (dict != NULL)
+        copy = xmlDictLookup(dict, name, -1);
+    else
+        copy = xmlStrdup(name);
+    if (copy == NULL)
+        return;
+
+    oldName = cur->name;
+    cur->name = copy;
+    if ((oldName != NULL) &&
+        ((dict == NULL) || (!xmlDictOwns(dict, oldName))))
+        xmlFree((xmlChar *) oldName);
 }
 #endif
 
@@ -5293,23 +5271,6 @@
     if (cur == NULL)
         return(-1);
     switch(cur->type) {
-        case XML_TEXT_NODE:
-        case XML_CDATA_SECTION_NODE:
-        case XML_COMMENT_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-        case XML_DOCUMENT_FRAG_NODE:
-        case XML_NOTATION_NODE:
-        case XML_DTD_NODE:
-        case XML_ELEMENT_DECL:
-        case XML_ATTRIBUTE_DECL:
-        case XML_ENTITY_DECL:
-        case XML_PI_NODE:
-        case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
-	case XML_NAMESPACE_DECL:
-	case XML_XINCLUDE_START:
-	case XML_XINCLUDE_END:
-	    return(-1);
         case XML_ELEMENT_NODE:
         case XML_ATTRIBUTE_NODE:
 	    break;
@@ -5328,9 +5289,11 @@
             }
 	    return(0);
 	}
+        default:
+	    return(-1);
     }
 
-    ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE);
+    xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns);
     if (ns == NULL)
 	return(-1);
     fixed = xmlPathToURI(uri);
@@ -5411,6 +5374,8 @@
 	if (cur->type == XML_ENTITY_DECL) {
 	    xmlEntityPtr ent = (xmlEntityPtr) cur;
 
+            if (ent->URI == NULL)
+                break;
             xmlFree(ret);
 	    ret = xmlStrdup(ent->URI);
             if (ret == NULL)
@@ -5509,6 +5474,59 @@
     return(0);
 }
 
+static void
+xmlBufGetEntityRefContent(xmlBufPtr buf, const xmlNode *ref) {
+    xmlEntityPtr ent;
+
+    if (ref->children != NULL) {
+        ent = (xmlEntityPtr) ref->children;
+    } else {
+        /* lookup entity declaration */
+        ent = xmlGetDocEntity(ref->doc, ref->name);
+        if (ent == NULL)
+            return;
+    }
+
+    if (ent->flags & XML_ENT_EXPANDING)
+        return;
+
+    ent->flags |= XML_ENT_EXPANDING;
+    xmlBufGetChildContent(buf, (xmlNodePtr) ent);
+    ent->flags &= ~XML_ENT_EXPANDING;
+}
+
+static void
+xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree) {
+    const xmlNode *cur = tree->children;
+
+    while (cur != NULL) {
+        switch (cur->type) {
+            case XML_TEXT_NODE:
+            case XML_CDATA_SECTION_NODE:
+                xmlBufCat(buf, cur->content);
+                break;
+
+            case XML_ENTITY_REF_NODE:
+                xmlBufGetEntityRefContent(buf, cur);
+                break;
+
+            default:
+                if (cur->children != NULL) {
+                    cur = cur->children;
+                    continue;
+                }
+                break;
+        }
+
+        while (cur->next == NULL) {
+            cur = cur->parent;
+            if (cur == tree)
+                return;
+        }
+        cur = cur->next;
+    }
+}
+
 /**
  * xmlBufGetNodeContent:
  * @buf:  a buffer xmlBufPtr
@@ -5525,127 +5543,38 @@
 int
 xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur)
 {
-    if ((cur == NULL) || (buf == NULL)) return(-1);
+    if ((cur == NULL) || (buf == NULL))
+        return(-1);
+
     switch (cur->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_ELEMENT_NODE:
+        case XML_ATTRIBUTE_NODE:
+        case XML_ENTITY_DECL:
+            xmlBufGetChildContent(buf, cur);
+            break;
+
         case XML_CDATA_SECTION_NODE:
         case XML_TEXT_NODE:
-	    xmlBufCat(buf, cur->content);
-            break;
-        case XML_DOCUMENT_FRAG_NODE:
-        case XML_ELEMENT_NODE:{
-                const xmlNode *tmp = cur;
-
-                while (tmp != NULL) {
-                    switch (tmp->type) {
-                        case XML_CDATA_SECTION_NODE:
-                        case XML_TEXT_NODE:
-                            if (tmp->content != NULL)
-                                xmlBufCat(buf, tmp->content);
-                            break;
-                        case XML_ENTITY_REF_NODE:
-                            xmlBufGetNodeContent(buf, tmp);
-                            break;
-                        default:
-                            break;
-                    }
-                    /*
-                     * Skip to next node
-                     */
-                    if (tmp->children != NULL) {
-                        if (tmp->children->type != XML_ENTITY_DECL) {
-                            tmp = tmp->children;
-                            continue;
-                        }
-                    }
-                    if (tmp == cur)
-                        break;
-
-                    if (tmp->next != NULL) {
-                        tmp = tmp->next;
-                        continue;
-                    }
-
-                    do {
-                        tmp = tmp->parent;
-                        if (tmp == NULL)
-                            break;
-                        if (tmp == cur) {
-                            tmp = NULL;
-                            break;
-                        }
-                        if (tmp->next != NULL) {
-                            tmp = tmp->next;
-                            break;
-                        }
-                    } while (tmp != NULL);
-                }
-		break;
-            }
-        case XML_ATTRIBUTE_NODE:{
-                xmlAttrPtr attr = (xmlAttrPtr) cur;
-		xmlNodePtr tmp = attr->children;
-
-		while (tmp != NULL) {
-		    if (tmp->type == XML_TEXT_NODE)
-		        xmlBufCat(buf, tmp->content);
-		    else
-		        xmlBufGetNodeContent(buf, tmp);
-		    tmp = tmp->next;
-		}
-                break;
-            }
         case XML_COMMENT_NODE:
         case XML_PI_NODE:
 	    xmlBufCat(buf, cur->content);
             break;
-        case XML_ENTITY_REF_NODE:{
-                xmlEntityPtr ent;
-                xmlNodePtr tmp;
 
-                /* lookup entity declaration */
-                ent = xmlGetDocEntity(cur->doc, cur->name);
-                if (ent == NULL)
-                    return(-1);
-
-                /* an entity content can be any "well balanced chunk",
-                 * i.e. the result of the content [43] production:
-                 * http://www.w3.org/TR/REC-xml#NT-content
-                 * -> we iterate through child nodes and recursive call
-                 * xmlNodeGetContent() which handles all possible node types */
-                tmp = ent->children;
-                while (tmp) {
-		    xmlBufGetNodeContent(buf, tmp);
-                    tmp = tmp->next;
-                }
-		break;
-            }
-        case XML_ENTITY_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-        case XML_NOTATION_NODE:
-        case XML_DTD_NODE:
-        case XML_XINCLUDE_START:
-        case XML_XINCLUDE_END:
+        case XML_ENTITY_REF_NODE:
+            xmlBufGetEntityRefContent(buf, cur);
             break;
-        case XML_DOCUMENT_NODE:
-        case XML_HTML_DOCUMENT_NODE:
-	    cur = cur->children;
-	    while (cur!= NULL) {
-		if ((cur->type == XML_ELEMENT_NODE) ||
-		    (cur->type == XML_TEXT_NODE) ||
-		    (cur->type == XML_CDATA_SECTION_NODE)) {
-		    xmlBufGetNodeContent(buf, cur);
-		}
-		cur = cur->next;
-	    }
-	    break;
+
         case XML_NAMESPACE_DECL:
 	    xmlBufCat(buf, ((xmlNsPtr) cur)->href);
 	    break;
-        case XML_ELEMENT_DECL:
-        case XML_ATTRIBUTE_DECL:
-        case XML_ENTITY_DECL:
+
+        default:
             break;
     }
+
     return(0);
 }
 
@@ -5663,98 +5592,103 @@
 xmlChar *
 xmlNodeGetContent(const xmlNode *cur)
 {
+    xmlBufPtr buf;
+    xmlChar *ret;
+
     if (cur == NULL)
         return (NULL);
-    switch (cur->type) {
-        case XML_DOCUMENT_FRAG_NODE:
-        case XML_ELEMENT_NODE:{
-                xmlBufPtr buf;
-                xmlChar *ret;
 
-                buf = xmlBufCreateSize(64);
-                if (buf == NULL)
-                    return (NULL);
-                xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
-		xmlBufGetNodeContent(buf, cur);
-                ret = xmlBufDetach(buf);
-                xmlBufFree(buf);
-                return (ret);
-            }
+    switch (cur->type) {
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_ENTITY_REF_NODE:
+            break;
+
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_ELEMENT_NODE:
         case XML_ATTRIBUTE_NODE:
-	    return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur));
+        case XML_ENTITY_DECL: {
+            xmlNodePtr children = cur->children;
+
+            if (children == NULL)
+                return(xmlStrdup(BAD_CAST ""));
+
+            /* Optimization for single text children */
+            if (((children->type == XML_TEXT_NODE) ||
+                 (children->type == XML_CDATA_SECTION_NODE)) &&
+                (children->next == NULL)) {
+                if (children->content == NULL)
+                    return(xmlStrdup(BAD_CAST ""));
+                return(xmlStrdup(children->content));
+            }
+
+            break;
+        }
+
+        case XML_CDATA_SECTION_NODE:
+        case XML_TEXT_NODE:
         case XML_COMMENT_NODE:
         case XML_PI_NODE:
             if (cur->content != NULL)
-                return (xmlStrdup(cur->content));
+                return(xmlStrdup(cur->content));
             else
-                return (xmlStrdup(BAD_CAST ""));
-            return (NULL);
-        case XML_ENTITY_REF_NODE:{
-                xmlEntityPtr ent;
-                xmlBufPtr buf;
-                xmlChar *ret;
+                return(xmlStrdup(BAD_CAST ""));
 
-                /* lookup entity declaration */
-                ent = xmlGetDocEntity(cur->doc, cur->name);
-                if (ent == NULL)
-                    return (NULL);
+        case XML_NAMESPACE_DECL:
+	    return(xmlStrdup(((xmlNsPtr) cur)->href));
 
-                buf = xmlBufCreate();
-                if (buf == NULL)
-                    return (NULL);
-                xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
-
-                xmlBufGetNodeContent(buf, cur);
-
-                ret = xmlBufDetach(buf);
-                xmlBufFree(buf);
-                return (ret);
-            }
-        case XML_ENTITY_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-        case XML_NOTATION_NODE:
-        case XML_DTD_NODE:
-        case XML_XINCLUDE_START:
-        case XML_XINCLUDE_END:
-            return (NULL);
-        case XML_DOCUMENT_NODE:
-        case XML_HTML_DOCUMENT_NODE: {
-	    xmlBufPtr buf;
-	    xmlChar *ret;
-
-	    buf = xmlBufCreate();
-	    if (buf == NULL)
-		return (NULL);
-            xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
-
-	    xmlBufGetNodeContent(buf, (xmlNodePtr) cur);
-
-	    ret = xmlBufDetach(buf);
-	    xmlBufFree(buf);
-	    return (ret);
-	}
-        case XML_NAMESPACE_DECL: {
-	    xmlChar *tmp;
-
-	    tmp = xmlStrdup(((xmlNsPtr) cur)->href);
-            return (tmp);
-	}
-        case XML_ELEMENT_DECL:
-            /* TODO !!! */
-            return (NULL);
-        case XML_ATTRIBUTE_DECL:
-            /* TODO !!! */
-            return (NULL);
-        case XML_ENTITY_DECL:
-            /* TODO !!! */
-            return (NULL);
-        case XML_CDATA_SECTION_NODE:
-        case XML_TEXT_NODE:
-            if (cur->content != NULL)
-                return (xmlStrdup(cur->content));
-            return (NULL);
+        default:
+            return(NULL);
     }
-    return (NULL);
+
+    buf = xmlBufCreateSize(64);
+    if (buf == NULL)
+        return (NULL);
+    xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
+    xmlBufGetNodeContent(buf, cur);
+    ret = xmlBufDetach(buf);
+    xmlBufFree(buf);
+
+    return(ret);
+}
+
+static int
+xmlNodeSetContentInternal(xmlNodePtr cur, const xmlChar *content, int len) {
+    if (cur == NULL) {
+	return(1);
+    }
+    switch (cur->type) {
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_ELEMENT_NODE:
+        case XML_ATTRIBUTE_NODE:
+            if (xmlNodeParseContent(cur, content, len) < 0)
+                return(-1);
+	    break;
+
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE: {
+            xmlChar *copy = NULL;
+
+	    if (content != NULL) {
+                if (len < 0)
+                    copy = xmlStrdup(content);
+                else
+		    copy = xmlStrndup(content, len);
+                if (copy == NULL)
+                    return(-1);
+	    }
+
+            xmlTextSetContent(cur, copy);
+	    break;
+        }
+
+        default:
+            break;
+    }
+
+    return(0);
 }
 
 /**
@@ -5762,86 +5696,27 @@
  * @cur:  the node being modified
  * @content:  the new value of the content
  *
- * Replace the content of a node.
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
- *       references, but XML special chars need to be escaped first by using
- *       xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
+ * Replace the text content of a node.
+ *
+ * Sets the raw text content of text, CDATA, comment or PI nodes.
+ *
+ * For element and attribute nodes, removes all children and
+ * replaces them by parsing @content which is expected to be a
+ * valid XML attribute value possibly containing character and
+ * entity references. Syntax errors and references to undeclared
+ * entities are ignored silently. Unfortunately, there isn't an
+ * API to pass raw content directly. An inefficient work-around
+ * is to escape the content with xmlEncodeSpecialChars before
+ * passing it. A better trick is clearing the old content
+ * with xmlNodeSetContent(node, NULL) first and then calling
+ * xmlNodeAddContent(node, content). Unlike this function,
+ * xmlNodeAddContent accepts raw text.
  *
  * Returns 0 on success, 1 on error, -1 if a memory allocation failed.
  */
 int
 xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
-    if (cur == NULL) {
-	return(1);
-    }
-    switch (cur->type) {
-        case XML_DOCUMENT_FRAG_NODE:
-        case XML_ELEMENT_NODE:
-        case XML_ATTRIBUTE_NODE: {
-            xmlNodePtr list = NULL;
-
-            if (content != NULL) {
-	        list = xmlStringGetNodeList(cur->doc, content);
-                if (list == NULL)
-                    return(-1);
-            }
-
-	    if (cur->children != NULL)
-                xmlFreeNodeList(cur->children);
-	    cur->children = list;
-	    UPDATE_LAST_CHILD_AND_PARENT(cur)
-	    break;
-        }
-        case XML_TEXT_NODE:
-        case XML_CDATA_SECTION_NODE:
-        case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
-        case XML_PI_NODE:
-        case XML_COMMENT_NODE: {
-            xmlChar *copy = NULL;
-
-	    if (content != NULL) {
-		copy = xmlStrdup(content);
-                if (copy == NULL)
-                    return(-1);
-            }
-
-	    if ((cur->content != NULL) &&
-	        (cur->content != (xmlChar *) &(cur->properties))) {
-	        if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
-		    (xmlDictOwns(cur->doc->dict, cur->content))))
-		    xmlFree(cur->content);
-	    }
-	    if (cur->children != NULL)
-                xmlFreeNodeList(cur->children);
-	    cur->last = cur->children = NULL;
-            cur->content = copy;
-	    break;
-        }
-        case XML_DOCUMENT_NODE:
-        case XML_HTML_DOCUMENT_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-	case XML_XINCLUDE_START:
-	case XML_XINCLUDE_END:
-	    break;
-        case XML_NOTATION_NODE:
-	    break;
-        case XML_DTD_NODE:
-	    break;
-	case XML_NAMESPACE_DECL:
-	    break;
-        case XML_ELEMENT_DECL:
-	    /* TODO !!! */
-	    break;
-        case XML_ATTRIBUTE_DECL:
-	    /* TODO !!! */
-	    break;
-        case XML_ENTITY_DECL:
-	    /* TODO !!! */
-	    break;
-    }
-
-    return(0);
+    return(xmlNodeSetContentInternal(cur, content, -1));
 }
 
 #ifdef LIBXML_TREE_ENABLED
@@ -5851,84 +5726,13 @@
  * @content:  the new value of the content
  * @len:  the size of @content
  *
- * Replace the content of a node.
- * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity
- *       references, but XML special chars need to be escaped first by using
- *       xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars().
+ * See xmlNodeSetContent.
  *
  * Returns 0 on success, 1 on error, -1 if a memory allocation failed.
  */
 int
 xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
-    if (cur == NULL) {
-	return(1);
-    }
-    switch (cur->type) {
-        case XML_DOCUMENT_FRAG_NODE:
-        case XML_ELEMENT_NODE:
-        case XML_ATTRIBUTE_NODE: {
-            xmlNodePtr list = NULL;
-
-            if (content != NULL) {
-	        list = xmlStringLenGetNodeList(cur->doc, content, len);
-                if (list == NULL)
-                    return(-1);
-            }
-
-	    if (cur->children != NULL)
-                xmlFreeNodeList(cur->children);
-	    cur->children = list;
-	    UPDATE_LAST_CHILD_AND_PARENT(cur)
-	    break;
-        }
-        case XML_TEXT_NODE:
-        case XML_CDATA_SECTION_NODE:
-        case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
-        case XML_PI_NODE:
-        case XML_COMMENT_NODE:
-        case XML_NOTATION_NODE: {
-            xmlChar *copy = NULL;
-
-	    if (content != NULL) {
-		copy = xmlStrndup(content, len);
-                if (copy == NULL)
-                    return(-1);
-	    }
-
-	    if ((cur->content != NULL) &&
-	        (cur->content != (xmlChar *) &(cur->properties))) {
-	        if (!((cur->doc != NULL) && (cur->doc->dict != NULL) &&
-		    (xmlDictOwns(cur->doc->dict, cur->content))))
-		    xmlFree(cur->content);
-	    }
-	    if (cur->children != NULL)
-                xmlFreeNodeList(cur->children);
-	    cur->children = cur->last = NULL;
-	    cur->content = copy;
-	    cur->properties = NULL;
-	    break;
-        }
-        case XML_DOCUMENT_NODE:
-        case XML_DTD_NODE:
-        case XML_HTML_DOCUMENT_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-	case XML_NAMESPACE_DECL:
-	case XML_XINCLUDE_START:
-	case XML_XINCLUDE_END:
-	    break;
-        case XML_ELEMENT_DECL:
-	    /* TODO !!! */
-	    break;
-        case XML_ATTRIBUTE_DECL:
-	    /* TODO !!! */
-	    break;
-        case XML_ENTITY_DECL:
-	    /* TODO !!! */
-	    break;
-    }
-
-    return(0);
+    return(xmlNodeSetContentInternal(cur, content, len));
 }
 #endif /* LIBXML_TREE_ENABLED */
 
@@ -5961,49 +5765,21 @@
 	    if (newNode == NULL)
                 return(-1);
             tmp = xmlAddChild(cur, newNode);
-            if (tmp == NULL)
+            if (tmp == NULL) {
+                xmlFreeNode(newNode);
                 return(-1);
+            }
 	    break;
 	}
         case XML_ATTRIBUTE_NODE:
 	    break;
         case XML_TEXT_NODE:
         case XML_CDATA_SECTION_NODE:
-        case XML_ENTITY_REF_NODE:
-        case XML_ENTITY_NODE:
         case XML_PI_NODE:
         case XML_COMMENT_NODE:
-        case XML_NOTATION_NODE: {
-            xmlChar *newContent = NULL;
-
-            if ((cur->content == (xmlChar *) &(cur->properties)) ||
-                ((cur->doc != NULL) && (cur->doc->dict != NULL) &&
-                        xmlDictOwns(cur->doc->dict, cur->content))) {
-                newContent = xmlStrncatNew(cur->content, content, len);
-                if (newContent == NULL)
-                    return(-1);
-                cur->properties = NULL;
-            } else {
-                newContent = xmlStrncatNew(cur->content, content, len);
-                if (newContent == NULL)
-                    return(-1);
-                xmlFree(cur->content);
-            }
-            cur->content = newContent;
-	    break;
-        }
-        case XML_DOCUMENT_NODE:
-        case XML_DTD_NODE:
-        case XML_HTML_DOCUMENT_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-	case XML_NAMESPACE_DECL:
-	case XML_XINCLUDE_START:
-	case XML_XINCLUDE_END:
-	    break;
-        case XML_ELEMENT_DECL:
-        case XML_ATTRIBUTE_DECL:
-        case XML_ENTITY_DECL:
-	    break;
+            return(xmlTextAddContent(cur, content, len));
+        default:
+            break;
     }
 
     return(0);
@@ -6031,18 +5807,22 @@
  * @first:  the first text node
  * @second:  the second text node being merged
  *
- * Merge two text nodes into one
- * Returns the first text node augmented
+ * Merge the second text node into the first. The second node is
+ * unlinked and freed.
+ *
+ * Returns the first text node augmented or NULL in case of error.
  */
 xmlNodePtr
 xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
-    if (first == NULL) return(second);
-    if (second == NULL) return(first);
-    if (first->type != XML_TEXT_NODE) return(first);
-    if (second->type != XML_TEXT_NODE) return(first);
-    if (second->name != first->name)
-	return(first);
-    xmlNodeAddContent(first, second->content);
+    if ((first == NULL) || (first->type != XML_TEXT_NODE) ||
+        (second == NULL) || (second->type != XML_TEXT_NODE) ||
+        (first == second) ||
+        (first->name != second->name))
+	return(NULL);
+
+    if (xmlTextAddContent(first, second->content, -1) < 0)
+        return(NULL);
+
     xmlUnlinkNode(second);
     xmlFreeNode(second);
     return(first);
@@ -6050,17 +5830,17 @@
 
 #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
 /**
- * xmlGetNsList:
+ * xmlGetNsListSafe:
  * @doc:  the document
  * @node:  the current node
  * @out:  the returned namespace array
  *
- * Search all the namespace applying to a given element. @out returns
- * a NULL terminated array of all the namespaces found that needs to be
- * freed by the caller allocation failed.
+ * Find all in-scope namespaces of a node. @out returns a NULL
+ * terminated array of namespace pointers that must be freed by
+ * the caller.
  *
- * Returns 0 on success, 1 if no namespace were found, -1 if a memory
- * allocation failed.
+ * Returns 0 on success, 1 if no namespaces were found, -1 if a
+ * memory allocation failed.
  */
 int
 xmlGetNsListSafe(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node,
@@ -6120,10 +5900,13 @@
  * @doc:  the document
  * @node:  the current node
  *
- * Search all the namespace applying to a given element.
- * Returns an NULL terminated array of all the #xmlNsPtr found
- *         that need to be freed by the caller or NULL if a memory
- *         allocation failed
+ * Find all in-scope namespaces of a node.
+ *
+ * Use xmlGetNsListSafe for better error reporting.
+ *
+ * Returns a NULL terminated array of namespace pointers that must
+ * be freed by the caller or NULL if no namespaces were found or
+ * a memory allocation failed.
  */
 xmlNsPtr *
 xmlGetNsList(const xmlDoc *doc, const xmlNode *node)
@@ -6135,6 +5918,29 @@
 }
 #endif /* LIBXML_TREE_ENABLED */
 
+static xmlNsPtr
+xmlNewXmlNs(void) {
+    xmlNsPtr ns;
+
+    ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+    if (ns == NULL)
+        return(NULL);
+    memset(ns, 0, sizeof(xmlNs));
+    ns->type = XML_LOCAL_NAMESPACE;
+    ns->href = xmlStrdup(XML_XML_NAMESPACE);
+    if (ns->href == NULL) {
+        xmlFreeNs(ns);
+        return(NULL);
+    }
+    ns->prefix = xmlStrdup(BAD_CAST "xml");
+    if (ns->prefix == NULL) {
+        xmlFreeNs(ns);
+        return(NULL);
+    }
+
+    return(ns);
+}
+
 /*
 * xmlTreeEnsureXMLDecl:
 * @doc: the doc
@@ -6143,33 +5949,89 @@
 *
 * Returns the XML ns-struct or NULL if a memory allocation failed.
 */
-xmlNsPtr
+static xmlNsPtr
 xmlTreeEnsureXMLDecl(xmlDocPtr doc)
 {
-    if (doc == NULL)
-	return (NULL);
-    if (doc->oldNs != NULL)
-	return (doc->oldNs);
-    {
-	xmlNsPtr ns;
-	ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
-	if (ns == NULL)
-	    return(NULL);
-	memset(ns, 0, sizeof(xmlNs));
-	ns->type = XML_LOCAL_NAMESPACE;
-	ns->href = xmlStrdup(XML_XML_NAMESPACE);
-        if (ns->href == NULL) {
-            xmlFreeNs(ns);
-            return(NULL);
-        }
-	ns->prefix = xmlStrdup((const xmlChar *)"xml");
-        if (ns->prefix == NULL) {
-            xmlFreeNs(ns);
-            return(NULL);
-        }
-	doc->oldNs = ns;
+    xmlNsPtr ns;
+
+    ns = doc->oldNs;
+    if (ns != NULL)
 	return (ns);
+
+    ns = xmlNewXmlNs();
+    doc->oldNs = ns;
+
+    return(ns);
+}
+
+int
+xmlSearchNsSafe(xmlNodePtr node, const xmlChar *prefix,
+                xmlNsPtr *out) {
+    xmlNsPtr cur;
+    xmlDocPtr doc;
+    xmlNodePtr orig = node;
+    xmlNodePtr parent;
+
+    if (out == NULL)
+        return(1);
+    *out = NULL;
+    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
+        return(1);
+
+    doc = node->doc;
+
+    if ((doc != NULL) && (IS_STR_XML(prefix))) {
+        cur = xmlTreeEnsureXMLDecl(doc);
+        if (cur == NULL)
+            return(-1);
+        *out = cur;
+        return(0);
     }
+
+    while (node->type != XML_ELEMENT_NODE) {
+        node = node->parent;
+        if (node == NULL)
+            return(0);
+    }
+
+    parent = node;
+
+    while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
+        cur = node->nsDef;
+        while (cur != NULL) {
+            if (xmlStrEqual(cur->prefix, prefix)) {
+                *out = cur;
+                return(0);
+            }
+            cur = cur->next;
+        }
+        if (orig != node) {
+            cur = node->ns;
+            if ((cur != NULL) &&
+                (xmlStrEqual(cur->prefix, prefix))) {
+                *out = cur;
+                return(0);
+            }
+        }
+
+	node = node->parent;
+    }
+
+    /*
+     * The XML-1.0 namespace is normally held on the document
+     * element. In this case exceptionally create it on the
+     * node element.
+     */
+    if ((doc == NULL) && (IS_STR_XML(prefix))) {
+        cur = xmlNewXmlNs();
+        if (cur == NULL)
+            return(-1);
+        cur->next = parent->nsDef;
+        parent->nsDef = cur;
+        *out = cur;
+    }
+
+    return(0);
 }
 
 /**
@@ -6188,81 +6050,15 @@
  *
  * Returns the namespace pointer or NULL if no namespace was found or
  * a memory allocation failed. Allocations can only fail if the "xml"
- * namespace is queried and xmlTreeEnsureXMLDecl wasn't called
- * successfully or doc is NULL.
+ * namespace is queried.
  */
 xmlNsPtr
-xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
-
+xmlSearchNs(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
+            const xmlChar *nameSpace) {
     xmlNsPtr cur;
-    const xmlNode *orig = node;
 
-    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL);
-    if ((nameSpace != NULL) &&
-	(xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
-	if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
-	    /*
-	     * The XML-1.0 namespace is normally held on the root
-	     * element. In this case exceptionally create it on the
-	     * node element.
-	     */
-	    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
-	    if (cur == NULL)
-		return(NULL);
-	    memset(cur, 0, sizeof(xmlNs));
-	    cur->type = XML_LOCAL_NAMESPACE;
-	    cur->href = xmlStrdup(XML_XML_NAMESPACE);
-	    cur->prefix = xmlStrdup((const xmlChar *)"xml");
-	    cur->next = node->nsDef;
-	    node->nsDef = cur;
-	    return(cur);
-	}
-	if (doc == NULL) {
-	    doc = node->doc;
-	    if (doc == NULL)
-		return(NULL);
-	}
-	/*
-	* Return the XML namespace declaration held by the doc.
-	*/
-	if (doc->oldNs == NULL)
-	    return(xmlTreeEnsureXMLDecl(doc));
-	else
-	    return(doc->oldNs);
-    }
-    while (node != NULL) {
-	if ((node->type == XML_ENTITY_REF_NODE) ||
-	    (node->type == XML_ENTITY_NODE) ||
-	    (node->type == XML_ENTITY_DECL))
-	    return(NULL);
-	if (node->type == XML_ELEMENT_NODE) {
-	    cur = node->nsDef;
-	    while (cur != NULL) {
-		if ((cur->prefix == NULL) && (nameSpace == NULL) &&
-		    (cur->href != NULL))
-		    return(cur);
-		if ((cur->prefix != NULL) && (nameSpace != NULL) &&
-		    (cur->href != NULL) &&
-		    (xmlStrEqual(cur->prefix, nameSpace)))
-		    return(cur);
-		cur = cur->next;
-	    }
-	    if (orig != node) {
-	        cur = node->ns;
-	        if (cur != NULL) {
-		    if ((cur->prefix == NULL) && (nameSpace == NULL) &&
-		        (cur->href != NULL))
-		        return(cur);
-		    if ((cur->prefix != NULL) && (nameSpace != NULL) &&
-		        (cur->href != NULL) &&
-		        (xmlStrEqual(cur->prefix, nameSpace)))
-		        return(cur);
-	        }
-	    }
-	}
-	node = node->parent;
-    }
-    return(NULL);
+    xmlSearchNsSafe(node, nameSpace, &cur);
+    return(cur);
 }
 
 /**
@@ -6285,7 +6081,6 @@
 
     while ((node != NULL) && (node != ancestor)) {
         if ((node->type == XML_ENTITY_REF_NODE) ||
-            (node->type == XML_ENTITY_NODE) ||
             (node->type == XML_ENTITY_DECL))
             return (-1);
         if (node->type == XML_ELEMENT_NODE) {
@@ -6308,6 +6103,87 @@
     return (1);
 }
 
+int
+xmlSearchNsByHrefSafe(xmlNodePtr node, const xmlChar *href,
+                      xmlNsPtr *out) {
+    xmlNsPtr cur;
+    xmlDocPtr doc;
+    xmlNodePtr orig = node;
+    xmlNodePtr parent;
+    int is_attr;
+
+    if (out == NULL)
+        return(1);
+    *out = NULL;
+    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
+        return(1);
+
+    doc = node->doc;
+
+    if ((doc != NULL) && (xmlStrEqual(href, XML_XML_NAMESPACE))) {
+        cur = xmlTreeEnsureXMLDecl(doc);
+        if (cur == NULL)
+            return(-1);
+        *out = cur;
+        return(0);
+    }
+
+    is_attr = (node->type == XML_ATTRIBUTE_NODE);
+
+    while (node->type != XML_ELEMENT_NODE) {
+        node = node->parent;
+        if (node == NULL)
+            return(0);
+    }
+
+    parent = node;
+
+    while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
+        cur = node->nsDef;
+        while (cur != NULL) {
+            if (xmlStrEqual(cur->href, href)) {
+                if (((!is_attr) || (cur->prefix != NULL)) &&
+                    (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) {
+                    *out = cur;
+                    return(0);
+                }
+            }
+            cur = cur->next;
+        }
+        if (orig != node) {
+            cur = node->ns;
+            if (cur != NULL) {
+                if (xmlStrEqual(cur->href, href)) {
+                    if (((!is_attr) || (cur->prefix != NULL)) &&
+                        (xmlNsInScope(doc, orig, node,
+                                      cur->prefix) == 1)) {
+                        *out = cur;
+                        return(0);
+                    }
+                }
+            }
+        }
+
+        node = node->parent;
+    }
+
+    /*
+     * The XML-1.0 namespace is normally held on the document
+     * element. In this case exceptionally create it on the
+     * node element.
+     */
+    if ((doc == NULL) && (xmlStrEqual(href, XML_XML_NAMESPACE))) {
+        cur = xmlNewXmlNs();
+        if (cur == NULL)
+            return(-1);
+        cur->next = parent->nsDef;
+        parent->nsDef = cur;
+        *out = cur;
+    }
+
+    return(0);
+}
+
 /**
  * xmlSearchNsByHref:
  * @doc:  the document
@@ -6319,84 +6195,15 @@
  *
  * Returns the namespace pointer or NULL if no namespace was found or
  * a memory allocation failed. Allocations can only fail if the "xml"
- * namespace is queried and xmlTreeEnsureXMLDecl wasn't called
- * successfully or doc is NULL.
+ * namespace is queried.
  */
 xmlNsPtr
-xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href)
-{
+xmlSearchNsByHref(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
+                  const xmlChar * href) {
     xmlNsPtr cur;
-    xmlNodePtr orig = node;
-    int is_attr;
 
-    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL))
-        return (NULL);
-    if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
-        /*
-         * Only the document can hold the XML spec namespace.
-         */
-        if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) {
-            /*
-             * The XML-1.0 namespace is normally held on the root
-             * element. In this case exceptionally create it on the
-             * node element.
-             */
-            cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
-            if (cur == NULL)
-                return (NULL);
-            memset(cur, 0, sizeof(xmlNs));
-            cur->type = XML_LOCAL_NAMESPACE;
-            cur->href = xmlStrdup(XML_XML_NAMESPACE);
-            cur->prefix = xmlStrdup((const xmlChar *) "xml");
-            cur->next = node->nsDef;
-            node->nsDef = cur;
-            return (cur);
-        }
-	if (doc == NULL) {
-	    doc = node->doc;
-	    if (doc == NULL)
-		return(NULL);
-	}
-	/*
-	* Return the XML namespace declaration held by the doc.
-	*/
-	if (doc->oldNs == NULL)
-	    return(xmlTreeEnsureXMLDecl(doc));
-	else
-	    return(doc->oldNs);
-    }
-    is_attr = (node->type == XML_ATTRIBUTE_NODE);
-    while (node != NULL) {
-        if ((node->type == XML_ENTITY_REF_NODE) ||
-            (node->type == XML_ENTITY_NODE) ||
-            (node->type == XML_ENTITY_DECL))
-            return (NULL);
-        if (node->type == XML_ELEMENT_NODE) {
-            cur = node->nsDef;
-            while (cur != NULL) {
-                if ((cur->href != NULL) && (href != NULL) &&
-                    (xmlStrEqual(cur->href, href))) {
-		    if (((!is_attr) || (cur->prefix != NULL)) &&
-		        (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
-			return (cur);
-                }
-                cur = cur->next;
-            }
-            if (orig != node) {
-                cur = node->ns;
-                if (cur != NULL) {
-                    if ((cur->href != NULL) && (href != NULL) &&
-                        (xmlStrEqual(cur->href, href))) {
-			if (((!is_attr) || (cur->prefix != NULL)) &&
-		            (xmlNsInScope(doc, orig, node, cur->prefix) == 1))
-			    return (cur);
-                    }
-                }
-            }
-        }
-        node = node->parent;
-    }
-    return (NULL);
+    xmlSearchNsByHrefSafe(node, href, &cur);
+    return(cur);
 }
 
 /**
@@ -6413,10 +6220,11 @@
  * Returns the (new) namespace definition or NULL in case of error
  */
 static xmlNsPtr
-xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
+xmlNewReconciledNs(xmlNodePtr tree, xmlNsPtr ns) {
     xmlNsPtr def;
     xmlChar prefix[50];
     int counter = 1;
+    int res;
 
     if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) {
 	return(NULL);
@@ -6427,7 +6235,9 @@
     /*
      * Search an existing namespace definition inherited.
      */
-    def = xmlSearchNsByHref(doc, tree, ns->href);
+    res = xmlSearchNsByHrefSafe(tree, ns->href, &def);
+    if (res < 0)
+        return(NULL);
     if (def != NULL)
         return(def);
 
@@ -6440,7 +6250,9 @@
     else
 	snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
 
-    def = xmlSearchNs(doc, tree, prefix);
+    res = xmlSearchNsSafe(tree, prefix, &def);
+    if (res < 0)
+        return(NULL);
     while (def != NULL) {
         if (counter > 1000) return(NULL);
 	if (ns->prefix == NULL)
@@ -6448,7 +6260,9 @@
 	else
 	    snprintf((char *) prefix, sizeof(prefix), "%.20s%d",
 		(char *)ns->prefix, counter++);
-	def = xmlSearchNs(doc, tree, prefix);
+	res = xmlSearchNsSafe(tree, prefix, &def);
+        if (res < 0)
+            return(NULL);
     }
 
     /*
@@ -6459,6 +6273,12 @@
 }
 
 #ifdef LIBXML_TREE_ENABLED
+
+typedef struct {
+    xmlNsPtr oldNs;
+    xmlNsPtr newNs;
+} xmlNsCache;
+
 /**
  * xmlReconciliateNs:
  * @doc:  the document
@@ -6471,12 +6291,12 @@
  * as possible the function try to reuse the existing namespaces found in
  * the new environment. If not possible the new namespaces are redeclared
  * on @tree at the top of the given subtree.
- * Returns the number of namespace declarations created or -1 in case of error.
+ *
+ * Returns 0 on success or -1 in case of error.
  */
 int
 xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
-    xmlNsPtr *oldNs = NULL;
-    xmlNsPtr *newNs = NULL;
+    xmlNsCache *cache = NULL;
     int sizeCache = 0;
     int nbCache = 0;
 
@@ -6486,32 +6306,15 @@
     int ret = 0, i;
 
     if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1);
-    if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1);
     if (node->doc != doc) return(-1);
     while (node != NULL) {
         /*
 	 * Reconciliate the node namespace
 	 */
 	if (node->ns != NULL) {
-	    /*
-	     * initialize the cache if needed
-	     */
-	    if (sizeCache == 0) {
-		sizeCache = 10;
-		oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
-					       sizeof(xmlNsPtr));
-		if (oldNs == NULL)
-		    return(-1);
-		newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
-					       sizeof(xmlNsPtr));
-		if (newNs == NULL) {
-		    xmlFree(oldNs);
-		    return(-1);
-		}
-	    }
-	    for (i = 0;i < nbCache;i++) {
-	        if (oldNs[i] == node->ns) {
-		    node->ns = newNs[i];
+	    for (i = 0; i < nbCache; i++) {
+	        if (cache[i].oldNs == node->ns) {
+		    node->ns = cache[i].newNs;
 		    break;
 		}
 	    }
@@ -6519,30 +6322,31 @@
 	        /*
 		 * OK we need to recreate a new namespace definition
 		 */
-		n = xmlNewReconciledNs(doc, tree, node->ns);
-		if (n != NULL) { /* :-( what if else ??? */
+		n = xmlNewReconciledNs(tree, node->ns);
+		if (n == NULL) {
+                    ret = -1;
+                } else {
 		    /*
 		     * check if we need to grow the cache buffers.
 		     */
 		    if (sizeCache <= nbCache) {
-		        sizeCache *= 2;
-			oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
-			                               sizeof(xmlNsPtr));
-		        if (oldNs == NULL) {
-			    xmlFree(newNs);
-			    return(-1);
-			}
-			newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
-			                               sizeof(xmlNsPtr));
-		        if (newNs == NULL) {
-			    xmlFree(oldNs);
-			    return(-1);
-			}
+                        xmlNsCache *tmp;
+                        size_t newSize = sizeCache ? sizeCache * 2 : 10;
+
+			tmp = xmlRealloc(cache, newSize * sizeof(tmp[0]));
+		        if (tmp == NULL) {
+                            ret = -1;
+			} else {
+                            cache = tmp;
+                            sizeCache = newSize;
+                        }
 		    }
-		    newNs[nbCache] = n;
-		    oldNs[nbCache++] = node->ns;
-		    node->ns = n;
+		    if (nbCache < sizeCache) {
+                        cache[nbCache].newNs = n;
+                        cache[nbCache++].oldNs = node->ns;
+                    }
                 }
+		node->ns = n;
 	    }
 	}
 	/*
@@ -6552,25 +6356,9 @@
 	    attr = node->properties;
 	    while (attr != NULL) {
 		if (attr->ns != NULL) {
-		    /*
-		     * initialize the cache if needed
-		     */
-		    if (sizeCache == 0) {
-			sizeCache = 10;
-			oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
-						       sizeof(xmlNsPtr));
-			if (oldNs == NULL)
-			    return(-1);
-			newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
-						       sizeof(xmlNsPtr));
-			if (newNs == NULL) {
-			    xmlFree(oldNs);
-			    return(-1);
-			}
-		    }
-		    for (i = 0;i < nbCache;i++) {
-			if (oldNs[i] == attr->ns) {
-			    attr->ns = newNs[i];
+		    for (i = 0; i < nbCache; i++) {
+			if (cache[i].oldNs == attr->ns) {
+			    attr->ns = cache[i].newNs;
 			    break;
 			}
 		    }
@@ -6578,30 +6366,33 @@
 			/*
 			 * OK we need to recreate a new namespace definition
 			 */
-			n = xmlNewReconciledNs(doc, tree, attr->ns);
-			if (n != NULL) { /* :-( what if else ??? */
+			n = xmlNewReconciledNs(tree, attr->ns);
+			if (n == NULL) {
+                            ret = -1;
+                        } else {
 			    /*
 			     * check if we need to grow the cache buffers.
 			     */
 			    if (sizeCache <= nbCache) {
-				sizeCache *= 2;
-				oldNs = (xmlNsPtr *) xmlRealloc(oldNs,
-				           sizeCache * sizeof(xmlNsPtr));
-				if (oldNs == NULL) {
-				    xmlFree(newNs);
-				    return(-1);
-				}
-				newNs = (xmlNsPtr *) xmlRealloc(newNs,
-				           sizeCache * sizeof(xmlNsPtr));
-				if (newNs == NULL) {
-				    xmlFree(oldNs);
-				    return(-1);
-				}
+                                xmlNsCache *tmp;
+                                size_t newSize = sizeCache ?
+                                        sizeCache * 2 : 10;
+
+                                tmp = xmlRealloc(cache,
+                                        newSize * sizeof(tmp[0]));
+                                if (tmp == NULL) {
+                                    ret = -1;
+                                } else {
+                                    cache = tmp;
+                                    sizeCache = newSize;
+                                }
 			    }
-			    newNs[nbCache] = n;
-			    oldNs[nbCache++] = attr->ns;
-			    attr->ns = n;
+			    if (nbCache < sizeCache) {
+                                cache[nbCache].newNs = n;
+                                cache[nbCache++].oldNs = attr->ns;
+			    }
 			}
+			attr->ns = n;
 		    }
 		}
 		attr = attr->next;
@@ -6637,10 +6428,8 @@
 	} else
 	    break;
     }
-    if (oldNs != NULL)
-	xmlFree(oldNs);
-    if (newNs != NULL)
-	xmlFree(newNs);
+    if (cache != NULL)
+	xmlFree(cache);
     return(ret);
 }
 #endif /* LIBXML_TREE_ENABLED */
@@ -6702,7 +6491,11 @@
 	*/
 	if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
 	    tmpstr = xmlStrdup(node->ns->prefix);
+	    if (tmpstr == NULL)
+		return(NULL);
 	    tmpstr = xmlStrcat(tmpstr, BAD_CAST ":");
+	    if (tmpstr == NULL)
+		return(NULL);
 	    tmpstr = xmlStrcat(tmpstr, node->name);
 	    if (tmpstr == NULL)
 		return(NULL);
@@ -6778,23 +6571,7 @@
     if (prop == NULL)
 	return(NULL);
     if (prop->type == XML_ATTRIBUTE_NODE) {
-	/*
-	* Note that we return at least the empty string.
-	*/
-	if (prop->children != NULL) {
-	    if ((prop->children->next == NULL) &&
-		((prop->children->type == XML_TEXT_NODE) ||
-		(prop->children->type == XML_CDATA_SECTION_NODE)))
-	    {
-		/*
-		* Optimization for the common case: only 1 text node.
-		*/
-		return(xmlStrdup(prop->children->content));
-	    } else {
-		return(xmlNodeListGetString(prop->doc, prop->children, 1));
-	    }
-	}
-	return(xmlStrdup((xmlChar *)""));
+	return(xmlNodeGetContent((xmlNodePtr) prop));
     } else if (prop->type == XML_ATTRIBUTE_DECL) {
 	return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue));
     }
@@ -6808,10 +6585,11 @@
  *
  * Search an attribute associated to a node
  * This function also looks in DTD attribute declaration for #FIXED or
- * default declaration values unless DTD use has been turned off.
+ * default declaration values.
  *
  * Returns the attribute or the attribute declaration or NULL if
- *         neither was found.
+ * neither was found. Also returns NULL if a memory allocation failed
+ * making this function unreliable.
  */
 xmlAttrPtr
 xmlHasProp(const xmlNode *node, const xmlChar *name) {
@@ -6861,11 +6639,12 @@
  * This attribute has to be anchored in the namespace specified.
  * This does the entity substitution.
  * This function looks in DTD attribute declaration for #FIXED or
- * default declaration values unless DTD use has been turned off.
+ * default declaration values.
  * Note that a namespace of NULL indicates to use the default namespace.
  *
- * Returns the attribute or the attribute declaration or NULL
- *     if neither was found.
+ * Returns the attribute or the attribute declaration or NULL if
+ * neither was found. Also returns NULL if a memory allocation failed
+ * making this function unreliable.
  */
 xmlAttrPtr
 xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) {
@@ -7055,8 +6834,10 @@
  */
 xmlAttrPtr
 xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
-    int len;
-    const xmlChar *nqname;
+    xmlNsPtr ns = NULL;
+    const xmlChar *localname;
+    xmlChar *prefix;
+    int res;
 
     if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE))
 	return(NULL);
@@ -7064,16 +6845,19 @@
     /*
      * handle QNames
      */
-    nqname = xmlSplitQName3(name, &len);
-    if (nqname != NULL) {
-        xmlNsPtr ns;
-	xmlChar *prefix = xmlStrndup(name, len);
-	ns = xmlSearchNs(node->doc, node, prefix);
-	if (prefix != NULL)
-	    xmlFree(prefix);
-	if (ns != NULL)
-	    return(xmlSetNsProp(node, ns, nqname, value));
+    localname = xmlSplitQName4(name, &prefix);
+    if (localname == NULL)
+        return(NULL);
+
+    if (prefix != NULL) {
+	res = xmlSearchNsSafe(node, prefix, &ns);
+	xmlFree(prefix);
+        if (res < 0)
+            return(NULL);
+        if (ns != NULL)
+            return(xmlSetNsProp(node, ns, localname, value));
     }
+
     return(xmlSetNsProp(node, NULL, name, value));
 }
 
@@ -7097,6 +6881,8 @@
 
     if (ns && (ns->href == NULL))
 	return(NULL);
+    if (name == NULL)
+        return(NULL);
     prop = xmlGetPropNodeInternal(node, name,
                                   (ns != NULL) ? ns->href : NULL, 0);
     if (prop != NULL) {
@@ -7134,7 +6920,7 @@
 	    }
 	}
 	if ((prop->atype == XML_ATTRIBUTE_ID) &&
-	    (xmlAddIDSafe(node->doc, value, prop, 0, NULL) < 0)) {
+	    (xmlAddIDSafe(prop, value) < 0)) {
             return(NULL);
         }
 	return(prop);
@@ -7195,33 +6981,25 @@
  * @content:  the content
  * @len:  @content length
  *
- * Concat the given string at the end of the existing node content
+ * Concat the given string at the end of the existing node content.
+ *
+ * If @len is -1, the string length will be calculated.
  *
  * Returns -1 in case of error, 0 otherwise
  */
 
 int
 xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
-    if (node == NULL) return(-1);
+    if (node == NULL)
+        return(-1);
 
     if ((node->type != XML_TEXT_NODE) &&
         (node->type != XML_CDATA_SECTION_NODE) &&
 	(node->type != XML_COMMENT_NODE) &&
-	(node->type != XML_PI_NODE)) {
+	(node->type != XML_PI_NODE))
         return(-1);
-    }
-    /* need to check if content is currently in the dictionary */
-    if ((node->content == (xmlChar *) &(node->properties)) ||
-        ((node->doc != NULL) && (node->doc->dict != NULL) &&
-		xmlDictOwns(node->doc->dict, node->content))) {
-	node->content = xmlStrncatNew(node->content, content, len);
-    } else {
-        node->content = xmlStrncat(node->content, content, len);
-    }
-    node->properties = NULL;
-    if (node->content == NULL)
-        return(-1);
-    return(0);
+
+    return(xmlTextAddContent(node, content, len));
 }
 
 /************************************************************************
@@ -8249,39 +8027,6 @@
 }
 
 /*
-* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict;
-* otherwise copy it, when it was in the source-dict.
-*/
-#define XML_TREE_ADOPT_STR(str) \
-    if (adoptStr && (str != NULL)) { \
-	if (destDoc->dict) { \
-	    const xmlChar *old = str;	\
-	    str = xmlDictLookup(destDoc->dict, str, -1); \
-	    if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \
-	        (!xmlDictOwns(sourceDoc->dict, old))) \
-		xmlFree((char *)old); \
-	} else if ((sourceDoc) && (sourceDoc->dict) && \
-	    xmlDictOwns(sourceDoc->dict, str)) { \
-	    str = BAD_CAST xmlStrdup(str); \
-	} \
-    }
-
-/*
-* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then
-* put it in dest-dict or copy it.
-*/
-#define XML_TREE_ADOPT_STR_2(str) \
-    if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \
-	(sourceDoc->dict != NULL) && \
-	xmlDictOwns(sourceDoc->dict, cur->content)) { \
-	if (destDoc->dict) \
-	    cur->content = (xmlChar *) \
-		xmlDictLookup(destDoc->dict, cur->content, -1); \
-	else \
-	    cur->content = xmlStrdup(BAD_CAST cur->content); \
-    }
-
-/*
 * xmlDOMWrapNSNormAddNsMapItem2:
 *
 * For internal use. Adds a ns-decl mapping.
@@ -8292,19 +8037,18 @@
 xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number,
 			xmlNsPtr oldNs, xmlNsPtr newNs)
 {
-    if (*list == NULL) {
-	*list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr));
-	if (*list == NULL)
-	    return(-1);
-	*size = 3;
-	*number = 0;
-    } else if ((*number) >= (*size)) {
-	*size *= 2;
-	*list = (xmlNsPtr *) xmlRealloc(*list,
-	    (*size) * 2 * sizeof(xmlNsPtr));
-	if (*list == NULL)
-	    return(-1);
+    if (*number >= *size) {
+        xmlNsPtr *tmp;
+        size_t newSize;
+
+        newSize = *size ? *size * 2 : 3;
+        tmp = xmlRealloc(*list, newSize * 2 * sizeof(tmp[0]));
+        if (tmp == NULL)
+            return(-1);
+        *list = tmp;
+        *size = newSize;
     }
+
     (*list)[2 * (*number)] = oldNs;
     (*list)[2 * (*number) +1] = newNs;
     (*number)++;
@@ -8333,7 +8077,7 @@
 		     xmlNodePtr node, int options ATTRIBUTE_UNUSED)
 {
     xmlNsPtr *list = NULL;
-    int sizeList, nbList, i, j;
+    int sizeList = 0, nbList = 0, ret = 0, i, j;
     xmlNsPtr ns;
 
     if ((node == NULL) || (doc == NULL) || (node->doc != doc))
@@ -8369,7 +8113,7 @@
 		    do {
 			if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
 			    &nbList, ns, ns) == -1)
-			    goto internal_error;
+			    ret = -1;
 			ns = ns->next;
 		    } while (ns != NULL);
 		}
@@ -8399,7 +8143,7 @@
 			ns = xmlDOMWrapStoreNs(doc, node->ns->href,
 			    node->ns->prefix);
 			if (ns == NULL)
-			    goto internal_error;
+			    ret = -1;
 		    }
 		    if (ns != NULL) {
 			/*
@@ -8407,7 +8151,7 @@
 			*/
 			if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList,
 			    &nbList, node->ns, ns) == -1)
-			    goto internal_error;
+			    ret = -1;
 		    }
 		    node->ns = ns;
 		}
@@ -8432,19 +8176,22 @@
 	if (node->next != NULL)
 	    node = node->next;
 	else {
+            int type = node->type;
+
 	    node = node->parent;
-	    goto next_sibling;
+            if ((type == XML_ATTRIBUTE_NODE) &&
+                (node != NULL) &&
+                (node->children != NULL)) {
+                node = node->children;
+            } else {
+	        goto next_sibling;
+            }
 	}
     } while (node != NULL);
 
     if (list != NULL)
 	xmlFree(list);
-    return (0);
-
-internal_error:
-    if (list != NULL)
-	xmlFree(list);
-    return (-1);
+    return (ret);
 }
 
 /*
@@ -8542,8 +8289,7 @@
 		out = prev;
 		prev = cur;
 	    }
-	} else if ((cur->type == XML_ENTITY_NODE) ||
-            (cur->type == XML_ENTITY_DECL))
+	} else if (cur->type == XML_ENTITY_DECL)
 	    return (0);
 	cur = cur->parent;
     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
@@ -8605,8 +8351,7 @@
 		    ns = ns->next;
 		} while (ns != NULL);
 	    }
-	} else if ((cur->type == XML_ENTITY_NODE) ||
-            (cur->type == XML_ENTITY_DECL))
+	} else if (cur->type == XML_ENTITY_DECL)
 	    return (0);
 	cur = cur->parent;
     } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur));
@@ -8790,7 +8535,6 @@
 	*/
 	if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns,
 		tmpns, XML_TREE_NSMAP_DOC) == NULL) {
-	    xmlFreeNs(tmpns);
 	    return (-1);
 	}
 	*retNs = tmpns;
@@ -8820,7 +8564,6 @@
 	    }
 	}
 	if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) {
-	    xmlFreeNs(tmpns);
 	    return (-1);
 	}
 	*retNs = tmpns;
@@ -8865,7 +8608,7 @@
     int optRemoveRedundantNS =
 	((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0;
     xmlNsPtr *listRedund = NULL;
-    int sizeRedund = 0, nbRedund = 0, ret, i, j;
+    int sizeRedund = 0, nbRedund = 0, ret = 0, i, j;
 
     if ((elem == NULL) || (elem->doc == NULL) ||
 	(elem->type != XML_ELEMENT_NODE))
@@ -8894,7 +8637,7 @@
 				*/
 				if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
 				    elem->parent) == -1)
-				    goto internal_error;
+				    ret = -1;
 			    }
 			    parnsdone = 1;
 			}
@@ -8916,16 +8659,18 @@
 				    * Add it to the list of redundant ns-decls.
 				    */
 				    if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund,
-					&sizeRedund, &nbRedund, ns, mi->newNs) == -1)
-					goto internal_error;
-				    /*
-				    * Remove the ns-decl from the element-node.
-				    */
-				    if (prevns)
-					prevns->next = ns->next;
-				    else
-					cur->nsDef = ns->next;
-				    goto next_ns_decl;
+					&sizeRedund, &nbRedund, ns, mi->newNs) == -1) {
+					ret = -1;
+                                    } else {
+                                        /*
+                                        * Remove the ns-decl from the element-node.
+                                        */
+                                        if (prevns)
+                                            prevns->next = ns->next;
+                                        else
+                                            cur->nsDef = ns->next;
+                                        goto next_ns_decl;
+                                    }
 				}
 			    }
 			}
@@ -8955,7 +8700,7 @@
 			*/
 			if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns,
 			    depth) == NULL)
-			    goto internal_error;
+			    ret = -1;
 
 			prevns = ns;
 next_ns_decl:
@@ -8975,7 +8720,7 @@
 			((xmlNodePtr) elem->parent->doc != elem->parent)) {
 			if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
 				elem->parent) == -1)
-			    goto internal_error;
+			    ret = -1;
 		    }
 		    parnsdone = 1;
 		}
@@ -9014,7 +8759,7 @@
 			&nsMap, depth,
 			ancestorsOnly,
 			(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
-		    goto internal_error;
+		    ret = -1;
 		cur->ns = ns;
 
 ns_end:
@@ -9074,11 +8819,6 @@
 	}
     } while (cur != NULL);
 
-    ret = 0;
-    goto exit;
-internal_error:
-    ret = -1;
-exit:
     if (listRedund) {
 	for (i = 0, j = 0; i < nbRedund; i++, j += 2) {
 	    xmlFreeNs(listRedund[j]);
@@ -9114,7 +8854,7 @@
 */
 static int
 xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt,
-		      xmlDocPtr sourceDoc,
+		      xmlDocPtr sourceDoc ATTRIBUTE_UNUSED,
 		      xmlNodePtr node,
 		      xmlDocPtr destDoc,
 		      xmlNodePtr destParent,
@@ -9125,22 +8865,13 @@
     xmlNsMapPtr nsMap = NULL;
     xmlNsMapItemPtr mi;
     xmlNsPtr ns = NULL;
-    int depth = -1, adoptStr = 1;
+    int depth = -1;
     /* gather @parent's ns-decls. */
     int parnsdone;
     /* @ancestorsOnly should be set per option. */
     int ancestorsOnly = 0;
 
     /*
-    * Optimize string adoption for equal or none dicts.
-    */
-    if ((sourceDoc != NULL) &&
-	(sourceDoc->dict == destDoc->dict))
-	adoptStr = 0;
-    else
-	adoptStr = 1;
-
-    /*
     * Get the ns-map from the context if available.
     */
     if (ctxt)
@@ -9159,40 +8890,21 @@
 	parnsdone = 0;
 
     cur = node;
-    if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
-	goto internal_error;
 
     while (cur != NULL) {
-	/*
-	* Paranoid source-doc sanity check.
-	*/
-	if (cur->doc != sourceDoc) {
-	    /*
-	    * We'll assume XIncluded nodes if the doc differs.
-	    * TODO: Do we need to reconciliate XIncluded nodes?
-	    * This here skips XIncluded nodes and tries to handle
-	    * broken sequences.
-	    */
-	    if (cur->next == NULL)
-		goto leave_node;
-	    do {
-		cur = cur->next;
-		if ((cur->type == XML_XINCLUDE_END) ||
-		    (cur->doc == node->doc))
-		    break;
-	    } while (cur->next != NULL);
+        if (cur->doc != destDoc) {
+            if (xmlNodeSetDoc(cur, destDoc) < 0)
+                ret = -1;
+        }
 
-	    if (cur->doc != node->doc)
-		goto leave_node;
-	}
-	cur->doc = destDoc;
 	switch (cur->type) {
 	    case XML_XINCLUDE_START:
 	    case XML_XINCLUDE_END:
 		/*
 		* TODO
 		*/
-		return (-1);
+		ret = -1;
+                goto leave_node;
 	    case XML_ELEMENT_NODE:
 		curElem = cur;
 		depth++;
@@ -9213,14 +8925,12 @@
 			*/
 			if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
 			    destParent) == -1)
-			    goto internal_error;
+			    ret = -1;
 			parnsdone = 1;
 		    }
 		    for (ns = cur->nsDef; ns != NULL; ns = ns->next) {
 			/*
 			* NOTE: ns->prefix and ns->href are never in the dict.
-			* XML_TREE_ADOPT_STR(ns->prefix)
-			* XML_TREE_ADOPT_STR(ns->href)
 			*/
 			/*
 			* Does it shadow any ns-decl?
@@ -9242,7 +8952,7 @@
 			*/
 			if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
 			    ns, ns, depth) == NULL)
-			    goto internal_error;
+			    ret = -1;
 		    }
 		}
                 /* Falls through. */
@@ -9254,7 +8964,7 @@
 		if (! parnsdone) {
 		    if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap,
 			destParent) == -1)
-			goto internal_error;
+			ret = -1;
 		    parnsdone = 1;
 		}
 		/*
@@ -9288,7 +8998,7 @@
 		    */
 		    if (xmlDOMWrapNsMapAddItem(&nsMap, -1,
 			    cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL)
-			goto internal_error;
+			ret = -1;
 		    cur->ns = ns;
 		} else {
 		    /*
@@ -9302,15 +9012,11 @@
 			ancestorsOnly,
 			/* ns-decls must be prefixed for attributes. */
 			(cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1)
-			goto internal_error;
+			ret = -1;
 		    cur->ns = ns;
 		}
+
 ns_end:
-		/*
-		* Further node properties.
-		* TODO: Is this all?
-		*/
-		XML_TREE_ADOPT_STR(cur->name)
 		if (cur->type == XML_ELEMENT_NODE) {
 		    cur->psvi = NULL;
 		    cur->line = 0;
@@ -9325,55 +9031,16 @@
 			cur = (xmlNodePtr) cur->properties;
 			continue;
 		    }
-		} else {
-		    /*
-		    * Attributes.
-		    */
-		    if ((sourceDoc != NULL) &&
-			(((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID))
-		    {
-			xmlRemoveID(sourceDoc, (xmlAttrPtr) cur);
-		    }
-		    ((xmlAttrPtr) cur)->atype = 0;
-		    ((xmlAttrPtr) cur)->psvi = NULL;
 		}
 		break;
 	    case XML_TEXT_NODE:
 	    case XML_CDATA_SECTION_NODE:
-		/*
-		* This puts the content in the dest dict, only if
-		* it was previously in the source dict.
-		*/
-		XML_TREE_ADOPT_STR_2(cur->content)
-		goto leave_node;
-	    case XML_ENTITY_REF_NODE:
-		/*
-		* Remove reference to the entity-node.
-		*/
-		cur->content = NULL;
-		cur->children = NULL;
-		cur->last = NULL;
-		if ((destDoc->intSubset) || (destDoc->extSubset)) {
-		    xmlEntityPtr ent;
-		    /*
-		    * Assign new entity-node if available.
-		    */
-		    ent = xmlGetDocEntity(destDoc, cur->name);
-		    if (ent != NULL) {
-			cur->content = ent->content;
-			cur->children = (xmlNodePtr) ent;
-			cur->last = (xmlNodePtr) ent;
-		    }
-		}
-		goto leave_node;
 	    case XML_PI_NODE:
-		XML_TREE_ADOPT_STR(cur->name)
-		XML_TREE_ADOPT_STR_2(cur->content)
-		break;
 	    case XML_COMMENT_NODE:
-		break;
+	    case XML_ENTITY_REF_NODE:
+		goto leave_node;
 	    default:
-		goto internal_error;
+		ret = -1;
 	}
 	/*
 	* Walk the tree.
@@ -9424,12 +9091,6 @@
 	}
     }
 
-    goto exit;
-
-internal_error:
-    ret = -1;
-
-exit:
     /*
     * Cleanup.
     */
@@ -9491,7 +9152,7 @@
 		      int options ATTRIBUTE_UNUSED)
 {
     int ret = 0;
-    xmlNodePtr cur, curElem = NULL;
+    xmlNodePtr cur, cloneElem = NULL;
     xmlNsMapPtr nsMap = NULL;
     xmlNsMapItemPtr mi;
     xmlNsPtr ns;
@@ -9509,7 +9170,8 @@
     xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL;
     xmlDictPtr dict; /* The destination dict */
 
-    if ((node == NULL) || (resNode == NULL) || (destDoc == NULL))
+    if ((node == NULL) || (resNode == NULL) || (destDoc == NULL) ||
+	((destParent != NULL) && (destParent->doc != destDoc)))
 	return(-1);
     /*
     * TODO: Initially we support only element-nodes.
@@ -9571,7 +9233,6 @@
 	    case XML_PI_NODE:
 	    case XML_DOCUMENT_FRAG_NODE:
 	    case XML_ENTITY_REF_NODE:
-	    case XML_ENTITY_NODE:
 		/*
 		* Nodes of xmlNode structure.
 		*/
@@ -9589,6 +9250,7 @@
 			clone->prev = prevClone;
 		    } else
 			parentClone->children = clone;
+                    parentClone->last = clone;
 		} else
 		    resultClone = clone;
 
@@ -9641,7 +9303,12 @@
 	else if (cur->name == xmlStringComment)
 	    clone->name = xmlStringComment;
 	else if (cur->name != NULL) {
-	    DICT_CONST_COPY(cur->name, clone->name);
+            if (dict != NULL)
+                clone->name = xmlDictLookup(dict, cur->name, -1);
+            else
+                clone->name = xmlStrdup(cur->name);
+            if (clone->name == NULL)
+                goto internal_error;
 	}
 
 	switch (cur->type) {
@@ -9652,7 +9319,7 @@
 		*/
 		return (-1);
 	    case XML_ELEMENT_NODE:
-		curElem = cur;
+		cloneElem = clone;
 		depth++;
 		/*
 		* Namespace declarations.
@@ -9679,14 +9346,24 @@
 			*/
 			cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
 			if (cloneNs == NULL)
-			    return(-1);
+			    goto internal_error;
 			memset(cloneNs, 0, sizeof(xmlNs));
 			cloneNs->type = XML_LOCAL_NAMESPACE;
 
-			if (ns->href != NULL)
+			if (ns->href != NULL) {
 			    cloneNs->href = xmlStrdup(ns->href);
-			if (ns->prefix != NULL)
+                            if (cloneNs->href == NULL) {
+                                xmlFreeNs(cloneNs);
+                                goto internal_error;
+                            }
+                        }
+			if (ns->prefix != NULL) {
 			    cloneNs->prefix = xmlStrdup(ns->prefix);
+                            if (cloneNs->prefix == NULL) {
+                                xmlFreeNs(cloneNs);
+                                goto internal_error;
+                            }
+                        }
 
 			*cloneNsDefSlot = cloneNs;
 			cloneNsDefSlot = &(cloneNs->next);
@@ -9732,15 +9409,18 @@
 		/* IDs will be processed further down. */
 		/* cur->ns will be processed further down. */
 		break;
+	    case XML_PI_NODE:
+	    case XML_COMMENT_NODE:
 	    case XML_TEXT_NODE:
 	    case XML_CDATA_SECTION_NODE:
 		/*
 		* Note that this will also cover the values of attributes.
 		*/
-		DICT_COPY(cur->content, clone->content);
-		goto leave_node;
-	    case XML_ENTITY_NODE:
-		/* TODO: What to do here? */
+                if (cur->content != NULL) {
+                    clone->content = xmlStrdup(cur->content);
+                    if (clone->content == NULL)
+                        goto internal_error;
+                }
 		goto leave_node;
 	    case XML_ENTITY_REF_NODE:
 		if (sourceDoc != destDoc) {
@@ -9766,12 +9446,6 @@
 		    clone->last = cur->last;
 		}
 		goto leave_node;
-	    case XML_PI_NODE:
-		DICT_COPY(cur->content, clone->content);
-		goto leave_node;
-	    case XML_COMMENT_NODE:
-		DICT_COPY(cur->content, clone->content);
-		goto leave_node;
 	    default:
 		goto internal_error;
 	}
@@ -9831,8 +9505,8 @@
 	    * Acquire a normalized ns-decl and add it to the map.
 	    */
 	    if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc,
-		/* ns-decls on curElem or on destDoc->oldNs */
-		destParent ? curElem : NULL,
+		/* ns-decls on cloneElem or on destDoc->oldNs */
+		destParent ? cloneElem : NULL,
 		cur->ns, &ns,
 		&nsMap, depth,
 		/* if we need to search only in the ancestor-axis */
@@ -9853,20 +9527,22 @@
 	if ((clone->type == XML_ATTRIBUTE_NODE) &&
 	    (clone->parent != NULL))
 	{
-	    if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) {
+            int res;
 
+	    res = xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone);
+            if (res < 0)
+                goto internal_error;
+            if (res == 1) {
 		xmlChar *idVal;
 
-		idVal = xmlNodeListGetString(cur->doc, cur->children, 1);
-		if (idVal != NULL) {
-		    if (xmlAddIDSafe(destDoc, idVal, (xmlAttrPtr) cur, 0,
-                                     NULL) < 0) {
-			/* TODO: error message. */
-			xmlFree(idVal);
-			goto internal_error;
-		    }
-		    xmlFree(idVal);
-		}
+		idVal = xmlNodeGetContent(cur);
+                if (idVal == NULL)
+                    goto internal_error;
+                if (xmlAddIDSafe((xmlAttrPtr) cur, idVal) < 0) {
+                    xmlFree(idVal);
+                    goto internal_error;
+                }
+                xmlFree(idVal);
 	    }
 	}
 	/*
@@ -9931,11 +9607,6 @@
 	    prevClone = clone;
 	    cur = cur->next;
 	} else if (cur->type != XML_ATTRIBUTE_NODE) {
-	    /*
-	    * Set clone->last.
-	    */
-	    if (clone->parent != NULL)
-		clone->parent->last = clone;
 	    clone = clone->parent;
 	    if (clone != NULL)
 		parentClone = clone->parent;
@@ -10004,19 +9675,22 @@
 */
 static int
 xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt,
-		    xmlDocPtr sourceDoc,
+		    xmlDocPtr sourceDoc ATTRIBUTE_UNUSED,
 		    xmlAttrPtr attr,
 		    xmlDocPtr destDoc,
 		    xmlNodePtr destParent,
 		    int options ATTRIBUTE_UNUSED)
 {
-    xmlNodePtr cur;
-    int adoptStr = 1;
+    int ret = 0;
 
     if ((attr == NULL) || (destDoc == NULL))
 	return (-1);
 
-    attr->doc = destDoc;
+    if (attr->doc != destDoc) {
+        if (xmlSetTreeDoc((xmlNodePtr) attr, destDoc) < 0)
+            ret = -1;
+    }
+
     if (attr->ns != NULL) {
 	xmlNsPtr ns = NULL;
 
@@ -10037,75 +9711,18 @@
 	    */
 	    if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href,
 		&ns, 1) == -1)
-		goto internal_error;
+		ret = -1;
 	    if (ns == NULL) {
 		ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent,
 		    attr->ns->href, attr->ns->prefix, 1);
 	    }
 	}
 	if (ns == NULL)
-	    goto internal_error;
+	    ret = -1;
 	attr->ns = ns;
     }
 
-    XML_TREE_ADOPT_STR(attr->name);
-    attr->atype = 0;
-    attr->psvi = NULL;
-    /*
-    * Walk content.
-    */
-    if (attr->children == NULL)
-	return (0);
-    cur = attr->children;
-    if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL))
-        goto internal_error;
-    while (cur != NULL) {
-	cur->doc = destDoc;
-	switch (cur->type) {
-	    case XML_TEXT_NODE:
-	    case XML_CDATA_SECTION_NODE:
-		XML_TREE_ADOPT_STR_2(cur->content)
-		break;
-	    case XML_ENTITY_REF_NODE:
-		/*
-		* Remove reference to the entity-node.
-		*/
-		cur->content = NULL;
-		cur->children = NULL;
-		cur->last = NULL;
-		if ((destDoc->intSubset) || (destDoc->extSubset)) {
-		    xmlEntityPtr ent;
-		    /*
-		    * Assign new entity-node if available.
-		    */
-		    ent = xmlGetDocEntity(destDoc, cur->name);
-		    if (ent != NULL) {
-			cur->content = ent->content;
-			cur->children = (xmlNodePtr) ent;
-			cur->last = (xmlNodePtr) ent;
-		    }
-		}
-		break;
-	    default:
-		break;
-	}
-	if (cur->children != NULL) {
-	    cur = cur->children;
-	    continue;
-	}
-next_sibling:
-	if (cur == (xmlNodePtr) attr)
-	    break;
-	if (cur->next != NULL)
-	    cur = cur->next;
-	else {
-	    cur = cur->parent;
-	    goto next_sibling;
-	}
-    }
-    return (0);
-internal_error:
-    return (-1);
+    return (ret);
 }
 
 /*
@@ -10143,6 +9760,8 @@
 		    xmlNodePtr destParent,
 		    int options)
 {
+    int ret = 0;
+
     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
         (destDoc == NULL) ||
 	((destParent != NULL) && (destParent->doc != destDoc)))
@@ -10150,17 +9769,18 @@
     /*
     * Check node->doc sanity.
     */
-    if ((node->doc != NULL) && (sourceDoc != NULL) &&
-	(node->doc != sourceDoc)) {
-	/*
-	* Might be an XIncluded node.
-	*/
+    if (sourceDoc == NULL) {
+        sourceDoc = node->doc;
+    } else if (node->doc != sourceDoc) {
 	return (-1);
     }
-    if (sourceDoc == NULL)
-	sourceDoc = node->doc;
+
+    /*
+     * TODO: Shouldn't this be allowed?
+     */
     if (sourceDoc == destDoc)
 	return (-1);
+
     switch (node->type) {
 	case XML_ELEMENT_NODE:
 	case XML_ATTRIBUTE_NODE:
@@ -10189,52 +9809,12 @@
 	    return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc,
 		(xmlAttrPtr) node, destDoc, destParent, options));
     } else {
-	xmlNodePtr cur = node;
-	int adoptStr = 1;
-
-	cur->doc = destDoc;
-	/*
-	* Optimize string adoption.
-	*/
-	if ((sourceDoc != NULL) &&
-	    (sourceDoc->dict == destDoc->dict))
-		adoptStr = 0;
-	switch (node->type) {
-	    case XML_TEXT_NODE:
-	    case XML_CDATA_SECTION_NODE:
-		XML_TREE_ADOPT_STR_2(node->content)
-		    break;
-	    case XML_ENTITY_REF_NODE:
-		/*
-		* Remove reference to the entity-node.
-		*/
-		node->content = NULL;
-		node->children = NULL;
-		node->last = NULL;
-		if ((destDoc->intSubset) || (destDoc->extSubset)) {
-		    xmlEntityPtr ent;
-		    /*
-		    * Assign new entity-node if available.
-		    */
-		    ent = xmlGetDocEntity(destDoc, node->name);
-		    if (ent != NULL) {
-			node->content = ent->content;
-			node->children = (xmlNodePtr) ent;
-			node->last = (xmlNodePtr) ent;
-		    }
-		}
-		XML_TREE_ADOPT_STR(node->name)
-		break;
-	    case XML_PI_NODE: {
-		XML_TREE_ADOPT_STR(node->name)
-		XML_TREE_ADOPT_STR_2(node->content)
-		break;
-	    }
-	    default:
-		break;
-	}
+        if (node->doc != destDoc) {
+            if (xmlNodeSetDoc(node, destDoc) < 0)
+                ret = -1;
+        }
     }
-    return (0);
+    return (ret);
 }
 
 /************************************************************************
diff --git a/src/valid.c b/src/valid.c
index ada36a6..897a368 100644
--- a/src/valid.c
+++ b/src/valid.c
@@ -74,7 +74,9 @@
     xmlParserCtxtPtr pctxt = NULL;
     va_list ap;
 
-    if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT))
+    if (ctxt == NULL)
+        return;
+    if (ctxt->flags & XML_VCTXT_USE_PCTXT)
         pctxt = ctxt->userData;
 
     va_start(ap, msg);
@@ -590,6 +592,8 @@
  * @ctxt:  a validation context
  * @elem:  an element declaration node
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * (Re)Build the automata associated to the content model of this
  * element
  *
@@ -1184,9 +1188,8 @@
 	    }
 	    break;
 	default:
-	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
-		    "Internal: ELEMENT decl corrupted invalid type\n",
-		    NULL);
+	    xmlErrValid(ctxt, XML_ERR_ARGUMENT,
+		    "xmlAddElementDecl: invalid type\n", NULL);
 	    return(NULL);
     }
 
@@ -1423,7 +1426,8 @@
 
     save = xmlSaveToBuffer(buf, NULL, 0);
     xmlSaveTree(save, (xmlNodePtr) elem);
-    xmlSaveClose(save);
+    if (xmlSaveFinish(save) != XML_ERR_OK)
+        xmlFree(xmlBufferDetach(buf));
 }
 
 /**
@@ -1435,9 +1439,9 @@
  * the arguments.
  */
 static void
-xmlDumpElementDeclScan(void *elem, void *buf,
+xmlDumpElementDeclScan(void *elem, void *save,
                        const xmlChar *name ATTRIBUTE_UNUSED) {
-    xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
+    xmlSaveTree(save, elem);
 }
 
 /**
@@ -1451,9 +1455,15 @@
  */
 void
 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
+    xmlSaveCtxtPtr save;
+
     if ((buf == NULL) || (table == NULL))
         return;
-    xmlHashScan(table, xmlDumpElementDeclScan, buf);
+
+    save = xmlSaveToBuffer(buf, NULL, 0);
+    xmlHashScan(table, xmlDumpElementDeclScan, save);
+    if (xmlSaveFinish(save) != XML_ERR_OK)
+        xmlFree(xmlBufferDetach(buf));
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
 
@@ -1686,9 +1696,8 @@
         case XML_ATTRIBUTE_NOTATION:
 	    break;
 	default:
-	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
-		    "Internal: ATTRIBUTE struct corrupted invalid type\n",
-		    NULL);
+	    xmlErrValid(ctxt, XML_ERR_ARGUMENT,
+		    "xmlAddAttributeDecl: invalid type\n", NULL);
 	    xmlFreeEnumeration(tree);
 	    return(NULL);
     }
@@ -1770,9 +1779,13 @@
 	else
 	    ret->defaultValue = xmlStrdup(defaultValue);
         if (ret->defaultValue == NULL)
-            xmlVErrMemory(ctxt);
+            goto mem_error;
     }
 
+    elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem);
+    if (elemDef == NULL)
+        goto mem_error;
+
     /*
      * Validity Check:
      * Search the DTD for previous declarations of the ATTLIST
@@ -1798,48 +1811,44 @@
      * Validity Check:
      * Multiple ID per element
      */
-    elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem);
-    if (elemDef != NULL) {
-
 #ifdef LIBXML_VALID_ENABLED
-        if ((type == XML_ATTRIBUTE_ID) &&
-	    (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);
-	    if (ctxt != NULL)
-		ctxt->valid = 0;
-	}
+    if ((type == XML_ATTRIBUTE_ID) &&
+        (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);
+        if (ctxt != NULL)
+            ctxt->valid = 0;
+    }
 #endif /* LIBXML_VALID_ENABLED */
 
-	/*
-	 * Insert namespace default def first they need to be
-	 * processed first.
-	 */
-	if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
-	    ((ret->prefix != NULL &&
-	     (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
-	    ret->nexth = elemDef->attributes;
-	    elemDef->attributes = ret;
-	} else {
-	    xmlAttributePtr tmp = elemDef->attributes;
+    /*
+     * Insert namespace default def first they need to be
+     * processed first.
+     */
+    if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
+        ((ret->prefix != NULL &&
+         (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
+        ret->nexth = elemDef->attributes;
+        elemDef->attributes = ret;
+    } else {
+        xmlAttributePtr tmp = elemDef->attributes;
 
-	    while ((tmp != NULL) &&
-		   ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
-		    ((ret->prefix != NULL &&
-		     (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
-		if (tmp->nexth == NULL)
-		    break;
-		tmp = tmp->nexth;
-	    }
-	    if (tmp != NULL) {
-		ret->nexth = tmp->nexth;
-	        tmp->nexth = ret;
-	    } else {
-		ret->nexth = elemDef->attributes;
-		elemDef->attributes = ret;
-	    }
-	}
+        while ((tmp != NULL) &&
+               ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
+                ((ret->prefix != NULL &&
+                 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
+            if (tmp->nexth == NULL)
+                break;
+            tmp = tmp->nexth;
+        }
+        if (tmp != NULL) {
+            ret->nexth = tmp->nexth;
+            tmp->nexth = ret;
+        } else {
+            ret->nexth = elemDef->attributes;
+            elemDef->attributes = ret;
+        }
     }
 
     /*
@@ -1966,7 +1975,8 @@
 
     save = xmlSaveToBuffer(buf, NULL, 0);
     xmlSaveTree(save, (xmlNodePtr) attr);
-    xmlSaveClose(save);
+    if (xmlSaveFinish(save) != XML_ERR_OK)
+        xmlFree(xmlBufferDetach(buf));
 }
 
 /**
@@ -1977,9 +1987,9 @@
  * This is used with the hash scan function - just reverses arguments
  */
 static void
-xmlDumpAttributeDeclScan(void *attr, void *buf,
+xmlDumpAttributeDeclScan(void *attr, void *save,
                          const xmlChar *name ATTRIBUTE_UNUSED) {
-    xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
+    xmlSaveTree(save, attr);
 }
 
 /**
@@ -1993,9 +2003,15 @@
  */
 void
 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
+    xmlSaveCtxtPtr save;
+
     if ((buf == NULL) || (table == NULL))
         return;
-    xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
+
+    save = xmlSaveToBuffer(buf, NULL, 0);
+    xmlHashScan(table, xmlDumpAttributeDeclScan, save);
+    if (xmlSaveFinish(save) != XML_ERR_OK)
+        xmlFree(xmlBufferDetach(buf));
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
 
@@ -2202,7 +2218,8 @@
 
     save = xmlSaveToBuffer(buf, NULL, 0);
     xmlSaveNotationDecl(save, nota);
-    xmlSaveClose(save);
+    if (xmlSaveFinish(save) != XML_ERR_OK)
+        xmlFree(xmlBufferDetach(buf));
 }
 
 /**
@@ -2223,7 +2240,8 @@
 
     save = xmlSaveToBuffer(buf, NULL, 0);
     xmlSaveNotationTable(save, table);
-    xmlSaveClose(save);
+    if (xmlSaveFinish(save) != XML_ERR_OK)
+        xmlFree(xmlBufferDetach(buf));
 }
 #endif /* LIBXML_OUTPUT_ENABLED */
 
@@ -2275,40 +2293,46 @@
 	DICT_FREE(id->value)
     if (id->name != NULL)
 	DICT_FREE(id->name)
+    if (id->attr != NULL) {
+        id->attr->id = NULL;
+        id->attr->atype = 0;
+    }
+
     xmlFree(id);
 }
 
 
 /**
- * xmlAddIDSafe:
- * @doc:  pointer to the document
- * @value:  the value name
+ * xmlAddIDInternal:
  * @attr:  the attribute holding the ID
- * @id:  pointer to new xmlIdPtr (optional)
+ * @value:  the attribute (ID) value
+ * @idPtr:  pointer to resulting ID
  *
  * Register a new id declaration
  *
  * Returns 1 on success, 0 if the ID already exists, -1 if a memory
  * allocation fails.
  */
-int
-xmlAddIDSafe(xmlDocPtr doc, const xmlChar *value, xmlAttrPtr attr,
-             int streaming, xmlIDPtr *id) {
-    xmlIDPtr ret;
+static int
+xmlAddIDInternal(xmlAttrPtr attr, const xmlChar *value, xmlIDPtr *idPtr) {
+    xmlDocPtr doc;
+    xmlIDPtr id;
     xmlIDTablePtr table;
+    int ret;
 
-    if (id != NULL)
-        *id = NULL;
-
-    if (doc == NULL) {
-	return(-1);
-    }
-    if ((value == NULL) || (value[0] == 0)) {
+    if (idPtr != NULL)
+        *idPtr = NULL;
+    if ((value == NULL) || (value[0] == 0))
 	return(0);
-    }
-    if (attr == NULL) {
-	return(-1);
-    }
+    if (attr == NULL)
+	return(0);
+
+    doc = attr->doc;
+    if (doc == NULL)
+        return(0);
+
+    if (attr->id != NULL)
+        xmlRemoveID(doc, attr);
 
     /*
      * Create the ID table if needed.
@@ -2319,69 +2343,63 @@
         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;
+        id = xmlHashLookup(table, value);
+        if (id != NULL) {
+            if (id->attr != NULL) {
+                id->attr->id = NULL;
+                id->attr->atype = 0;
             }
-            ret->lineno = xmlGetLineNo(attr->parent);
-	    attr->atype = XML_ATTRIBUTE_ID;
-            return(0);
+            ret = 0;
+            goto done;
         }
     }
 
-    ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
-    if (ret == NULL)
+    id = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
+    if (id == NULL)
 	return(-1);
-    memset(ret, 0, sizeof(*ret));
+    memset(id, 0, sizeof(*id));
 
     /*
      * fill the structure.
      */
-    ret->doc = doc;
-    ret->value = xmlStrdup(value);
-    if (ret->value == NULL) {
-        xmlFreeID(ret);
+    id->doc = doc;
+    id->value = xmlStrdup(value);
+    if (id->value == NULL) {
+        xmlFreeID(id);
         return(-1);
     }
-    if (streaming) {
-	/*
-	 * Operating in streaming mode, attr is gonna disappear
-	 */
-	if (doc->dict != NULL)
-	    ret->name = xmlDictLookup(doc->dict, attr->name, -1);
-	else
-	    ret->name = xmlStrdup(attr->name);
-        if (ret->name == NULL) {
-            xmlFreeID(ret);
-            return(-1);
-        }
-	ret->attr = NULL;
-    } else {
-	ret->attr = attr;
-	ret->name = NULL;
-    }
-    ret->lineno = xmlGetLineNo(attr->parent);
 
-    if (xmlHashAddEntry(table, value, ret) < 0) {
-	xmlFreeID(ret);
+    if (xmlHashAddEntry(table, value, id) < 0) {
+	xmlFreeID(id);
 	return(-1);
     }
 
-    attr->atype = XML_ATTRIBUTE_ID;
-    if (!streaming)
-        attr->id = ret;
+    ret = 1;
+    if (idPtr != NULL)
+        *idPtr = id;
 
-    if (id != NULL)
-        *id = ret;
-    return(1);
+done:
+    id->attr = attr;
+    id->lineno = xmlGetLineNo(attr->parent);
+    attr->atype = XML_ATTRIBUTE_ID;
+    attr->id = id;
+
+    return(ret);
+}
+
+/**
+ * xmlAddIDSafe:
+ * @attr:  the attribute holding the ID
+ * @value:  the attribute (ID) value
+ *
+ * Register a new id declaration
+ *
+ * Returns 1 on success, 0 if the ID already exists, -1 if a memory
+ * allocation fails.
+ */
+int
+xmlAddIDSafe(xmlAttrPtr attr, const xmlChar *value) {
+    return(xmlAddIDInternal(attr, value, NULL));
 }
 
 /**
@@ -2401,7 +2419,10 @@
     xmlIDPtr id;
     int res;
 
-    res = xmlAddIDSafe(doc, value, attr, xmlIsStreaming(ctxt), &id);
+    if ((attr == NULL) || (doc != attr->doc))
+        return(NULL);
+
+    res = xmlAddIDInternal(attr, value, &id);
     if (res < 0) {
         xmlVErrMemory(ctxt);
     }
@@ -2452,30 +2473,39 @@
  */
 int
 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
-    if ((attr == NULL) || (attr->name == NULL)) return(0);
-    if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
-        (!strcmp((char *) attr->name, "id")) &&
-        (!strcmp((char *) attr->ns->prefix, "xml")))
-	return(1);
-    if (doc == NULL) return(0);
-    if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
-        (doc->type != XML_HTML_DOCUMENT_NODE)) {
-	return(0);
-    } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
-        if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
-	    ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
-	    ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
+    if ((attr == NULL) || (attr->name == NULL))
+        return(0);
+
+    if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
+        if (xmlStrEqual(BAD_CAST "id", attr->name))
+            return(1);
+
+        if ((elem == NULL) || (elem->type != XML_ELEMENT_NODE))
+            return(0);
+
+        if ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
+	    (xmlStrEqual(elem->name, BAD_CAST "a")))
 	    return(1);
-	return(0);
-    } else if (elem == NULL) {
-	return(0);
     } else {
 	xmlAttributePtr attrDecl = NULL;
-
 	xmlChar felem[50];
 	xmlChar *fullelemname;
         const xmlChar *aprefix;
 
+        if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
+            (!strcmp((char *) attr->name, "id")) &&
+            (!strcmp((char *) attr->ns->prefix, "xml")))
+            return(1);
+
+        if ((doc == NULL) ||
+            ((doc->intSubset == NULL) && (doc->extSubset == NULL)))
+            return(0);
+
+        if ((elem == NULL) ||
+            (elem->type != XML_ELEMENT_NODE) ||
+            (elem->name == NULL))
+            return(0);
+
 	fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
 	    xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
 	    (xmlChar *)elem->name;
@@ -2498,6 +2528,7 @@
         if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
 	    return(1);
     }
+
     return(0);
 }
 
@@ -2524,9 +2555,6 @@
     if (xmlHashRemoveEntry(table, attr->id->value, xmlFreeIDTableEntry) < 0)
         return(-1);
 
-    attr->atype = 0;
-    attr->id = NULL;
-
     return(0);
 }
 
@@ -2868,7 +2896,7 @@
 
     /*If the list is empty then remove the list entry in the hash */
     if (xmlListEmpty(ref_list))
-        xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry);
+        xmlHashRemoveEntry(table, ID, xmlFreeRefTableEntry);
     xmlFree(ID);
     return(0);
 }
@@ -2925,19 +2953,23 @@
 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
     xmlElementTablePtr table;
     xmlElementPtr cur;
-    xmlChar *uqname = NULL, *prefix = NULL;
+    const xmlChar *localname;
+    xmlChar *prefix;
 
-    if ((dtd == NULL) || (name == NULL)) return(NULL);
-    if (dtd->elements == NULL)
-	return(NULL);
+    if ((dtd == NULL) || (dtd->elements == NULL) ||
+        (name == NULL))
+        return(NULL);
+
     table = (xmlElementTablePtr) dtd->elements;
+    if (table == NULL)
+	return(NULL);
 
-    uqname = xmlSplitQName2(name, &prefix);
-    if (uqname != NULL)
-        name = uqname;
-    cur = xmlHashLookup2(table, name, prefix);
-    if (prefix != NULL) xmlFree(prefix);
-    if (uqname != NULL) xmlFree(uqname);
+    localname = xmlSplitQName4(name, &prefix);
+    if (localname == NULL)
+        return(NULL);
+    cur = xmlHashLookup2(table, localname, prefix);
+    if (prefix != NULL)
+        xmlFree(prefix);
     return(cur);
 }
 
@@ -2986,6 +3018,7 @@
             goto mem_error;
 	memset(cur, 0, sizeof(xmlElement));
 	cur->type = XML_ELEMENT_DECL;
+        cur->doc = dtd->doc;
 
 	/*
 	 * fill the structure.
@@ -3051,23 +3084,23 @@
 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
     xmlAttributeTablePtr table;
     xmlAttributePtr cur;
-    xmlChar *uqname = NULL, *prefix = NULL;
+    const xmlChar *localname;
+    xmlChar *prefix = NULL;
 
-    if (dtd == NULL) return(NULL);
-    if (dtd->attributes == NULL) return(NULL);
+    if ((dtd == NULL) || (dtd->attributes == NULL) ||
+        (elem == NULL) || (name == NULL))
+        return(NULL);
 
     table = (xmlAttributeTablePtr) dtd->attributes;
     if (table == NULL)
 	return(NULL);
 
-    uqname = xmlSplitQName2(name, &prefix);
-
-    if (uqname != NULL) {
-	cur = xmlHashLookup3(table, uqname, prefix, elem);
-	if (prefix != NULL) xmlFree(prefix);
-	if (uqname != NULL) xmlFree(uqname);
-    } else
-	cur = xmlHashLookup3(table, name, NULL, elem);
+    localname = xmlSplitQName4(name, &prefix);
+    if (localname == NULL)
+        return(NULL);
+    cur = xmlHashLookup3(table, localname, prefix, elem);
+    if (prefix != NULL)
+        xmlFree(prefix);
     return(cur);
 }
 
@@ -3124,6 +3157,8 @@
  * @doc:  the document
  * @notationName:  the notation name to check
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Validate that the given name match a notation declaration.
  * - [ VC: Notation Declared ]
  *
@@ -3220,41 +3255,6 @@
     *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) {
@@ -3574,6 +3574,8 @@
  * @doc:  a document instance
  * @nota:  a notation definition
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Try to validate a single notation definition
  * basically it does the following checks as described by the
  * XML-1.0 recommendation:
@@ -3630,6 +3632,8 @@
  * @type:  an attribute type
  * @value:  an attribute value
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Validate that the given attribute value match  the proper production
  *
  * [ VC: ID ]
@@ -3786,6 +3790,8 @@
  * @value:  the attribute value
  * @ctxt:  the validation context or NULL
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Does the validation related extra step of the normalization of attribute
  * values:
  *
@@ -3882,6 +3888,8 @@
  * @name:  the attribute name
  * @value:  the attribute value
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Does the validation related extra step of the normalization of attribute
  * values:
  *
@@ -3945,6 +3953,8 @@
  * @doc:  a document instance
  * @attr:  an attribute definition
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Try to validate a single attribute definition
  * basically it does the following checks as described by the
  * XML-1.0 recommendation:
@@ -3990,11 +4000,21 @@
 
     /* One ID per Element Type */
     if (attr->atype == XML_ATTRIBUTE_ID) {
+        xmlElementPtr elem = NULL;
+        const xmlChar *elemLocalName;
+        xmlChar *elemPrefix;
         int nbId;
 
+        elemLocalName = xmlSplitQName4(attr->elem, &elemPrefix);
+        if (elemLocalName == NULL) {
+            xmlVErrMemory(ctxt);
+            return(0);
+        }
+
 	/* the trick is that we parse DtD as their own internal subset */
-        xmlElementPtr elem = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset,
-	                                              attr->elem);
+        if (doc->intSubset != NULL)
+            elem = xmlHashLookup2(doc->intSubset->elements,
+                                  elemLocalName, elemPrefix);
 	if (elem != NULL) {
 	    nbId = xmlScanIDAttributeDecl(ctxt, elem, 0);
 	} else {
@@ -4016,9 +4036,11 @@
 	    xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
        "Element %s has %d ID attribute defined in the internal subset : %s\n",
 		   attr->elem, nbId, attr->name);
+            ret = 0;
 	} else if (doc->extSubset != NULL) {
 	    int extId = 0;
-	    elem = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, attr->elem);
+	    elem = xmlHashLookup2(doc->extSubset->elements,
+                                  elemLocalName, elemPrefix);
 	    if (elem != NULL) {
 		extId = xmlScanIDAttributeDecl(ctxt, elem, 0);
 	    }
@@ -4026,12 +4048,16 @@
 		xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
        "Element %s has %d ID attribute defined in the external subset : %s\n",
 		       attr->elem, extId, attr->name);
+                ret = 0;
 	    } else if (extId + nbId > 1) {
 		xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
 "Element %s has ID attributes defined in the internal and external subset : %s\n",
 		       attr->elem, attr->name, NULL);
+                ret = 0;
 	    }
 	}
+
+        xmlFree(elemPrefix);
     }
 
     /* Validity Constraint: Enumeration */
@@ -4058,6 +4084,8 @@
  * @doc:  a document instance
  * @elem:  an element definition
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Try to validate a single element definition
  * basically it does the following checks as described by the
  * XML-1.0 recommendation:
@@ -4073,6 +4101,8 @@
                        xmlElementPtr elem) {
     int ret = 1;
     xmlElementPtr tst;
+    const xmlChar *localName;
+    xmlChar *prefix;
 
     CHECK_DTD;
 
@@ -4136,32 +4166,47 @@
 	}
     }
 
+    localName = xmlSplitQName4(elem->name, &prefix);
+    if (localName == NULL) {
+        xmlVErrMemory(ctxt);
+        return(0);
+    }
+
     /* VC: Unique Element Type Declaration */
-    tst = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset, elem->name);
-    if ((tst != NULL ) && (tst != elem) &&
-	((tst->prefix == elem->prefix) ||
-	 (xmlStrEqual(tst->prefix, elem->prefix))) &&
-	(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
-	xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
-	                "Redefinition of element %s\n",
-		       elem->name, NULL, NULL);
-	ret = 0;
+    if (doc->intSubset != NULL) {
+        tst = xmlHashLookup2(doc->intSubset->elements, localName, prefix);
+
+        if ((tst != NULL ) && (tst != elem) &&
+            ((tst->prefix == elem->prefix) ||
+             (xmlStrEqual(tst->prefix, elem->prefix))) &&
+            (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
+            xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
+                            "Redefinition of element %s\n",
+                           elem->name, NULL, NULL);
+            ret = 0;
+        }
     }
-    tst = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, elem->name);
-    if ((tst != NULL ) && (tst != elem) &&
-	((tst->prefix == elem->prefix) ||
-	 (xmlStrEqual(tst->prefix, elem->prefix))) &&
-	(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
-	xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
-	                "Redefinition of element %s\n",
-		       elem->name, NULL, NULL);
-	ret = 0;
+    if (doc->extSubset != NULL) {
+        tst = xmlHashLookup2(doc->extSubset->elements, localName, prefix);
+
+        if ((tst != NULL ) && (tst != elem) &&
+            ((tst->prefix == elem->prefix) ||
+             (xmlStrEqual(tst->prefix, elem->prefix))) &&
+            (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
+            xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
+                            "Redefinition of element %s\n",
+                           elem->name, NULL, NULL);
+            ret = 0;
+        }
     }
+
     /* One ID per Element Type
      * already done when registering the attribute
     if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
 	ret = 0;
     } */
+
+    xmlFree(prefix);
     return(ret);
 }
 
@@ -4173,6 +4218,8 @@
  * @attr:  an attribute instance
  * @value:  the attribute value (without entities processing)
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Try to validate a single attribute for an element
  * basically it does the following checks as described by the
  * XML-1.0 recommendation:
@@ -4238,6 +4285,8 @@
 	       attr->name, elem->name, NULL);
 	return(0);
     }
+    if (attr->atype == XML_ATTRIBUTE_ID)
+        xmlRemoveID(doc, attr);
     attr->atype = attrDecl->atype;
 
     val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
@@ -4340,6 +4389,8 @@
  * @ns:  an namespace declaration instance
  * @value:  the attribute value (without entities processing)
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Try to validate a single namespace declaration for an element
  * basically it does the following checks as described by the
  * XML-1.0 recommendation:
@@ -4969,7 +5020,8 @@
 			strcat(buf, " ...");
 		    return;
 		}
-	        strcat(buf, (char *) cur->name);
+                if (cur->name != NULL)
+	            strcat(buf, (char *) cur->name);
 		if (cur->next != NULL)
 		    strcat(buf, " ");
 		break;
@@ -5513,6 +5565,8 @@
  * @elem:  an element instance
  * @qname:  the qualified name as appearing in the serialization
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Push a new element start on the validation stack.
  *
  * returns 1 if no validation problem was found or 0 otherwise
@@ -5610,6 +5664,8 @@
  * @data:  some character data read
  * @len:  the length of the data
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * check the CData parsed for validation in the current stack
  *
  * returns 1 if no validation problem was found or 0 otherwise
@@ -5683,6 +5739,8 @@
  * @elem:  an element instance
  * @qname:  the qualified name as appearing in the serialization
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Pop the element end from the validation stack.
  *
  * returns 1 if no validation problem was found or 0 otherwise
@@ -5737,6 +5795,8 @@
  * @doc:  a document instance
  * @elem:  an element instance
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Try to validate a single element and it's attributes,
  * basically it does the following checks as described by the
  * XML-1.0 recommendation:
@@ -5764,61 +5824,19 @@
 
     if (elem == NULL) return(0);
     switch (elem->type) {
-        case XML_ATTRIBUTE_NODE:
-	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		   "Attribute element not expected\n", NULL, NULL ,NULL);
-	    return(0);
         case XML_TEXT_NODE:
-	    if (elem->children != NULL) {
-		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		                "Text element has children !\n",
-				NULL,NULL,NULL);
-		return(0);
-	    }
-	    if (elem->ns != NULL) {
-		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		                "Text element has namespace !\n",
-				NULL,NULL,NULL);
-		return(0);
-	    }
-	    if (elem->content == NULL) {
-		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		                "Text element has no content !\n",
-				NULL,NULL,NULL);
-		return(0);
-	    }
-	    return(1);
-        case XML_XINCLUDE_START:
-        case XML_XINCLUDE_END:
-            return(1);
         case XML_CDATA_SECTION_NODE:
         case XML_ENTITY_REF_NODE:
         case XML_PI_NODE:
         case XML_COMMENT_NODE:
+        case XML_XINCLUDE_START:
+        case XML_XINCLUDE_END:
 	    return(1);
-        case XML_ENTITY_NODE:
-	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		   "Entity element not expected\n", NULL, NULL ,NULL);
-	    return(0);
-        case XML_NOTATION_NODE:
-	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		   "Notation element not expected\n", NULL, NULL ,NULL);
-	    return(0);
-        case XML_DOCUMENT_NODE:
-        case XML_DOCUMENT_TYPE_NODE:
-        case XML_DOCUMENT_FRAG_NODE:
-	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		   "Document element not expected\n", NULL, NULL ,NULL);
-	    return(0);
-        case XML_HTML_DOCUMENT_NODE:
-	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		   "HTML Document not expected\n", NULL, NULL ,NULL);
-	    return(0);
         case XML_ELEMENT_NODE:
 	    break;
 	default:
 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
-		   "unknown element type\n", NULL, NULL ,NULL);
+		   "unexpected element type\n", NULL, NULL ,NULL);
 	    return(0);
     }
 
@@ -5876,8 +5894,10 @@
 
 			fullname = xmlBuildQName(child->name, child->ns->prefix,
 				                 fn, 50);
-			if (fullname == NULL)
+			if (fullname == NULL) {
+                            xmlVErrMemory(ctxt);
 			    return(0);
+                        }
 			cont = elemDecl->content;
 			while (cont != NULL) {
 			    if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
@@ -5941,7 +5961,8 @@
 		 */
 		child = elem->children;
 		while (child != NULL) {
-		    if (child->type == XML_TEXT_NODE) {
+		    if ((child->type == XML_TEXT_NODE) &&
+                        (child->content != NULL)) {
 			const xmlChar *content = child->content;
 
 			while (IS_BLANK_CH(*content))
@@ -5962,7 +5983,7 @@
 	    cont = elemDecl->content;
 	    tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
 	    if (tmp <= 0)
-		ret = tmp;
+		ret = 0;
 	    break;
     }
     } /* not continuous */
@@ -6104,6 +6125,8 @@
  * @ctxt:  the validation context
  * @doc:  a document instance
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Try to validate a the root element
  * basically it does the following check as described by the
  * XML-1.0 recommendation:
@@ -6197,11 +6220,13 @@
             attr = elem->properties;
             while (attr != NULL) {
                 value = xmlNodeListGetString(doc, attr->children, 0);
-                if (value == NULL)
+                if (value == NULL) {
                     xmlVErrMemory(ctxt);
-                ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
-                if (value != NULL)
+                    ret = 0;
+                } else {
+                    ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
                     xmlFree((char *)value);
+                }
                 attr= attr->next;
             }
 
@@ -6363,6 +6388,8 @@
  * @ctxt:  the validation context
  * @doc:  a document instance
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Does the final step for the document validation once all the
  * incremental validation steps have been completed
  *
@@ -6439,31 +6466,42 @@
     xmlDtdPtr oldExt, oldInt;
     xmlNodePtr root;
 
-    if (dtd == NULL) return(0);
-    if (doc == NULL) return(0);
+    if (dtd == NULL)
+        return(0);
+    if (doc == NULL)
+        return(0);
+
     oldExt = doc->extSubset;
     oldInt = doc->intSubset;
     doc->extSubset = dtd;
     doc->intSubset = NULL;
-    ret = xmlValidateRoot(ctxt, doc);
-    if (ret == 0) {
-	doc->extSubset = oldExt;
-	doc->intSubset = oldInt;
-	return(ret);
-    }
     if (doc->ids != NULL) {
-          xmlFreeIDTable(doc->ids);
-          doc->ids = NULL;
+        xmlFreeIDTable(doc->ids);
+        doc->ids = NULL;
     }
     if (doc->refs != NULL) {
-          xmlFreeRefTable(doc->refs);
-          doc->refs = NULL;
+        xmlFreeRefTable(doc->refs);
+        doc->refs = NULL;
     }
-    root = xmlDocGetRootElement(doc);
-    ret = xmlValidateElement(ctxt, doc, root);
-    ret &= xmlValidateDocumentFinal(ctxt, doc);
+
+    ret = xmlValidateRoot(ctxt, doc);
+    if (ret != 0) {
+        root = xmlDocGetRootElement(doc);
+        ret = xmlValidateElement(ctxt, doc, root);
+        ret &= xmlValidateDocumentFinal(ctxt, doc);
+    }
+
     doc->extSubset = oldExt;
     doc->intSubset = oldInt;
+    if (doc->ids != NULL) {
+        xmlFreeIDTable(doc->ids);
+        doc->ids = NULL;
+    }
+    if (doc->refs != NULL) {
+        xmlFreeRefTable(doc->refs);
+        doc->refs = NULL;
+    }
+
     return(ret);
 }
 
@@ -6530,6 +6568,9 @@
 	    }
     }
     if (cur->atype == XML_ATTRIBUTE_NOTATION) {
+        const xmlChar *elemLocalName;
+        xmlChar *elemPrefix;
+
 	doc = cur->doc;
 	if (cur->elem == NULL) {
 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
@@ -6538,14 +6579,25 @@
 	    return;
 	}
 
-	if (doc != NULL)
-	    elem = xmlCtxtGetDtdElementDesc(ctxt, doc->intSubset, cur->elem);
-	if ((elem == NULL) && (doc != NULL))
-	    elem = xmlCtxtGetDtdElementDesc(ctxt, doc->extSubset, cur->elem);
+        elemLocalName = xmlSplitQName4(cur->elem, &elemPrefix);
+        if (elemLocalName == NULL) {
+            xmlVErrMemory(ctxt);
+            return;
+        }
+
+	if ((doc != NULL) && (doc->intSubset != NULL))
+	    elem = xmlHashLookup2(doc->intSubset->elements,
+                                  elemLocalName, elemPrefix);
+	if ((elem == NULL) && (doc != NULL) && (doc->extSubset != NULL))
+	    elem = xmlHashLookup2(doc->extSubset->elements,
+                                  elemLocalName, elemPrefix);
 	if ((elem == NULL) && (cur->parent != NULL) &&
 	    (cur->parent->type == XML_DTD_NODE))
-	    elem = xmlCtxtGetDtdElementDesc(ctxt, (xmlDtdPtr) cur->parent,
-                                            cur->elem);
+	    elem = xmlHashLookup2(((xmlDtdPtr) cur->parent)->elements,
+                                  elemLocalName, elemPrefix);
+
+        xmlFree(elemPrefix);
+
 	if (elem == NULL) {
 	    xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
 		   "attribute %s: could not find decl for element %s\n",
@@ -6566,6 +6618,8 @@
  * @ctxt:  the validation context
  * @doc:  a document instance
  *
+ * DEPRECATED: Internal function, don't use.
+ *
  * Does the final step for the dtds validation once all the
  * subsets have been parsed
  *
diff --git a/src/xmlIO.c b/src/xmlIO.c
index 96c8502..56a183a 100644
--- a/src/xmlIO.c
+++ b/src/xmlIO.c
@@ -140,7 +140,7 @@
     xmlStructuredErrorFunc schannel = NULL;
     xmlGenericErrorFunc channel = NULL;
     void *data = NULL;
-    const char *fmt, *arg;
+    const char *fmt, *arg1, *arg2;
     int res;
 
     if (code == 0) {
@@ -309,18 +309,19 @@
         data = xmlGenericErrorContext;
     }
 
-    if (code == XML_IO_NETWORK_ATTEMPT) {
-        fmt = "Attempt to load network entity %s";
-        arg = extra;
+    if (extra != NULL) {
+        fmt = "%s: %s";
     } else {
         fmt = "%s";
-        arg = xmlErrString(code);
     }
 
+    arg1 = xmlErrString(code);
+    arg2 = extra;
+
     res = __xmlRaiseError(schannel, channel, data, NULL, NULL,
                           domain, code, XML_ERR_ERROR, NULL, 0,
                           extra, NULL, NULL, 0, 0,
-                          fmt, arg);
+                          fmt, arg1, arg2);
     if (res < 0) {
         xmlIOErrMemory();
         return(XML_ERR_NO_MEMORY);
@@ -1393,7 +1394,7 @@
         xmlFree(ret);
 	return(NULL);
     }
-    xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
+    xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
 
     ret->encoder = encoder;
     if (encoder != NULL) {
@@ -2451,8 +2452,10 @@
                 nbchars = ret >= 0 ? ret : 0;
 	} else {
 	    ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
-	    if (ret != 0)
+	    if (ret != 0) {
+                out->error = XML_ERR_NO_MEMORY;
 	        return(-1);
+            }
             if (out->writecallback)
 	        nbchars = xmlBufUse(out->buffer);
             else
@@ -2606,8 +2609,10 @@
 	 * not the case force a flush, but make sure we stay in the loop
 	 */
 	if (chunk < 40) {
-	    if (xmlBufGrow(out->buffer, 100) < 0)
+	    if (xmlBufGrow(out->buffer, 100) < 0) {
+                out->error = XML_ERR_NO_MEMORY;
 	        return(-1);
+            }
             oldwritten = -1;
 	    continue;
 	}
@@ -2621,11 +2626,17 @@
 	     */
 	    if (out->conv == NULL) {
 		out->conv = xmlBufCreate();
+                if (out->conv == NULL) {
+                    out->error = XML_ERR_NO_MEMORY;
+                    return(-1);
+                }
 	    }
 	    ret = escaping(xmlBufEnd(out->buffer) ,
 	                   &chunk, str, &cons);
-	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
-	        return(-1);
+            if (ret < 0) {
+                out->error = XML_ERR_NO_MEMORY;
+                return(-1);
+            }
             xmlBufAddLen(out->buffer, chunk);
 
 	    if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
@@ -2643,8 +2654,10 @@
                 nbchars = ret >= 0 ? ret : 0;
 	} else {
 	    ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
-	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
-	        return(-1);
+            if (ret < 0) {
+                out->error = XML_ERR_NO_MEMORY;
+                return(-1);
+            }
             xmlBufAddLen(out->buffer, chunk);
             if (out->writecallback)
 	        nbchars = xmlBufUse(out->buffer);
@@ -2676,14 +2689,17 @@
                 int errNo = (ret == -1) ? XML_IO_WRITE : -ret;
 		xmlIOErr(errNo, NULL);
 		out->error = errNo;
-		return(ret);
+		return(-1);
 	    }
             if (out->written > INT_MAX - ret)
                 out->written = INT_MAX;
             else
                 out->written += ret;
 	} else if (xmlBufAvail(out->buffer) < MINLEN) {
-	    xmlBufGrow(out->buffer, MINLEN);
+            if (xmlBufGrow(out->buffer, MINLEN) < 0) {
+                out->error = XML_ERR_NO_MEMORY;
+                return(-1);
+            }
 	}
 	written += nbchars;
     } while ((len > 0) && (oldwritten != written));
@@ -2720,6 +2736,56 @@
 }
 
 /**
+ * xmlOutputBufferWriteQuotedString:
+ * @buf:  output buffer
+ * @string:  the string to add
+ *
+ * routine which manage and grows an output buffer. This one writes
+ * a quoted or double quoted #xmlChar string, checking first if it holds
+ * quote or double-quotes internally
+ */
+void
+xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf,
+                                 const xmlChar *string) {
+    const xmlChar *cur, *base;
+
+    if ((buf == NULL) || (buf->error))
+        return;
+
+    if (xmlStrchr(string, '\"')) {
+        if (xmlStrchr(string, '\'')) {
+	    xmlOutputBufferWrite(buf, 1, "\"");
+            base = cur = string;
+            while(*cur != 0){
+                if(*cur == '"'){
+                    if (base != cur)
+                        xmlOutputBufferWrite(buf, cur - base,
+                                             (const char *) base);
+                    xmlOutputBufferWrite(buf, 6, "&quot;");
+                    cur++;
+                    base = cur;
+                }
+                else {
+                    cur++;
+                }
+            }
+            if (base != cur)
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+	    xmlOutputBufferWrite(buf, 1, "\"");
+	}
+        else{
+	    xmlOutputBufferWrite(buf, 1, "'");
+            xmlOutputBufferWriteString(buf, (const char *) string);
+	    xmlOutputBufferWrite(buf, 1, "'");
+        }
+    } else {
+        xmlOutputBufferWrite(buf, 1, "\"");
+        xmlOutputBufferWriteString(buf, (const char *) string);
+        xmlOutputBufferWrite(buf, 1, "\"");
+    }
+}
+
+/**
  * xmlOutputBufferFlush:
  * @out:  a buffered output
  *
diff --git a/src/xmlreader.c b/src/xmlreader.c
index 4aaf6fc..eecca84 100644
--- a/src/xmlreader.c
+++ b/src/xmlreader.c
@@ -222,7 +222,19 @@
     if (cur->children != NULL)
         xmlTextReaderFreeNodeList(reader, cur->children);
 
-    DICT_FREE(cur->name);
+    if (cur->id != NULL) {
+        /*
+         * Operating in streaming mode, attr is gonna disappear
+         */
+        cur->id->attr = NULL;
+        if (cur->id->name != NULL)
+            DICT_FREE(cur->id->name);
+        cur->id->name = cur->name;
+        cur->name = NULL;
+    } else {
+        DICT_FREE(cur->name);
+    }
+
     if ((reader != NULL) && (reader->ctxt != NULL) &&
         (reader->ctxt->freeAttrsNr < MAX_FREE_NODES)) {
         cur->next = reader->ctxt->freeAttrs;
@@ -2866,20 +2878,17 @@
  */
 const xmlChar *
 xmlTextReaderConstEncoding(xmlTextReaderPtr reader) {
-    xmlDocPtr doc = NULL;
-    if (reader == NULL)
-	return(NULL);
-    if (reader->doc != NULL)
-        doc = reader->doc;
-    else if (reader->ctxt != NULL)
-	doc = reader->ctxt->myDoc;
-    if (doc == NULL)
-	return(NULL);
+    const xmlChar *encoding = NULL;
 
-    if (doc->encoding == NULL)
-	return(NULL);
-    else
-      return(CONSTSTR(doc->encoding));
+    if (reader == NULL)
+        return(NULL);
+
+    if (reader->ctxt != NULL)
+        encoding = xmlGetActualEncoding(reader->ctxt);
+    else if (reader->doc != NULL)
+        encoding = reader->doc->encoding;
+
+    return(CONSTSTR(encoding));
 }
 
 
diff --git a/src/xmlsave.c b/src/xmlsave.c
index 636432a..beb52c9 100644
--- a/src/xmlsave.c
+++ b/src/xmlsave.c
@@ -9,6 +9,7 @@
 #define IN_LIBXML
 #include "libxml.h"
 
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <libxml/xmlmemory.h>
@@ -23,6 +24,7 @@
 #include "private/buf.h"
 #include "private/enc.h"
 #include "private/error.h"
+#include "private/io.h"
 #include "private/save.h"
 
 #ifdef LIBXML_OUTPUT_ENABLED
@@ -245,10 +247,6 @@
             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 {
@@ -395,14 +393,13 @@
     while (children != NULL) {
         switch (children->type) {
             case XML_TEXT_NODE:
-	        xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc,
-		                              attr, children->content);
+	        xmlBufAttrSerializeTxtContent(buf, attr->doc,
+		                              children->content);
 		break;
             case XML_ENTITY_REF_NODE:
-                xmlBufAdd(buf->buffer, BAD_CAST "&", 1);
-                xmlBufAdd(buf->buffer, children->name,
-                             xmlStrlen(children->name));
-                xmlBufAdd(buf->buffer, BAD_CAST ";", 1);
+                xmlOutputBufferWrite(buf, 1, "&");
+                xmlOutputBufferWriteString(buf, (const char *) children->name);
+                xmlOutputBufferWrite(buf, 1, ";");
                 break;
             default:
                 /* should not happen unless we have a badly built tree */
@@ -426,14 +423,14 @@
 
     if (nota->PublicID != NULL) {
 	xmlOutputBufferWrite(buf, 8, " PUBLIC ");
-	xmlBufWriteQuotedString(buf->buffer, nota->PublicID);
+	xmlOutputBufferWriteQuotedString(buf, nota->PublicID);
 	if (nota->SystemID != NULL) {
 	    xmlOutputBufferWrite(buf, 1, " ");
-	    xmlBufWriteQuotedString(buf->buffer, nota->SystemID);
+	    xmlOutputBufferWriteQuotedString(buf, nota->SystemID);
 	}
     } else {
 	xmlOutputBufferWrite(buf, 8, " SYSTEM ");
-	xmlBufWriteQuotedString(buf->buffer, nota->SystemID);
+	xmlOutputBufferWriteQuotedString(buf, nota->SystemID);
     }
 
     xmlOutputBufferWrite(buf, 3, " >\n");
@@ -693,7 +690,7 @@
 
     if (attr->defaultValue != NULL) {
 	xmlOutputBufferWrite(buf, 1, " ");
-	xmlBufWriteQuotedString(buf->buffer, attr->defaultValue);
+	xmlOutputBufferWriteQuotedString(buf, attr->defaultValue);
     }
 
     xmlOutputBufferWrite(buf, 2, ">\n");
@@ -735,7 +732,7 @@
 	    xmlOutputBufferWrite(buf, cur - base, base);
 	xmlOutputBufferWrite(buf, 1, "\"");
     } else {
-        xmlBufWriteQuotedString(buf->buffer, content);
+        xmlOutputBufferWriteQuotedString(buf, content);
     }
 }
 
@@ -761,12 +758,12 @@
         (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) {
         if (ent->ExternalID != NULL) {
              xmlOutputBufferWrite(buf, 7, "PUBLIC ");
-             xmlBufWriteQuotedString(buf->buffer, ent->ExternalID);
+             xmlOutputBufferWriteQuotedString(buf, ent->ExternalID);
              xmlOutputBufferWrite(buf, 1, " ");
         } else {
              xmlOutputBufferWrite(buf, 7, "SYSTEM ");
         }
-        xmlBufWriteQuotedString(buf->buffer, ent->SystemID);
+        xmlOutputBufferWriteQuotedString(buf, ent->SystemID);
     }
 
     if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
@@ -782,7 +779,7 @@
     if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) ||
         (ent->etype == XML_INTERNAL_PARAMETER_ENTITY)) {
         if (ent->orig != NULL)
-            xmlBufWriteQuotedString(buf->buffer, ent->orig);
+            xmlOutputBufferWriteQuotedString(buf, ent->orig);
         else
             xmlBufDumpEntityContent(buf, ent->content);
     }
@@ -891,7 +888,7 @@
 	} else
 	    xmlOutputBufferWrite(buf, 5, "xmlns");
 	xmlOutputBufferWrite(buf, 1, "=");
-	xmlBufWriteQuotedString(buf->buffer, cur->href);
+	xmlOutputBufferWriteQuotedString(buf, cur->href);
     }
 }
 
@@ -961,12 +958,12 @@
     xmlOutputBufferWriteString(buf, (const char *)dtd->name);
     if (dtd->ExternalID != NULL) {
 	xmlOutputBufferWrite(buf, 8, " PUBLIC ");
-	xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID);
+	xmlOutputBufferWriteQuotedString(buf, dtd->ExternalID);
 	xmlOutputBufferWrite(buf, 1, " ");
-	xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
+	xmlOutputBufferWriteQuotedString(buf, dtd->SystemID);
     }  else if (dtd->SystemID != NULL) {
 	xmlOutputBufferWrite(buf, 8, " SYSTEM ");
-	xmlBufWriteQuotedString(buf->buffer, dtd->SystemID);
+	xmlOutputBufferWriteQuotedString(buf, dtd->SystemID);
     }
     if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
         (dtd->attributes == NULL) && (dtd->notations == NULL) &&
@@ -1460,12 +1457,12 @@
 	if ((ctxt->options & XML_SAVE_NO_DECL) == 0) {
 	    xmlOutputBufferWrite(buf, 14, "<?xml version=");
 	    if (cur->version != NULL)
-		xmlBufWriteQuotedString(buf->buffer, cur->version);
+		xmlOutputBufferWriteQuotedString(buf, cur->version);
 	    else
 		xmlOutputBufferWrite(buf, 5, "\"1.0\"");
 	    if (encoding != NULL) {
 		xmlOutputBufferWrite(buf, 10, " encoding=");
-		xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding);
+		xmlOutputBufferWriteQuotedString(buf, (xmlChar *) encoding);
 	    }
 	    switch (cur->standalone) {
 		case 0:
@@ -1545,7 +1542,7 @@
 	return(0);
     if (node->children != NULL)
 	return(0);
-    switch (node->name[0]) {
+    switch (node->name ? node->name[0] : 0) {
 	case 'a':
 	    if (xmlStrEqual(node->name, BAD_CAST "area"))
 		return(1);
@@ -2170,12 +2167,16 @@
 
 int
 xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur) {
+    if (ctxt == NULL)
+        return(-1);
     xmlBufDumpNotationDecl(ctxt->buf, cur);
     return(0);
 }
 
 int
 xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur) {
+    if (ctxt == NULL)
+        return(-1);
     xmlBufDumpNotationTable(ctxt->buf, cur);
     return(0);
 }
@@ -2281,7 +2282,7 @@
 
 /**
  * xmlBufAttrSerializeTxtContent:
- * @buf:  and xmlBufPtr output
+ * @buf:  output buffer
  * @doc:  the document
  * @attr: the attribute node
  * @string: the text content
@@ -2289,56 +2290,55 @@
  * Serialize text attribute values to an xmlBufPtr
  */
 void
-xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc,
-                              xmlAttrPtr attr ATTRIBUTE_UNUSED,
-                              const xmlChar * string)
+xmlBufAttrSerializeTxtContent(xmlOutputBufferPtr buf, xmlDocPtr doc,
+                              const xmlChar *string)
 {
-    xmlChar *base, *cur;
+    const xmlChar *base, *cur;
 
     if (string == NULL)
         return;
-    base = cur = (xmlChar *) string;
+    base = cur = string;
     while (*cur != 0) {
         if (*cur == '\n') {
             if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
-            xmlBufAdd(buf, BAD_CAST "&#10;", 5);
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+            xmlOutputBufferWrite(buf, 5, "&#10;");
             cur++;
             base = cur;
         } else if (*cur == '\r') {
             if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
-            xmlBufAdd(buf, BAD_CAST "&#13;", 5);
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+            xmlOutputBufferWrite(buf, 5, "&#13;");
             cur++;
             base = cur;
         } else if (*cur == '\t') {
             if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
-            xmlBufAdd(buf, BAD_CAST "&#9;", 4);
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+            xmlOutputBufferWrite(buf, 4, "&#9;");
             cur++;
             base = cur;
         } else if (*cur == '"') {
             if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
-            xmlBufAdd(buf, BAD_CAST "&quot;", 6);
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+            xmlOutputBufferWrite(buf, 6, "&quot;");
             cur++;
             base = cur;
         } else if (*cur == '<') {
             if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
-            xmlBufAdd(buf, BAD_CAST "&lt;", 4);
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+            xmlOutputBufferWrite(buf, 4, "&lt;");
             cur++;
             base = cur;
         } else if (*cur == '>') {
             if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
-            xmlBufAdd(buf, BAD_CAST "&gt;", 4);
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+            xmlOutputBufferWrite(buf, 4, "&gt;");
             cur++;
             base = cur;
         } else if (*cur == '&') {
             if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
-            xmlBufAdd(buf, BAD_CAST "&amp;", 5);
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
+            xmlOutputBufferWrite(buf, 5, "&amp;");
             cur++;
             base = cur;
         } else if ((*cur >= 0x80) && (cur[1] != 0) &&
@@ -2350,14 +2350,10 @@
             int val = 0, l = 4;
 
             if (base != cur)
-                xmlBufAdd(buf, base, cur - base);
+                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
 
             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++;
             } else {
@@ -2371,14 +2367,14 @@
              * as a char ref
              */
 	    xmlSerializeHexCharRef(tmp, val);
-            xmlBufAdd(buf, (xmlChar *) tmp, -1);
+            xmlOutputBufferWriteString(buf, (const char *) tmp);
             base = cur;
         } else {
             cur++;
         }
     }
     if (base != cur)
-        xmlBufAdd(buf, base, cur - base);
+        xmlOutputBufferWrite(buf, cur - base, (const char *) base);
 }
 
 /**
@@ -2392,17 +2388,18 @@
  */
 void
 xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc,
-                           xmlAttrPtr attr, const xmlChar * string)
+                           xmlAttrPtr attr ATTRIBUTE_UNUSED,
+                           const xmlChar *string)
 {
-    xmlBufPtr buffer;
+    xmlOutputBufferPtr out;
 
     if ((buf == NULL) || (string == NULL))
         return;
-    buffer = xmlBufFromBuffer(buf);
-    if (buffer == NULL)
-        return;
-    xmlBufAttrSerializeTxtContent(buffer, doc, attr, string);
-    xmlBufBackToBuffer(buffer);
+    out = xmlOutputBufferCreateBuffer(buf, NULL);
+    xmlBufAttrSerializeTxtContent(out, doc, string);
+    if ((out == NULL) || (out->error))
+        xmlFree(xmlBufferDetach(buf));
+    xmlOutputBufferClose(out);
 }
 
 /**
@@ -2430,6 +2427,10 @@
 
     if ((buf == NULL) || (cur == NULL))
         return(-1);
+    if (level < 0)
+        level = 0;
+    else if (level > 100)
+        level = 100;
     buffer = xmlBufFromBuffer(buf);
     if (buffer == NULL)
         return(-1);
@@ -2461,22 +2462,22 @@
             int format)
 {
     size_t use;
-    int ret;
+    size_t ret;
     xmlOutputBufferPtr outbuf;
     int oldalloc;
 
     xmlInitParser();
 
     if (cur == NULL) {
-        return (-1);
+        return ((size_t) -1);
     }
     if (buf == NULL) {
-        return (-1);
+        return ((size_t) -1);
     }
     outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
     if (outbuf == NULL) {
         xmlSaveErrMemory(NULL);
-        return (-1);
+        return ((size_t) -1);
     }
     memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
     outbuf->buffer = buf;
@@ -2491,8 +2492,11 @@
     xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
     xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL);
     xmlBufSetAllocationScheme(buf, oldalloc);
+    if (outbuf->error)
+        ret = (size_t) -1;
+    else
+        ret = xmlBufUse(buf) - use;
     xmlFree(outbuf);
-    ret = xmlBufUse(buf) - use;
     return (ret);
 }
 
@@ -2562,6 +2566,11 @@
 
     if ((buf == NULL) || (cur == NULL)) return;
 
+    if (level < 0)
+        level = 0;
+    else if (level > 100)
+        level = 100;
+
     if (encoding == NULL)
         encoding = "UTF-8";
 
@@ -2611,8 +2620,6 @@
     int                         dummy = 0;
     xmlOutputBufferPtr          out_buff = NULL;
     xmlCharEncodingHandlerPtr   conv_hdlr = NULL;
-    xmlChar *content;
-    int len;
 
     if (doc_txt_len == NULL) {
         doc_txt_len = &dummy;   /*  Continue, caller just won't get length */
@@ -2664,29 +2671,18 @@
     ctxt.options |= XML_SAVE_AS_XML;
     xmlDocContentDumpOutput(&ctxt, out_doc);
     xmlOutputBufferFlush(out_buff);
-    if (out_buff->conv != NULL) {
-        if (xmlBufContent(out_buff->buffer) == NULL)
-            goto error;
-        content = xmlBufContent(out_buff->conv);
-        len = xmlBufUse(out_buff->conv);
-    } else {
-        content = xmlBufContent(out_buff->buffer);
-        len = xmlBufUse(out_buff->buffer);
+
+    if (!out_buff->error) {
+        if (out_buff->conv != NULL) {
+            *doc_txt_len = xmlBufUse(out_buff->conv);
+            *doc_txt_ptr = xmlBufDetach(out_buff->conv);
+        } else {
+            *doc_txt_len = xmlBufUse(out_buff->buffer);
+            *doc_txt_ptr = xmlBufDetach(out_buff->buffer);
+        }
     }
-    if (content == NULL)
-        goto error;
-    *doc_txt_ptr = xmlStrndup(content, len);
-    if (*doc_txt_ptr == NULL)
-        goto error;
-    *doc_txt_len = len;
-    xmlOutputBufferClose(out_buff);
 
-    return;
-
-error:
-    xmlSaveErrMemory(NULL);
     xmlOutputBufferClose(out_buff);
-    return;
 }
 
 /**
diff --git a/src/xmlstring.c b/src/xmlstring.c
index e30c084..8b08802 100644
--- a/src/xmlstring.c
+++ b/src/xmlstring.c
@@ -499,10 +499,10 @@
         if (len < 0)
             return(NULL);
     }
-    if ((str2 == NULL) || (len == 0))
-        return(xmlStrdup(str1));
     if (str1 == NULL)
         return(xmlStrndup(str2, len));
+    if ((str2 == NULL) || (len == 0))
+        return(xmlStrdup(str1));
 
     size = xmlStrlen(str1);
     if ((size < 0) || (size > INT_MAX - len))
diff --git a/src/xmlwriter.c b/src/xmlwriter.c
index a63a69f..f648dc0 100644
--- a/src/xmlwriter.c
+++ b/src/xmlwriter.c
@@ -1496,8 +1496,8 @@
                     break;
                 case XML_TEXTWRITER_ATTRIBUTE:
                     buf = NULL;
-                    xmlBufAttrSerializeTxtContent(writer->out->buffer,
-                                                  writer->doc, NULL, content);
+                    xmlBufAttrSerializeTxtContent(writer->out, writer->doc,
+                                                  content);
                     break;
 		default:
 		    break;
diff --git a/src/xpath.c b/src/xpath.c
index 3bff0d5..d173186 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -4260,10 +4260,8 @@
     if (prefix == NULL)
 	return(NULL);
 
-#ifdef XML_XML_NAMESPACE
     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
 	return(XML_XML_NAMESPACE);
-#endif
 
     if (ctxt->namespaces != NULL) {
 	int i;
@@ -8318,7 +8316,7 @@
     if (ctxt->error != 0)
         goto error;
 
-    target = xmlBufCreate();
+    target = xmlBufCreateSize(64);
     if (target == NULL) {
         xmlXPathPErrMemory(ctxt);
         goto error;
@@ -13408,7 +13406,7 @@
     CAST_TO_STRING;
     str = valuePop(ctxt);
 
-    target = xmlBufCreate();
+    target = xmlBufCreateSize(64);
 
     escape[0] = '%';
     escape[3] = 0;