Time to commit 3 days of work rewriting the parser internal,
fixing bugs and migrating to SAX2 interface by default. There
is some work letf TODO, like namespace validation and attributes
normalization (this break C14N right now)
* Makefile.am: fixed the test rules
* include/libxml/SAX2.h include/libxml/parser.h
  include/libxml/parserInternals.h SAX2.c parser.c
  parserInternals.c: changing the parser, migrating to SAX2,
  adding new interface to switch back to SAX1 or initialize a
  SAX block for v1 or v2. Most of the namespace work is done
  below SAX, as well as attribute defaulting
* globals.c: changed initialization of the default SAX handlers
* hash.c tree.c include/libxml/hash.h: added QName specific handling
* xmlIO.c: small fix
* xmllint.c testSAX.c: provide a --sax1 switch to test the old
  version code path
* result/p3p result/p3p.sax result/noent/p3p test/p3p: the new code
  pointed out a typo in a very old test namespace
Daniel
diff --git a/tree.c b/tree.c
index ad99092..a68beb9 100644
--- a/tree.c
+++ b/tree.c
@@ -1078,15 +1078,18 @@
     xmlNodePtr ret = NULL, last = NULL;
     xmlNodePtr node;
     xmlChar *val;
-    const xmlChar *cur = value;
+    const xmlChar *cur = value, *end = cur + len;
     const xmlChar *q;
     xmlEntityPtr ent;
 
     if (value == NULL) return(NULL);
 
     q = cur;
-    while ((*cur != 0) && (cur - value < len)) {
-	if (*cur == '&') {
+    while ((cur < end) && (*cur != 0)) {
+	if (cur[0] == '&') {
+	    int charval = 0;
+	    xmlChar tmp;
+
 	    /*
 	     * Save the current text.
 	     */
@@ -1105,69 +1108,142 @@
 		    }
 		}
 	    }
-	    /*
-	     * Read the entity string
-	     */
-	    cur++;
 	    q = cur;
-	    while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
-	    if ((*cur == 0) || (cur - value >= len)) {
-#ifdef DEBUG_TREE
-	        xmlGenericError(xmlGenericErrorContext,
-		    "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
-#endif
-	        return(ret);
-	    }
-            if (cur != q) {
-		/*
-		 * Predefined entities don't generate nodes
-		 */
-		val = xmlStrndup(q, cur - q);
-		ent = xmlGetDocEntity(doc, val);
-		if ((ent != NULL) &&
-		    (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
-		    if (last == NULL) {
-		        node = xmlNewDocText(doc, ent->content);
-			last = ret = node;
-		    } else
-		        xmlNodeAddContent(last, ent->content);
-		        
-		} else {
-		    /*
-		     * Create a new REFERENCE_REF node
-		     */
-		    node = xmlNewReference(doc, val);
-		    if (node == NULL) {
-			if (val != NULL) xmlFree(val);
-		        return(ret);
-		    }
-			else if ((ent != NULL) && (ent->children == NULL)) {
-				xmlNodePtr tmp;
-
-				ent->children =
-					xmlStringGetNodeList(doc, (const xmlChar*)node->content);
-				tmp = ent->children;
-				while (tmp) {
-					tmp->parent = (xmlNodePtr)ent;
-					tmp = tmp->next;
-				}
-			}
-		    if (last == NULL)
-			last = ret = node;
+	    if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) {
+		cur += 3;
+		if (cur < end)
+		    tmp = *cur;
+		else
+		    tmp = 0;
+		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 {
-			last->next = node;
-			node->prev = last;
-			last = node;
+			xmlGenericError(xmlGenericErrorContext,
+		    "xmlStringGetNodeList: invalid hexadecimal charvalue\n");
+			charval = 0;
+			break;
+		    }
+		    cur++;
+		    if (cur < end)
+			tmp = *cur;
+		    else
+			tmp = 0;
+		}
+		if (tmp == ';')
+		    cur++;
+		q = cur;
+	    } else if ((cur + 1 < end) && (cur[1] == '#')) {
+		cur += 2;
+		if (cur < end)
+		    tmp = *cur;
+		else
+		    tmp = 0;
+		while (tmp != ';') { /* Non input consuming loops */
+		    if ((tmp >= '0') && (tmp <= '9')) 
+			charval = charval * 10 + (tmp - '0');
+		    else {
+			xmlGenericError(xmlGenericErrorContext,
+		    "xmlStringGetNodeList: invalid decimal charvalue\n");
+			charval = 0;
+			break;
+		    }
+		    cur++;
+		    if (cur < end)
+			tmp = *cur;
+		    else
+			tmp = 0;
+		}
+		if (tmp == ';')
+		    cur++;
+		q = cur;
+	    } else {
+		/*
+		 * Read the entity string
+		 */
+		cur++;
+		q = cur;
+		while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++;
+		if ((cur >= end) || (*cur == 0)) {
+#ifdef DEBUG_TREE
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlStringGetNodeList: unterminated entity %30s\n", q);
+#endif
+		    return(ret);
+		}
+		if (cur != q) {
+		    /*
+		     * Predefined entities don't generate nodes
+		     */
+		    val = xmlStrndup(q, cur - q);
+		    ent = xmlGetDocEntity(doc, val);
+		    if ((ent != NULL) &&
+			(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
+			if (last == NULL) {
+			    node = xmlNewDocText(doc, ent->content);
+			    last = ret = node;
+			} else if (last->type != XML_TEXT_NODE) {
+			    node = xmlNewDocText(doc, ent->content);
+			    last = xmlAddNextSibling(last, node);
+			} else
+			    xmlNodeAddContent(last, ent->content);
+			    
+		    } else {
+			/*
+			 * Create a new REFERENCE_REF node
+			 */
+			node = xmlNewReference(doc, val);
+			if (node == NULL) {
+			    if (val != NULL) xmlFree(val);
+			    return(ret);
+			}
+			else if ((ent != NULL) && (ent->children == NULL)) {
+			    xmlNodePtr temp;
+
+			    ent->children = xmlStringGetNodeList(doc,
+				    (const xmlChar*)node->content);
+			    ent->owner = 1;
+			    temp = ent->children;
+			    while (temp) {
+				temp->parent = (xmlNodePtr)ent;
+				temp = temp->next;
+			    }
+			}
+			if (last == NULL) {
+			    last = ret = node;
+			} else {
+			    last = xmlAddNextSibling(last, node);
+			}
+		    }
+		    xmlFree(val);
+		}
+		cur++;
+		q = cur;
+	    }
+	    if (charval != 0) {
+		xmlChar buf[10];
+		int l;
+
+		l = xmlCopyCharMultiByte(buf, charval);
+		buf[l] = 0;
+		node = xmlNewDocText(doc, buf);
+		if (node != NULL) {
+		    if (last == NULL) {
+			last = ret = node;
+		    } else {
+			last = xmlAddNextSibling(last, node);
 		    }
 		}
-		xmlFree(val);
+		charval = 0;
 	    }
-	    cur++;
-	    q = cur;
-	} else 
+	} else
 	    cur++;
     }
-    if (cur != q) {
+    if ((cur != q) || (ret == NULL)) {
         /*
 	 * Handle the last piece of text.
 	 */
@@ -1176,12 +1252,10 @@
 	} else {
 	    node = xmlNewDocTextLen(doc, q, cur - q);
 	    if (node == NULL) return(ret);
-	    if (last == NULL)
+	    if (last == NULL) {
 		last = ret = node;
-	    else {
-		last->next = node;
-		node->prev = last;
-		last = node;
+	    } else {
+		last = xmlAddNextSibling(last, node);
 	    }
 	}
     }