Speed, conformance testing, more parsing, general improvements, Daniel.
diff --git a/ChangeLog b/ChangeLog
index 425103a..d0e3ba7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Sun Jan 17 20:06:36 CET 1999 Daniel Veillard <Daniel.Veillard@w3.org>
+
+	* parser.c, tree.[ch] : more work toward conformance testing,
+	  added a last element to accelerate parsing of very flat structures
+	  started working on internal subset Element content declaration.
+	* valid.[ch] : first cut at adding code toward validation.
+	* previous changes had also small impact on most files, especially
+	  the conformance testing using James Clark test suite.
+
 Sun Jan 17 14:45:06 CET 1999 Daniel Veillard <Daniel.Veillard@w3.org>
 
 	* test/* : updated the examples, most of them were not well
diff --git a/Makefile.am b/Makefile.am
index df550e8..87a2bae 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,7 +16,8 @@
 		error.h \
 		parser.c \
 		debugXML.c \
-		tree.c
+		tree.c \
+		valid.c
 
 xmlincdir = $(includedir)/gnome-xml
 xmlinc_HEADERS = \
@@ -24,7 +25,8 @@
 		encoding.h \
 		parser.h \
 		debugXML.h \
-		tree.h
+		tree.h \
+		valid.h
 
 DEPS = $(top_builddir)/libxml.la
 LDADDS = $(top_builddir)/libxml.la @Z_LIBS@
diff --git a/SAX.c b/SAX.c
index 9b7e504..46afbb9 100644
--- a/SAX.c
+++ b/SAX.c
@@ -1,6 +1,8 @@
 /*
  * SAX.c : Default SAX handler to build a tree.
  *
+ * See Copyright for the status of this software.
+ *
  * Daniel Veillard <Daniel.Veillard@w3.org>
  */
 
diff --git a/debugXML.c b/debugXML.c
index bb913fd..5abec63 100644
--- a/debugXML.c
+++ b/debugXML.c
@@ -2,6 +2,8 @@
  * debugXML.c : This is a set of routines used for debugging the tree
  *              produced by the XML parser.
  *
+ * See Copyright for the status of this software.
+ *
  * Daniel Veillard <Daniel.Veillard@w3.org>
  */
 
diff --git a/encoding.c b/encoding.c
index ce86fff..295ca39 100644
--- a/encoding.c
+++ b/encoding.c
@@ -16,8 +16,6 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
- *
  * Daniel.Veillard@w3.org
  */
 
diff --git a/encoding.h b/encoding.h
index 72348c3..b5a11f9 100644
--- a/encoding.h
+++ b/encoding.h
@@ -17,8 +17,6 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
- *
  * Daniel.Veillard@w3.org
  */
 
diff --git a/entities.c b/entities.c
index 30506cb..ef6aa79 100644
--- a/entities.c
+++ b/entities.c
@@ -3,7 +3,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #include <stdio.h>
@@ -186,14 +186,15 @@
               const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
     xmlEntitiesTablePtr table;
 
-    if (doc->dtd == NULL) {
-        fprintf(stderr, "xmlAddDtdEntity: document without Dtd !\n");
+    if (doc->extSubset == NULL) {
+        fprintf(stderr,
+	        "xmlAddDtdEntity: document without external subset !\n");
 	return;
     }
-    table = (xmlEntitiesTablePtr) doc->dtd->entities;
+    table = (xmlEntitiesTablePtr) doc->extSubset->entities;
     if (table == NULL) {
         table = xmlCreateEntitiesTable();
-	doc->dtd->entities = table;
+	doc->extSubset->entities = table;
     }
     xmlAddEntity(table, name, type, ExternalID, SystemID, content);
 }
@@ -214,12 +215,22 @@
               const CHAR *ExternalID, const CHAR *SystemID, CHAR *content) {
     xmlEntitiesTablePtr table;
 
-    table = (xmlEntitiesTablePtr) doc->entities;
+    if (doc == NULL) {
+        fprintf(stderr,
+	        "xmlAddDocEntity: document is NULL !\n");
+	return;
+    }
+    if (doc->intSubset == NULL) {
+        fprintf(stderr,
+	        "xmlAddDtdEntity: document without internal subset !\n");
+	return;
+    }
+    table = (xmlEntitiesTablePtr) doc->intSubset->entities;
     if (table == NULL) {
         table = xmlCreateEntitiesTable();
-	doc->entities = table;
+	doc->intSubset->entities = table;
     }
-    xmlAddEntity(doc->entities, name, type, ExternalID, SystemID, content);
+    xmlAddEntity(table, name, type, ExternalID, SystemID, content);
 }
 
 /**
@@ -238,8 +249,8 @@
     xmlEntityPtr cur;
     xmlEntitiesTablePtr table;
 
-    if ((doc->dtd != NULL) && (doc->dtd->entities != NULL)) {
-	table = (xmlEntitiesTablePtr) doc->dtd->entities;
+    if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
+	table = (xmlEntitiesTablePtr) doc->extSubset->entities;
 	for (i = 0;i < table->nb_entities;i++) {
 	    cur = &table->table[i];
 	    if (!xmlStrcmp(cur->name, name)) return(cur);
@@ -265,8 +276,8 @@
     xmlEntityPtr cur;
     xmlEntitiesTablePtr table;
 
-    if (doc->entities != NULL) {
-	table = (xmlEntitiesTablePtr) doc->entities;
+    if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
+	table = (xmlEntitiesTablePtr) doc->intSubset->entities;
 	for (i = 0;i < table->nb_entities;i++) {
 	    cur = &table->table[i];
 	    if (!xmlStrcmp(cur->name, name)) return(cur);
diff --git a/entities.h b/entities.h
index 0830101..86c425f 100644
--- a/entities.h
+++ b/entities.h
@@ -3,7 +3,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #ifndef __XML_ENTITIES_H__
diff --git a/error.c b/error.c
index a67bdbd..eb93d96 100644
--- a/error.c
+++ b/error.c
@@ -1,6 +1,8 @@
 /*
  * error.c: module displaying/handling XML parser errors
  *
+ * See Copyright for the status of this software.
+ *
  * Daniel Veillard <Daniel.Veillard@w3.org>
  */
 
diff --git a/include/libxml/encoding.h b/include/libxml/encoding.h
index 72348c3..b5a11f9 100644
--- a/include/libxml/encoding.h
+++ b/include/libxml/encoding.h
@@ -17,8 +17,6 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
- *
  * Daniel.Veillard@w3.org
  */
 
diff --git a/include/libxml/entities.h b/include/libxml/entities.h
index 0830101..86c425f 100644
--- a/include/libxml/entities.h
+++ b/include/libxml/entities.h
@@ -3,7 +3,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #ifndef __XML_ENTITIES_H__
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index 4cd2ead..a06d481 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -3,7 +3,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #ifndef __XML_PARSER_H__
@@ -46,6 +46,7 @@
 typedef struct xmlParserCtxt {
     struct xmlSAXHandler *sax;        /* The SAX handler */
     xmlDocPtr doc;                    /* the document being built */
+    int            wellFormed;        /* is the document well formed */
 
     /* Input stream stack */
     xmlParserInputPtr  input;         /* Current input stream */
@@ -131,15 +132,8 @@
 #include "entities.h"
 
 /*
- * Interfaces
+ * CHAR handling
  */
-extern int xmlParseDocument(xmlParserCtxtPtr ctxt);
-extern xmlDocPtr xmlParseDoc(CHAR *cur);
-extern xmlDocPtr xmlParseMemory(char *buffer, int size);
-extern xmlDocPtr xmlParseFile(const char *filename);
-extern xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur);
-extern xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size);
-extern xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename);
 extern CHAR *xmlStrdup(const CHAR *input);
 extern CHAR *xmlStrndup(const CHAR *input, int n);
 extern CHAR *xmlStrchr(const CHAR *str, CHAR val);
@@ -149,6 +143,29 @@
 extern CHAR *xmlStrcat(CHAR *cur, const CHAR *add);
 extern CHAR *xmlStrncat(CHAR *cur, const CHAR *add, int len);
 
+/*
+ * Interfaces
+ */
+extern xmlDocPtr xmlParseDoc(CHAR *cur);
+extern xmlDocPtr xmlParseMemory(char *buffer, int size);
+extern xmlDocPtr xmlParseFile(const char *filename);
+
+/*
+ * Recovery mode 
+ */
+extern xmlDocPtr xmlRecoverDoc(CHAR *cur);
+extern xmlDocPtr xmlRecoverMemory(char *buffer, int size);
+extern xmlDocPtr xmlRecoverFile(const char *filename);
+
+/*
+ * Internal routines
+ */
+extern int xmlParseDocument(xmlParserCtxtPtr ctxt);
+extern xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery);
+extern xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer,
+                                   int size, int recovery);
+extern xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
+                                 int recovery);
 extern void xmlInitParserCtxt(xmlParserCtxtPtr ctx);
 extern void xmlClearParserCtxt(xmlParserCtxtPtr ctx);
 extern void xmlSetupParserForBuffer(xmlParserCtxtPtr ctx, const CHAR* buffer,
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index 3921f7e..b6e26cf 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -4,7 +4,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #ifndef __XML_TREE_H__
@@ -15,6 +15,8 @@
 extern "C" {
 #endif
 
+#include <stdio.h>
+
 /*
  * The different element types carried by an XML tree
  *
@@ -61,18 +63,51 @@
  * TODO !!!!
  */
 
+#define XML_ATTRIBUTE_NONE		1
+#define XML_ATTRIBUTE_REQUIRED		2
+#define XML_ATTRIBUTE_IMPLIED		3
+#define XML_ATTRIBUTE_FIXED		4
+
+#define XML_ATTRIBUTE_STRING		1
+#define XML_ATTRIBUTE_ID		2
+#define XML_ATTRIBUTE_IDREF		3
+#define XML_ATTRIBUTE_IDREFS		4
+#define XML_ATTRIBUTE_ENTITY		5
+#define XML_ATTRIBUTE_ENTITIES		6
+#define XML_ATTRIBUTE_NMTOKEN		7
+#define XML_ATTRIBUTE_NMTOKENS		8
+#define XML_ATTRIBUTE_ENUMERATED	9
+
 /*
  * a DTD Element definition.
  */
+#define XML_ELEMENT_CONTENT_PCDATA	1
+#define XML_ELEMENT_CONTENT_ELEMENT	2
+#define XML_ELEMENT_CONTENT_SEQ		3
+#define XML_ELEMENT_CONTENT_OR		4
+
+#define XML_ELEMENT_CONTENT_ONCE	1
+#define XML_ELEMENT_CONTENT_OPT		2
+#define XML_ELEMENT_CONTENT_MULT	3
+#define XML_ELEMENT_CONTENT_PLUS	4
+
+typedef struct xmlElementContent {
+    int            type;		/* PCDATA, ELEMENT, SEQ or OR */
+    int            ocur;		/* ONCE, OPT, MULT or PLUS */
+    const CHAR    *name;		/* Element name */
+    struct xmlElementContent *c1;	/* first child */
+    struct xmlElementContent *c2;	/* second child */
+} xmlElementContent, *xmlElementContentPtr;
+
 #define XML_ELEMENT_TYPE_EMPTY		1
 #define XML_ELEMENT_TYPE_ANY		2
 #define XML_ELEMENT_TYPE_MIXED		3
 #define XML_ELEMENT_TYPE_ELEMENT	4
 
 typedef struct xmlElement {
-    const CHAR    *name;	/* Element name */
-    int            type;	/* type (too simple, to extend ...) */
-    /* TODO !!! more needed */
+    const CHAR    *name;		/* Element name */
+    int            type;		/* The type */
+    xmlElementContentPtr content;	/* the allowed element content */
 } xmlElement, *xmlElementPtr;
 
 /*
@@ -132,6 +167,7 @@
     struct xmlNode *next;	/* next sibling link  */
     struct xmlNode *prev;	/* previous sibling link  */
     struct xmlNode *childs;	/* parent->childs link */
+    struct xmlNode *last;	/* last child link */
     struct xmlAttr *properties;	/* properties list */
     const CHAR     *name;       /* the name of the node, or the entity */
     xmlNs          *ns;         /* pointer to the associated namespace */
@@ -153,9 +189,9 @@
     const CHAR     *encoding;   /* encoding, if any */
     int             compression;/* level of zlib compression */
     int             standalone; /* standalone document (no external refs) */
-    struct xmlDtd  *dtd;	/* the document DTD if available */
+    struct xmlDtd  *intSubset;	/* the document internal subset */
+    struct xmlDtd  *extSubset;	/* the document external subset */
     struct xmlNs   *oldNs;	/* Global namespace, the old way */
-    void           *entities;   /* Hash table for general entities if any */
     struct xmlNode *root;	/* the document tree */
 } xmlDoc, *xmlDocPtr;
 
@@ -169,6 +205,8 @@
 /*
  * Creating/freeing new structures
  */
+extern xmlDtdPtr xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
+                    const CHAR *ExternalID, const CHAR *SystemID);
 extern xmlDtdPtr xmlNewDtd(xmlDocPtr doc, const CHAR *name,
                     const CHAR *ExternalID, const CHAR *SystemID);
 extern void xmlFreeDtd(xmlDtdPtr cur);
@@ -240,7 +278,7 @@
  */
 extern xmlAttrPtr xmlSetProp(xmlNodePtr node, const CHAR *name,
                              const CHAR *value);
-extern const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name);
+extern CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name);
 extern xmlNodePtr xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value);
 extern xmlNodePtr xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value,
                                           int len);
diff --git a/include/libxml/valid.h b/include/libxml/valid.h
new file mode 100644
index 0000000..d6765ff
--- /dev/null
+++ b/include/libxml/valid.h
@@ -0,0 +1,18 @@
+/*
+ * valid.h : interface to the DTD handling and the validity checking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+
+#ifndef __XML_VALID_H__
+#define __XML_VALID_H__
+#include "tree.h"
+
+extern xmlElementPtr xmlAddElementDecl(xmlDtdPtr dtd, char *name, int type, 
+                                       xmlElementContentPtr content);
+extern xmlElementContentPtr xmlNewElementContent(CHAR *name, int type);
+extern void xmlFreeElementContent(xmlElementContentPtr cur);
+#endif /* __XML_VALID_H__ */
diff --git a/parser.c b/parser.c
index 5464b26..a466b8b 100644
--- a/parser.c
+++ b/parser.c
@@ -3,7 +3,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #ifdef WIN32
@@ -30,6 +30,7 @@
 #include "tree.h"
 #include "parser.h"
 #include "entities.h"
+#include "valid.h"
 
 /************************************************************************
  *									*
@@ -182,6 +183,38 @@
     return(input);
 }
 
+/**
+ * xmlNewStringInputStream:
+ * @ctxt:  an XML parser context
+ * @entity:  an Entity pointer
+ *
+ * Create a new input stream based on a memory buffer.
+ * return vakues: the new input stream
+ */
+xmlParserInputPtr
+xmlNewStringInputStream(xmlParserCtxtPtr ctxt, CHAR *string) {
+    xmlParserInputPtr input;
+
+    if (string == NULL) {
+        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt,
+	      "internal: xmlNewStringInputStream string = NULL\n");
+	return(NULL);
+    }
+    input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
+    if (input == NULL) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, "malloc: couldn't allocate a new input stream\n");
+	return(NULL);
+    }
+    input->filename = NULL;
+    input->base = string;
+    input->cur = string;
+    input->line = 1;
+    input->col = 1;
+    return(input);
+}
+
 /*
  * A few macros needed to help building the parser.
  */
@@ -198,8 +231,10 @@
  * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
  */
 #define IS_CHAR(c)							\
-    (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) ||			\
-     (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
+    ((((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) ||		\
+      (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF))) &&		\
+      (((c) <= 0xD7FF) || ((c) >= 0xE000)) && ((c) >= 0) &&		\
+      ((c) <= 0x10FFFF))
 
 /*
  * [3] S ::= (#x20 | #x9 | #xD | #xA)+
@@ -579,8 +614,9 @@
  * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
  */
 #define IS_CHAR(c)							\
-    (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) || ((c) >= 0x20) ||\
-     ((c) == 0xa))
+    ((((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) ||		\
+      (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF))) &&		\
+      (((c) <= 0xD7FF) || ((c) >= 0xE000)) && ((c) <= 0x10FFFF))
 
 /*
  * [85] BaseChar ::= ... long list see REC ...
@@ -935,6 +971,7 @@
         if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "xmlHandleEntity %s: content == NULL\n",
 	               entity->name);
+	ctxt->wellFormed = 0;
         return;
     }
     len = xmlStrlen(entity->content);
@@ -1081,6 +1118,7 @@
 	if (CUR != '"') {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "String not closed \"%.50s\"\n", q);
+	    ctxt->wellFormed = 0;
         } else {
             ret = xmlStrndup(q, CUR_PTR - q);
 	    NEXT;
@@ -1092,6 +1130,7 @@
 	if (CUR != '\'') {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "String not closed \"%.50s\"\n", q);
+	    ctxt->wellFormed = 0;
         } else {
             ret = xmlStrndup(q, CUR_PTR - q);
 	    NEXT;
@@ -1184,6 +1223,7 @@
 	    if (!garbage)
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, "xmlParseNamespace found garbage\n");
+	    ctxt->wellFormed = 0;
             NEXT;
         }
     }
@@ -1321,6 +1361,7 @@
 	if (!IS_CHAR(CUR)) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Unfinished EntityValue\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    ret = xmlStrncat(ret, q, CUR_PTR - q);
 	    NEXT;
@@ -1354,6 +1395,7 @@
 	if (!IS_CHAR(CUR)) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Unfinished EntityValue\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    ret = xmlStrncat(ret, q, CUR_PTR - q);
 	    NEXT;
@@ -1361,6 +1403,7 @@
     } else {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "xmlParseEntityValue \" or ' expected\n");
+	ctxt->wellFormed = 0;
     }
     
     return(ret);
@@ -1387,6 +1430,12 @@
 
 	q = CUR_PTR;
 	while ((IS_CHAR(CUR)) && (CUR != '"')) {
+	    if (CUR == '<') {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt,
+		       "Unescaped '<' not allowed in attributes values\n");
+		ctxt->wellFormed = 0;
+	    }
 	    if (CUR == '&') {
 	        ret = xmlStrncat(ret, q, CUR_PTR - q);
 	        cur = xmlParseReference(ctxt);
@@ -1419,6 +1468,7 @@
 	if (!IS_CHAR(CUR)) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Unfinished AttValue\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    ret = xmlStrncat(ret, q, CUR_PTR - q);
 	    NEXT;
@@ -1427,6 +1477,12 @@
         NEXT;
 	q = CUR_PTR;
 	while ((IS_CHAR(CUR)) && (CUR != '\'')) {
+	    if (CUR == '<') {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt,
+		       "Unescaped '<' not allowed in attributes values\n");
+		ctxt->wellFormed = 0;
+	    }
 	    if (CUR == '&') {
 	        ret = xmlStrncat(ret, q, CUR_PTR - q);
 	        cur = xmlParseReference(ctxt);
@@ -1459,6 +1515,7 @@
 	if (!IS_CHAR(CUR)) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Unfinished AttValue\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    ret = xmlStrncat(ret, q, CUR_PTR - q);
 	    NEXT;
@@ -1466,6 +1523,7 @@
     } else {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "AttValue: \" or ' expected\n");
+	ctxt->wellFormed = 0;
     }
     
     return(ret);
@@ -1494,6 +1552,7 @@
 	if (!IS_CHAR(CUR)) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Unfinished SystemLiteral\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    ret = xmlStrndup(q, CUR_PTR - q);
 	    NEXT;
@@ -1506,6 +1565,7 @@
 	if (!IS_CHAR(CUR)) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Unfinished SystemLiteral\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    ret = xmlStrndup(q, CUR_PTR - q);
 	    NEXT;
@@ -1513,6 +1573,7 @@
     } else {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "SystemLiteral \" or ' expected\n");
+	ctxt->wellFormed = 0;
     }
     
     return(ret);
@@ -1540,6 +1601,7 @@
 	if (CUR != '"') {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Unfinished PubidLiteral\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    ret = xmlStrndup(q, CUR_PTR - q);
 	    NEXT;
@@ -1552,6 +1614,7 @@
 	if (!IS_LETTER(CUR)) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Unfinished PubidLiteral\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    ret = xmlStrndup(q, CUR_PTR - q);
 	    NEXT;
@@ -1559,6 +1622,7 @@
     } else {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "SystemLiteral \" or ' expected\n");
+	ctxt->wellFormed = 0;
     }
     
     return(ret);
@@ -1583,9 +1647,17 @@
     q = CUR_PTR;
     while ((IS_CHAR(CUR)) && (CUR != '<') &&
            (CUR != '&')) {
+	if ((CUR == ']') && (NXT(1) == ']') &&
+	    (NXT(2) == '>')) {
+	    if (cdata) break;
+	    else {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt,
+		       "Sequence ']]>' not allowed in content\n");
+		ctxt->wellFormed = 0;
+	    }
+	}
         NEXT;
-	if ((cdata) && (CUR == ']') && (NXT(1) == ']') &&
-	    (NXT(2) == '>')) break;
     }
     if (q == CUR_PTR) return;
 
@@ -1621,28 +1693,52 @@
          (NXT(2) == 'S') && (NXT(3) == 'T') &&
 	 (NXT(4) == 'E') && (NXT(5) == 'M')) {
         SKIP(6);
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt,
+		    "Space required after 'SYSTEM'\n");
+	    ctxt->wellFormed = 0;
+	}
         SKIP_BLANKS;
 	URI = xmlParseSystemLiteral(ctxt);
-	if (URI == NULL)
+	if (URI == NULL) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt,
 	          "xmlParseExternalID: SYSTEM, no URI\n");
+	    ctxt->wellFormed = 0;
+        }
     } else if ((CUR == 'P') && (NXT(1) == 'U') &&
 	       (NXT(2) == 'B') && (NXT(3) == 'L') &&
 	       (NXT(4) == 'I') && (NXT(5) == 'C')) {
         SKIP(6);
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt,
+		    "Space required after 'PUBLIC'\n");
+	    ctxt->wellFormed = 0;
+	}
         SKIP_BLANKS;
 	*publicID = xmlParsePubidLiteral(ctxt);
-	if (*publicID == NULL)
+	if (*publicID == NULL) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, 
 	          "xmlParseExternalID: PUBLIC, no Public Identifier\n");
+	    ctxt->wellFormed = 0;
+	}
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt,
+		    "Space required after the Public Identifier\n");
+	    ctxt->wellFormed = 0;
+	}
         SKIP_BLANKS;
 	URI = xmlParseSystemLiteral(ctxt);
-	if (URI == NULL)
+	if (URI == NULL) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, 
 	           "xmlParseExternalID: PUBLIC, no URI\n");
+	    ctxt->wellFormed = 0;
+        }
     }
     return(URI);
 }
@@ -1682,15 +1778,18 @@
     while (IS_CHAR(CUR) &&
            ((CUR == ':') || (CUR != '>') ||
 	    (*r != '-') || (*q != '-'))) {
-	if ((*r == '-') && (*q == '-'))
+	if ((*r == '-') && (*q == '-')) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt,
 	       "Comment must not contain '--' (double-hyphen)`\n");
+	    ctxt->wellFormed = 0;
+	}
         NEXT;r++;q++;
     }
     if (!IS_CHAR(CUR)) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "Comment not terminated \n<!--%.50s\n", start);
+	ctxt->wellFormed = 0;
     } else {
         NEXT;
 	if (create) {
@@ -1782,8 +1881,9 @@
 		    NEXT;
 		if (!IS_CHAR(CUR)) {
 		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-		        ctxt->sax->error(ctxt, "xmlParsePI: PI %s never end ...\n",
-		                   target);
+		        ctxt->sax->error(ctxt,
+			  "xmlParsePI: PI %s never end ...\n", target);
+		    ctxt->wellFormed = 0;
 		} else {
 		    CHAR *data;
 
@@ -1809,6 +1909,8 @@
 	} else {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "xmlParsePI : no target name\n");
+	    ctxt->wellFormed = 0;
+
 	    /********* Should we try to complete parsing the PI ???
 	    while (IS_CHAR(CUR) &&
 		   (CUR != '?') && (CUR != '>'))
@@ -1861,6 +1963,7 @@
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt,
 	        "xmlParseAttributeListDecl: no name for Element\n");
+	    ctxt->wellFormed = 0;
 	    return;
 	}
 	SKIP_BLANKS;
@@ -1903,13 +2006,22 @@
     if ((CUR == '<') && (NXT(1) == '!') &&
         (NXT(2) == 'E') && (NXT(3) == 'N') &&
         (NXT(4) == 'T') && (NXT(5) == 'I') &&
-        (NXT(6) == 'T') && (NXT(7) == 'Y') &&
-        (IS_BLANK(NXT(8)))) {
+        (NXT(6) == 'T') && (NXT(7) == 'Y')) {
 	SKIP(8);
-        SKIP_BLANKS;
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, "Space required after '<!ENTITY'\n");
+	    ctxt->wellFormed = 0;
+	}
+	SKIP_BLANKS;
 
 	if (CUR == '%') {
 	    NEXT;
+	    if (!IS_BLANK(CUR)) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt, "Space required after '%'\n");
+		ctxt->wellFormed = 0;
+	    }
 	    SKIP_BLANKS;
 	    isParameter = 1;
 	}
@@ -1918,8 +2030,15 @@
 	if (name == NULL) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "xmlParseEntityDecl: no name\n");
+	    ctxt->wellFormed = 0;
             return;
 	}
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt,
+		     "Space required after the entity name\n");
+	    ctxt->wellFormed = 0;
+	}
         SKIP_BLANKS;
 
 	/*
@@ -1949,11 +2068,23 @@
 				NULL, NULL, value);
 	    } else {
 	        URI = xmlParseExternalID(ctxt, &literal);
+		if ((CUR != '>') && (!IS_BLANK(CUR))) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt,
+			    "Space required before 'NDATA'\n");
+		    ctxt->wellFormed = 0;
+		}
 		SKIP_BLANKS;
 		if ((CUR == 'N') && (NXT(1) == 'D') &&
 		    (NXT(2) == 'A') && (NXT(3) == 'T') &&
 		    (NXT(4) == 'A')) {
 		    SKIP(5);
+		    if (!IS_BLANK(CUR)) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt,
+			        "Space required after 'NDATA'\n");
+			ctxt->wellFormed = 0;
+		    }
 		    SKIP_BLANKS;
 		    ndata = xmlParseName(ctxt);
 		    xmlAddDocEntity(ctxt->doc, name,
@@ -1971,6 +2102,7 @@
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, 
 	            "xmlParseEntityDecl: entity %s not terminated\n", name);
+	    ctxt->wellFormed = 0;
 	} else
 	    NEXT;
 	if (name != NULL) free(name);
@@ -1982,6 +2114,64 @@
 }
 
 /**
+ * xmlParseDefaultDecl:
+ * @ctxt:  an XML parser context
+ * @value:  Receive a possible fixed default value for the attribute
+ *
+ * Parse an attribute default declaration
+ *
+ * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
+ *
+ * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
+ *          or XML_ATTRIBUTE_FIXED. 
+ */
+
+int
+xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, CHAR **value) {
+    int val;
+    CHAR *ret;
+
+    *value = NULL;
+    if ((CUR == '#') && (NXT(1) == 'R') &&
+        (NXT(2) == 'E') && (NXT(3) == 'Q') &&
+        (NXT(4) == 'U') && (NXT(5) == 'I') &&
+        (NXT(6) == 'R') && (NXT(7) == 'E') &&
+        (NXT(8) == 'D')) {
+	SKIP(9);
+	return(XML_ATTRIBUTE_REQUIRED);
+    }
+    if ((CUR == '#') && (NXT(1) == 'I') &&
+        (NXT(2) == 'M') && (NXT(3) == 'P') &&
+        (NXT(4) == 'L') && (NXT(5) == 'I') &&
+        (NXT(6) == 'E') && (NXT(7) == 'D')) {
+	SKIP(8);
+	return(XML_ATTRIBUTE_IMPLIED);
+    }
+    val = XML_ATTRIBUTE_NONE;
+    if ((CUR == '#') && (NXT(1) == 'F') &&
+        (NXT(2) == 'I') && (NXT(3) == 'X') &&
+        (NXT(4) == 'E') && (NXT(5) == 'D')) {
+	SKIP(6);
+	val = XML_ATTRIBUTE_FIXED;
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt, "Space required after '#FIXED'\n");
+	    ctxt->wellFormed = 0;
+	}
+	SKIP_BLANKS;
+    }
+    ret = xmlParseAttValue(ctxt);
+    if (ret == NULL) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt,
+	       "Attribute default value declaration error\n");
+	ctxt->wellFormed = 0;
+    } else
+        *value = ret;
+    return(val);
+}
+
+/**
  * xmlParseEnumeratedType:
  * @ctxt:  an XML parser context
  * @name:  ???
@@ -2003,6 +2193,7 @@
     /*
      * TODO !!!
      */
+    fprintf(stderr, "Production [57] EnumeratedType not yet supported\n");
     while ((IS_CHAR(CUR)) && (CUR != '>'))
         NEXT;
 }
@@ -2012,7 +2203,7 @@
  * @ctxt:  an XML parser context
  * @name:  ???
  *
- * : parse the Attribute list def for an element
+ * parse the Attribute list def for an element
  *
  * [54] AttType ::= StringType | TokenizedType | EnumeratedType
  *
@@ -2021,46 +2212,54 @@
  * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
  *                        'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
  *
- * TODO: not implemented !!!
+ * Returns: the attribute type
  */
-void
+int 
 xmlParseAttributeType(xmlParserCtxtPtr ctxt, CHAR *name) {
     /* TODO !!! */
     if ((CUR == 'C') && (NXT(1) == 'D') &&
         (NXT(2) == 'A') && (NXT(3) == 'T') &&
         (NXT(4) == 'A')) {
 	SKIP(5);
+	return(XML_ATTRIBUTE_STRING);
      } else if ((CUR == 'I') && (NXT(1) == 'D')) {
         SKIP(2);
+	return(XML_ATTRIBUTE_ID);
      } else if ((CUR == 'I') && (NXT(1) == 'D') &&
         (NXT(2) == 'R') && (NXT(3) == 'E') &&
         (NXT(4) == 'F')) {
 	SKIP(5);
+	return(XML_ATTRIBUTE_IDREF);
      } else if ((CUR == 'I') && (NXT(1) == 'D') &&
         (NXT(2) == 'R') && (NXT(3) == 'E') &&
         (NXT(4) == 'F') && (NXT(5) == 'S')) {
 	SKIP(6);
+	return(XML_ATTRIBUTE_IDREFS);
      } else if ((CUR == 'E') && (NXT(1) == 'N') &&
         (NXT(2) == 'T') && (NXT(3) == 'I') &&
         (NXT(4) == 'T') && (NXT(5) == 'Y')) {
 	SKIP(6);
+	return(XML_ATTRIBUTE_ENTITY);
      } else if ((CUR == 'E') && (NXT(1) == 'N') &&
         (NXT(2) == 'T') && (NXT(3) == 'I') &&
         (NXT(4) == 'T') && (NXT(5) == 'I') &&
         (NXT(6) == 'E') && (NXT(7) == 'S')) {
 	SKIP(8);
+	return(XML_ATTRIBUTE_ENTITIES);
      } else if ((CUR == 'N') && (NXT(1) == 'M') &&
         (NXT(2) == 'T') && (NXT(3) == 'O') &&
         (NXT(4) == 'K') && (NXT(5) == 'E') &&
         (NXT(6) == 'N')) {
 	SKIP(7);
+	return(XML_ATTRIBUTE_NMTOKEN);
      } else if ((CUR == 'N') && (NXT(1) == 'M') &&
         (NXT(2) == 'T') && (NXT(3) == 'O') &&
         (NXT(4) == 'K') && (NXT(5) == 'E') &&
         (NXT(6) == 'N') && (NXT(7) == 'S')) {
-     } else {
-        xmlParseEnumeratedType(ctxt, name);
+	return(XML_ATTRIBUTE_NMTOKENS);
      }
+     xmlParseEnumeratedType(ctxt, name);
+     return(XML_ATTRIBUTE_ENUMERATED);
 }
 
 /**
@@ -2077,51 +2276,183 @@
  */
 void
 xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
-    CHAR *name;
+    CHAR *elemName;
+    CHAR *attrName;
 
     /* TODO !!! */
     if ((CUR == '<') && (NXT(1) == '!') &&
         (NXT(2) == 'A') && (NXT(3) == 'T') &&
         (NXT(4) == 'T') && (NXT(5) == 'L') &&
         (NXT(6) == 'I') && (NXT(7) == 'S') &&
-        (NXT(8) == 'T') && (IS_BLANK(NXT(9)))) {
+        (NXT(8) == 'T')) {
 	SKIP(9);
-        SKIP_BLANKS;
-        name = xmlParseName(ctxt);
-	if (name == NULL) {
+	if (!IS_BLANK(CUR)) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	        ctxt->sax->error(ctxt, 
-	        "xmlParseAttributeListDecl: no name for Element\n");
+	        ctxt->sax->error(ctxt, "Space required after '<!ATTLIST'\n");
+	    ctxt->wellFormed = 0;
+	}
+        SKIP_BLANKS;
+        elemName = xmlParseName(ctxt);
+	if (elemName == NULL) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt, "ATTLIST: no name for Element\n");
+	    ctxt->wellFormed = 0;
 	    return;
 	}
 	SKIP_BLANKS;
 	while (CUR != '>') {
 	    const CHAR *check = CUR_PTR;
+	    int type;
+	    int def;
+	    CHAR *defaultValue = NULL;
 
-	    xmlParseAttributeType(ctxt, name);
+	    attrName = xmlParseName(ctxt);
+	    if (attrName == NULL) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt, "ATTLIST: no name for Attribute\n");
+		ctxt->wellFormed = 0;
+		break;
+	    }
+	    if (!IS_BLANK(CUR)) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt, 
+		        "Space required after the attribute name\n");
+		ctxt->wellFormed = 0;
+		break;
+	    }
 	    SKIP_BLANKS;
+
+	    type = xmlParseAttributeType(ctxt, attrName);
+	    if (type <= 0) break;
+
+	    if (!IS_BLANK(CUR)) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt, 
+		        "Space required after the attribute type\n");
+		ctxt->wellFormed = 0;
+		break;
+	    }
+	    SKIP_BLANKS;
+
+	    def = xmlParseDefaultDecl(ctxt, &defaultValue);
+	    if (def <= 0) break;
+
+            if (CUR != '>') {
+		if (!IS_BLANK(CUR)) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt, 
+			"Space required after the attribute default value\n");
+		    ctxt->wellFormed = 0;
+		    break;
+		}
+		SKIP_BLANKS;
+	    }
 	    if (check == CUR_PTR) {
 	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, 
-		    "xmlParseAttributeListDecl: detected error\n");
+		    "xmlParseAttributeListDecl: detected internal error\n");
 		break;
 	    }
+	    if (attrName != NULL)
+		free(attrName);
+	    if (defaultValue != NULL)
+	        free(defaultValue);
 	}
 	if (CUR == '>')
 	    NEXT;
 
-	free(name);
+	free(elemName);
     }
 }
 
 /**
- * xmlParseElementContentDecl:
+ * xmlParseElementMixedContentDecl:
  * @ctxt:  an XML parser context
- * @name:  ???
  *
- * parse the declaration for an Element content
- * either Mixed or Children, the cases EMPTY and ANY being handled
+ * parse the declaration for a Mixed Element content
+ * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
  * 
+ * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
+ *                '(' S? '#PCDATA' S? ')'
+ *
+ * returns: the list of the xmlElementContentPtr describing the element choices
+ */
+xmlElementContentPtr
+xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
+    xmlElementContentPtr ret = NULL, cur = NULL;
+    CHAR *elem = NULL;
+
+    if ((CUR == '#') && (NXT(1) == 'P') &&
+        (NXT(2) == 'C') && (NXT(3) == 'D') &&
+        (NXT(4) == 'A') && (NXT(5) == 'T') &&
+        (NXT(6) == 'A')) {
+	SKIP(7);
+	SKIP_BLANKS;
+	if ((CUR == '(') || (CUR == '|')) {
+	    ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
+	    if (ret == NULL) return(NULL);
+	} else {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		    "xmlParseElementMixedContentDecl : '|' or ')' expected\n");
+	    ctxt->wellFormed = 0;
+	    return(NULL);
+	}
+	while (CUR == '|') {
+	    if (elem == NULL) {
+	        ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
+		if (ret == NULL) return(NULL);
+		ret->c1 = cur;
+	    } else {
+	        cur->c1 = xmlNewElementContent(elem,
+		                               XML_ELEMENT_CONTENT_ELEMENT);
+	        cur->c2 = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
+		cur = cur->c2;
+		if (cur == NULL) return(NULL);
+	    }
+	    SKIP_BLANKS;
+	    elem = xmlParseName(ctxt);
+	    if (elem == NULL) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt, 
+			"xmlParseElementMixedContentDecl : Name expected\n");
+		ctxt->wellFormed = 0;
+		xmlFreeElementContent(cur);
+		return(NULL);
+	    }
+	    SKIP_BLANKS;
+	}
+	if (CUR == ')') {
+	    if (elem != NULL)
+		cur->c2 = xmlNewElementContent(elem,
+		                               XML_ELEMENT_CONTENT_ELEMENT);
+	    NEXT;
+	} else {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		    "xmlParseElementMixedContentDecl : '|' or ')' expected\n");
+	    ctxt->wellFormed = 0;
+	    xmlFreeElementContent(ret);
+	    return(NULL);
+	}
+
+    } else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, 
+		"xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
+	ctxt->wellFormed = 0;
+    }
+    return(ret);
+}
+
+/**
+ * xmlParseElementChildrenContentDecl:
+ * @ctxt:  an XML parser context
+ *
+ * parse the declaration for a Mixed Element content
+ * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
+ * 
+ *
  * [47] children ::= (choice | seq) ('?' | '*' | '+')?
  *
  * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
@@ -2130,23 +2461,217 @@
  *
  * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
  *
- * or
+ * returns: the tree of xmlElementContentPtr describing the element 
+ *          hierarchy.
+ */
+xmlElementContentPtr
+xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
+    xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
+    CHAR *elem;
+    CHAR type = 0;
+
+    SKIP_BLANKS;
+    if (CUR == '(') {
+        /* Recurse on first child */
+	NEXT;
+	SKIP_BLANKS;
+        cur = ret = xmlParseElementChildrenContentDecl(ctxt);
+	SKIP_BLANKS;
+    } else {
+	elem = xmlParseName(ctxt);
+	if (elem == NULL) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		"xmlParseElementChildrenContentDecl : Name or '(' expected\n");
+	    ctxt->wellFormed = 0;
+	    return(NULL);
+	}
+        cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
+	if (CUR == '?') {
+	    ret->ocur = XML_ELEMENT_CONTENT_OPT;
+	    NEXT;
+	} else if (CUR == '*') {
+	    ret->ocur = XML_ELEMENT_CONTENT_MULT;
+	    NEXT;
+	} else if (CUR == '+') {
+	    ret->ocur = XML_ELEMENT_CONTENT_PLUS;
+	    NEXT;
+	} else {
+	    ret->ocur = XML_ELEMENT_CONTENT_ONCE;
+	}
+    }
+    SKIP_BLANKS;
+    while (CUR != ')') {
+        /*
+	 * Each loop we parse one separator and one element.
+	 */
+        if (CUR == ',') {
+	    if (type == 0) type = CUR;
+
+	    /*
+	     * Detect "Name | Name , Name" error
+	     */
+	    else if (type != CUR) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt, 
+		    "xmlParseElementChildrenContentDecl : '%c' expected\n",
+		    type);
+		ctxt->wellFormed = 0;
+		xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+
+	    op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
+	    if (op == NULL) {
+	        xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+	    if (last == NULL) {
+		op->c1 = ret;
+		ret = cur = op;
+	    } else {
+	        cur->c2 = op;
+		op->c1 = last;
+		cur =op;
+	    }
+	} else if (CUR == '|') {
+	    if (type == 0) type = CUR;
+
+	    /*
+	     * Detect "Name , Name | Name" error
+	     */
+	    else if (type != CUR) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt, 
+		    "xmlParseElementChildrenContentDecl : '%c' expected\n",
+		    type);
+		ctxt->wellFormed = 0;
+		xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+
+	    op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
+	    if (op == NULL) {
+	        xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+	    if (last == NULL) {
+		op->c1 = ret;
+		ret = cur = op;
+	    } else {
+	        cur->c2 = op;
+		op->c1 = last;
+		cur =op;
+	    }
+	} else {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+	    "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
+	    ctxt->wellFormed = 0;
+	    xmlFreeElementContent(ret);
+	    return(NULL);
+	}
+	SKIP_BLANKS;
+	if (CUR == '(') {
+	    /* Recurse on second child */
+	    NEXT;
+	    SKIP_BLANKS;
+	    cur = xmlParseElementChildrenContentDecl(ctxt);
+	    SKIP_BLANKS;
+	} else {
+	    elem = xmlParseName(ctxt);
+	    if (elem == NULL) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt, 
+		    "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
+		ctxt->wellFormed = 0;
+		return(NULL);
+	    }
+	    cur = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
+	}
+	if (CUR == '?') {
+	    ret->ocur = XML_ELEMENT_CONTENT_OPT;
+	    NEXT;
+	} else if (CUR == '*') {
+	    ret->ocur = XML_ELEMENT_CONTENT_MULT;
+	    NEXT;
+	} else if (CUR == '+') {
+	    ret->ocur = XML_ELEMENT_CONTENT_PLUS;
+	    NEXT;
+	} else {
+	    ret->ocur = XML_ELEMENT_CONTENT_ONCE;
+	}
+	SKIP_BLANKS;
+    }
+    NEXT;
+    if (CUR == '?') {
+        ret->ocur = XML_ELEMENT_CONTENT_OPT;
+	NEXT;
+    } else if (CUR == '*') {
+        ret->ocur = XML_ELEMENT_CONTENT_MULT;
+	NEXT;
+    } else if (CUR == '+') {
+        ret->ocur = XML_ELEMENT_CONTENT_PLUS;
+	NEXT;
+    } else {
+        ret->ocur = XML_ELEMENT_CONTENT_ONCE;
+    }
+    return(ret);
+}
+
+/**
+ * xmlParseElementContentDecl:
+ * @ctxt:  an XML parser context
+ * @name:  the name of the element being defined.
+ * @result:  the Element Content pointer will be stored here if any
  *
- * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
- *                '(' S? '#PCDATA' S? ')'
+ * parse the declaration for an Element content either Mixed or Children,
+ * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
+ * 
+ * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
  *
- * TODO: not implemented !!!
+ * returns: the type of element content XML_ELEMENT_TYPE_xxx
  */
 
-void
-xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, CHAR *name) {
-    /*
-     * TODO This has to be parsed correctly, currently we just skip until
-     *      we reach the first '>'.
-     * !!!
-     */
-    while ((IS_CHAR(CUR)) && (CUR != '>'))
-        NEXT;
+int
+xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, CHAR *name,
+                           xmlElementContentPtr *result) {
+
+    xmlElementContentPtr tree = NULL;
+    int res;
+
+    *result = NULL;
+
+    if (CUR != '(') {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, 
+		"xmlParseElementContentDecl : '(' expected\n");
+	ctxt->wellFormed = 0;
+	return(-1);
+    }
+    NEXT;
+    SKIP_BLANKS;
+    if ((CUR == '#') && (NXT(1) == 'P') &&
+        (NXT(2) == 'C') && (NXT(3) == 'D') &&
+        (NXT(4) == 'A') && (NXT(5) == 'T') &&
+        (NXT(6) == 'A')) {
+        tree = xmlParseElementMixedContentDecl(ctxt);
+	res = XML_ELEMENT_TYPE_MIXED;
+    } else {
+        tree = xmlParseElementChildrenContentDecl(ctxt);
+	res = XML_ELEMENT_TYPE_ELEMENT;
+    }
+    SKIP_BLANKS;
+    /****************************
+    if (CUR != ')') {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, 
+		"xmlParseElementContentDecl : ')' expected\n");
+	ctxt->wellFormed = 0;
+	return(-1);
+    }
+     ****************************/
+    return(res);
 }
 
 /**
@@ -2157,26 +2682,40 @@
  *
  * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
  *
- * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
- *
  * TODO There is a check [ VC: Unique Element Type Declaration ]
  */
-void
+int
 xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
     CHAR *name;
+    int ret = -1;
+    xmlElementContentPtr content  = NULL;
 
     if ((CUR == '<') && (NXT(1) == '!') &&
         (NXT(2) == 'E') && (NXT(3) == 'L') &&
         (NXT(4) == 'E') && (NXT(5) == 'M') &&
         (NXT(6) == 'E') && (NXT(7) == 'N') &&
-        (NXT(8) == 'T') && (IS_BLANK(NXT(9)))) {
+        (NXT(8) == 'T')) {
 	SKIP(9);
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		    "Space required after 'ELEMENT'\n");
+	    ctxt->wellFormed = 0;
+	}
         SKIP_BLANKS;
         name = xmlParseName(ctxt);
 	if (name == NULL) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	        ctxt->sax->error(ctxt, "xmlParseElementDecl: no name for Element\n");
-	    return;
+	        ctxt->sax->error(ctxt,
+		   "xmlParseElementDecl: no name for Element\n");
+	    ctxt->wellFormed = 0;
+	    return(-1);
+	}
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		    "Space required after the element name\n");
+	    ctxt->wellFormed = 0;
 	}
         SKIP_BLANKS;
 	if ((CUR == 'E') && (NXT(1) == 'M') &&
@@ -2186,23 +2725,39 @@
 	    /*
 	     * Element must always be empty.
 	     */
+	    ret = XML_ELEMENT_TYPE_EMPTY;
 	} else if ((CUR == 'A') && (NXT(1) == 'N') &&
 	           (NXT(2) == 'Y')) {
 	    SKIP(3);
 	    /*
 	     * Element is a generic container.
 	     */
+	    ret = XML_ELEMENT_TYPE_ANY;
+	} else if (CUR == '(') {
+	    ret = xmlParseElementContentDecl(ctxt, name, &content);
 	} else {
-	    xmlParseElementContentDecl(ctxt, name);
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt, 
+	          "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
+	    ctxt->wellFormed = 0;
+	    if (name != NULL) free(name);
+	    return(-1);
 	}
 	SKIP_BLANKS;
 	if (CUR != '>') {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, 
 	          "xmlParseElementDecl: expected '>' at the end\n");
-	} else
+	    ctxt->wellFormed = 0;
+	} else {
 	    NEXT;
+	    xmlAddElementDecl(ctxt->doc->intSubset, name, ret, content);
+	}
+	if (name != NULL) {
+	    free(name);
+	}
     }
+    return(ret);
 }
 
 /**
@@ -2254,7 +2809,8 @@
 	    else {
 	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, 
-		         "xmlParseCharRef: invalid hexa value\n");
+		         "xmlParseCharRef: invalid hexadecimal value\n");
+		ctxt->wellFormed = 0;
 		val = 0;
 		break;
 	    }
@@ -2271,6 +2827,7 @@
 	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, 
 		         "xmlParseCharRef: invalid decimal value\n");
+		ctxt->wellFormed = 0;
 		val = 0;
 		break;
 	    }
@@ -2281,6 +2838,7 @@
     } else {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "xmlParseCharRef: invalid value\n");
+	ctxt->wellFormed = 0;
     }
     /*
      * Check the value IS_CHAR ...
@@ -2293,6 +2851,7 @@
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "xmlParseCharRef: invalid CHAR value %d\n",
 	                     val);
+	ctxt->wellFormed = 0;
     }
     return(NULL);
 }
@@ -2311,6 +2870,7 @@
     CHAR *ret = NULL;
     const CHAR *q;
     CHAR *name;
+    xmlEntityPtr ent;
     xmlParserInputPtr input = NULL;
 
     q = CUR_PTR;
@@ -2320,10 +2880,62 @@
 	if (name == NULL) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "xmlParseEntityRef: no name\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    if (CUR == ';') {
 	        NEXT;
 		/*
+		 * Well Formedness Constraint if:
+		 *   - standalone
+		 * or
+		 *   - no external subset and no external parameter entities
+		 *     referenced
+		 * then
+		 *   the entity referenced must have been declared
+		 *
+		 * TODO: to be double checked !!!
+		 */
+		ent = xmlGetDocEntity(ctxt->doc, name);
+		if ((ctxt->doc->standalone) ||
+		    ((ctxt->doc->intSubset == NULL) &&
+		     (ctxt->doc->extSubset == NULL))) {
+		    if (ent == NULL) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt, 
+			         "Entity '%s' not defined\n", name);
+			ctxt->wellFormed = 0;
+		    }
+		}
+
+		/*
+		 * Well Formedness Constraint :
+		 *   The referenced entity must be a parsed entity.
+		 */
+		if (ent != NULL) {
+		    switch (ent->type) {
+			case XML_INTERNAL_PARAMETER_ENTITY:
+			case XML_EXTERNAL_PARAMETER_ENTITY:
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt, 
+		     "Attempt to reference the parameter entity '%s'\n", name);
+			ctxt->wellFormed = 0;
+			break;
+                        
+			case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt, 
+		     "Attempt to reference unparsed entity '%s'\n", name);
+			ctxt->wellFormed = 0;
+			break;
+		    }
+		}
+
+		/*
+		 * Well Formedness Constraint :
+		 *   The referenced entity must not lead to recursion !
+		 */
+		 
+		/*
 		 * We parsed the entity reference correctly, call SAX
 		 * interface for the proper behaviour:
 		 *   - get a new input stream
@@ -2340,7 +2952,9 @@
 		char cst[2] = { '&', 0 };
 
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-		    ctxt->sax->error(ctxt, "xmlParseEntityRef: expecting ';'\n");
+		    ctxt->sax->error(ctxt,
+		                     "xmlParseEntityRef: expecting ';'\n");
+		ctxt->wellFormed = 0;
 		ret = xmlStrndup(cst, 1);
 		ret = xmlStrcat(ret, name);
 	    }
@@ -2363,7 +2977,14 @@
 CHAR *
 xmlParseReference(xmlParserCtxtPtr ctxt) {
     if ((CUR == '&') && (NXT(1) == '#')) {
-        return(xmlParseCharRef(ctxt));
+        CHAR *val = xmlParseCharRef(ctxt);
+	xmlParserInputPtr in;
+
+	if (val != NULL) {
+	    in = xmlNewStringInputStream(ctxt, val);
+	    xmlPushInput(ctxt, in);
+	}
+	return(NULL);
     } else if (CUR == '&') {
         return(xmlParseEntityRef(ctxt));
     }
@@ -2392,6 +3013,7 @@
 	if (name == NULL) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "xmlParsePEReference: no name\n");
+	    ctxt->wellFormed = 0;
 	} else {
 	    if (CUR == ';') {
 	        NEXT;
@@ -2399,7 +3021,7 @@
 		if (entity == NULL) {
 		    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
 		        ctxt->sax->warning(ctxt,
-		         "xmlParsePEReference: %%%s; not found\n");
+		         "xmlParsePEReference: %%%s; not found\n", name);
 		} else {
 		    input = xmlNewEntityInputStream(ctxt, entity);
 		    xmlPushInput(ctxt, input);
@@ -2408,7 +3030,9 @@
 		char cst[2] = { '%', 0 };
 
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-		    ctxt->sax->error(ctxt, "xmlParsePEReference: expecting ';'\n");
+		    ctxt->sax->error(ctxt,
+		                     "xmlParsePEReference: expecting ';'\n");
+		ctxt->wellFormed = 0;
 		ret = xmlStrndup(cst, 1);
 		ret = xmlStrcat(ret, name);
 	    }
@@ -2449,6 +3073,7 @@
     if (name == NULL) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "xmlParseDocTypeDecl : no DOCTYPE name !\n");
+	ctxt->wellFormed = 0;
     }
 
     SKIP_BLANKS;
@@ -2459,7 +3084,7 @@
     URI = xmlParseExternalID(ctxt, &ExternalID);
     SKIP_BLANKS;
 
-    dtd = xmlNewDtd(ctxt->doc, name, ExternalID, URI);
+    dtd = xmlCreateIntSubset(ctxt->doc, name, ExternalID, URI);
 
     /*
      * Is there any DTD definition ?
@@ -2482,6 +3107,7 @@
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, 
 		 "xmlParseDocTypeDecl: error detected in Markup declaration\n");
+		ctxt->wellFormed = 0;
 		break;
 	    }
 	}
@@ -2494,6 +3120,7 @@
     if (CUR != '>') {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "DOCTYPE unproperly terminated\n");
+	ctxt->wellFormed = 0;
         /* We shouldn't try to resynchronize ... */
     }
     NEXT;
@@ -2527,7 +3154,7 @@
  */
 
 xmlAttrPtr xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlNodePtr node) {
-    CHAR *name;
+    CHAR *name, *val;
     CHAR *ns;
     CHAR *value = NULL;
     xmlAttrPtr ret;
@@ -2536,6 +3163,7 @@
     if (name == NULL) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "error parsing attribute name\n");
+	ctxt->wellFormed = 0;
         return(NULL);
     }
 
@@ -2549,8 +3177,9 @@
 	value = xmlParseAttValue(ctxt);
     } else {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	    ctxt->sax->error(ctxt, "Specification mandate value for attribute %s\n",
-	               name);
+	    ctxt->sax->error(ctxt,
+	       "Specification mandate value for attribute %s\n", name);
+	ctxt->wellFormed = 0;
     }
 
     /*
@@ -2579,9 +3208,20 @@
 	return(NULL);
     }
 
-    ret = xmlNewProp(ctxt->node, name, NULL);
-    if (ret != NULL)
-        ret->val = xmlStringGetNodeList(ctxt->doc, value);
+    /*
+     * Well formedness requires at most one declaration of an attribute
+     */
+    if ((val = xmlGetProp(ctxt->node, name)) != NULL) {
+        free(val);
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, "Attribute %s redefined\n", name);
+	ctxt->wellFormed = 0;
+	ret = NULL;
+    } else {
+	ret = xmlNewProp(ctxt->node, name, NULL);
+	if (ret != NULL)
+	    ret->val = xmlStringGetNodeList(ctxt->doc, value);
+    }
 
     if (ns != NULL)
       free(ns);
@@ -2621,7 +3261,13 @@
     NEXT;
 
     name = xmlNamespaceParseQName(ctxt, &namespace);
-    if (name == NULL) return(NULL);
+    if (name == NULL) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, 
+	     "xmlParseStartTag: invalid element name\n");
+	ctxt->wellFormed = 0;
+        return(NULL);
+    }
 
     /*
      * Note : the namespace resolution is deferred until the end of the
@@ -2659,6 +3305,7 @@
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, 
 	         "xmlParseStartTag: problem parsing attributes\n");
+	    ctxt->wellFormed = 0;
 	    break;
 	}
     }
@@ -2719,6 +3366,7 @@
     if ((CUR != '<') || (NXT(1) != '/')) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "xmlParseEndTag: '</' not found\n");
+	ctxt->wellFormed = 0;
 	return;
     }
     SKIP(2);
@@ -2742,6 +3390,7 @@
     if ((!IS_CHAR(CUR)) || (CUR != '>')) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "End tag : expected '>'\n");
+	ctxt->wellFormed = 0;
     } else
 	NEXT;
 
@@ -2778,12 +3427,14 @@
     if (!IS_CHAR(CUR)) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "CData section not finished\n%.50s\n", base);
+	ctxt->wellFormed = 0;
         return;
     }
     r = NEXT;
     if (!IS_CHAR(CUR)) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "CData section not finished\n%.50s\n", base);
+	ctxt->wellFormed = 0;
         return;
     }
     s = NEXT;
@@ -2794,6 +3445,7 @@
     if (!IS_CHAR(CUR)) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "CData section not finished\n%.50s\n", base);
+	ctxt->wellFormed = 0;
         return;
     }
 
@@ -2802,9 +3454,9 @@
      */
     if (ctxt->sax != NULL) {
 	if (areBlanks(ctxt, base, CUR_PTR - base))
-	    ctxt->sax->ignorableWhitespace(ctxt, base, 0, CUR_PTR - base);
+	    ctxt->sax->ignorableWhitespace(ctxt, base, 0, (CUR_PTR - base) - 2);
 	else
-	    ctxt->sax->characters(ctxt, base, 0, CUR_PTR - base);
+	    ctxt->sax->characters(ctxt, base, 0, (CUR_PTR - base) - 2);
     }
 }
 
@@ -2891,7 +3543,9 @@
 
 	if (test == CUR_PTR) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	        ctxt->sax->error(ctxt, "detected an error in element content\n");
+	        ctxt->sax->error(ctxt,
+		     "detected an error in element content\n");
+	    ctxt->wellFormed = 0;
             break;
 	}
     }
@@ -2946,6 +3600,7 @@
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "Couldn't find end of Start Tag\n%.30s\n",
 	                     openTag);
+	ctxt->wellFormed = 0;
 
 	/*
 	 * end of parsing of this node.
@@ -2963,6 +3618,7 @@
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt,
 	         "Premature end of data in tag %.30s\n", openTag);
+	ctxt->wellFormed = 0;
 
 	/*
 	 * end of parsing of this node.
@@ -2985,15 +3641,18 @@
 	    ctxt->sax->error(ctxt, 
 	    "Start and End tags don't use the same namespace\n%.30s\n%.30s\n",
 	               openTag, endTag);
+	ctxt->wellFormed = 0;
     }
     if (endTag == NULL ) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "The End tag has no name\n%.30s\n", openTag);
+	ctxt->wellFormed = 0;
     } else if (xmlStrcmp(ret->name, endTag)) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, 
 	    "Start and End tags don't use the same name\n%.30s\n%.30s\n",
 	               openTag, endTag);
+	ctxt->wellFormed = 0;
     }
     /*
      * SAX: End of Tag
@@ -3071,6 +3730,7 @@
 	if (CUR != '=') {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "xmlParseVersionInfo : expected '='\n");
+	    ctxt->wellFormed = 0;
 	    return(NULL);
         }
 	NEXT;
@@ -3082,6 +3742,7 @@
 	    if (CUR != '"') {
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, "String not closed\n%.50s\n", q);
+		ctxt->wellFormed = 0;
 	    } else
 	        NEXT;
 	} else if (CUR == '\''){
@@ -3091,11 +3752,14 @@
 	    if (CUR != '\'') {
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, "String not closed\n%.50s\n", q);
+		ctxt->wellFormed = 0;
 	    } else
 	        NEXT;
 	} else {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	        ctxt->sax->error(ctxt, "xmlParseVersionInfo : expected ' or \"\n");
+	        ctxt->sax->error(ctxt,
+		      "xmlParseVersionInfo : expected ' or \"\n");
+		ctxt->wellFormed = 0;
 	}
     }
     return(version);
@@ -3128,6 +3792,7 @@
     } else {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "Invalid XML encoding name\n");
+	ctxt->wellFormed = 0;
     }
     return(ret);
 }
@@ -3160,6 +3825,7 @@
 	if (CUR != '=') {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "xmlParseEncodingDecl : expected '='\n");
+	    ctxt->wellFormed = 0;
 	    return(NULL);
         }
 	NEXT;
@@ -3171,6 +3837,7 @@
 	    if (CUR != '"') {
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, "String not closed\n%.50s\n", q);
+		ctxt->wellFormed = 0;
 	    } else
 	        NEXT;
 	} else if (CUR == '\''){
@@ -3180,11 +3847,14 @@
 	    if (CUR != '\'') {
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, "String not closed\n%.50s\n", q);
+		ctxt->wellFormed = 0;
 	    } else
 	        NEXT;
 	} else if (CUR == '"'){
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	        ctxt->sax->error(ctxt, "xmlParseEncodingDecl : expected ' or \"\n");
+	        ctxt->sax->error(ctxt,
+		     "xmlParseEncodingDecl : expected ' or \"\n");
+	    ctxt->wellFormed = 0;
 	}
     }
     return(encoding);
@@ -3214,7 +3884,9 @@
 	SKIP(10);
 	if (CUR != '=') {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-	        ctxt->sax->error(ctxt, "XML standalone declaration : expected '='\n");
+	        ctxt->sax->error(ctxt,
+		    "XML standalone declaration : expected '='\n");
+	    ctxt->wellFormed = 0;
 	    return(standalone);
         }
 	NEXT;
@@ -3231,10 +3903,12 @@
             } else {
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, "standalone accepts only 'yes' or 'no'\n");
+		ctxt->wellFormed = 0;
 	    }
 	    if (CUR != '\'') {
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, "String not closed\n");
+		ctxt->wellFormed = 0;
 	    } else
 	        NEXT;
 	} else if (CUR == '"'){
@@ -3248,16 +3922,20 @@
                 SKIP(3);
             } else {
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
-		    ctxt->sax->error(ctxt, "standalone accepts only 'yes' or 'no'\n");
+		    ctxt->sax->error(ctxt,
+		        "standalone accepts only 'yes' or 'no'\n");
+		ctxt->wellFormed = 0;
 	    }
 	    if (CUR != '"') {
 		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		    ctxt->sax->error(ctxt, "String not closed\n");
+		ctxt->wellFormed = 0;
 	    } else
 	        NEXT;
 	} else {
             if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	        ctxt->sax->error(ctxt, "Standalone value not found\n");
+	    ctxt->wellFormed = 0;
         }
     }
     return(standalone);
@@ -3281,6 +3959,11 @@
      */
     SKIP(5);
 
+    if (!IS_BLANK(CUR)) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, "Blank needed after '<?xml'\n");
+	ctxt->wellFormed = 0;
+    }
     SKIP_BLANKS;
 
     /*
@@ -3295,11 +3978,30 @@
     /*
      * We may have the encoding declaration
      */
+    if (!IS_BLANK(CUR)) {
+        if ((CUR == '?') && (NXT(1) == '>')) {
+	    SKIP(2);
+	    return;
+	}
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, "Blank needed here\n");
+	ctxt->wellFormed = 0;
+    }
     ctxt->doc->encoding = xmlParseEncodingDecl(ctxt);
 
     /*
      * We may have the standalone status.
      */
+    if ((ctxt->doc->encoding != NULL) && (!IS_BLANK(CUR))) {
+        if ((CUR == '?') && (NXT(1) == '>')) {
+	    SKIP(2);
+	    return;
+	}
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, "Blank needed here\n");
+	ctxt->wellFormed = 0;
+    }
+    SKIP_BLANKS;
     ctxt->doc->standalone = xmlParseSDDecl(ctxt);
 
     SKIP_BLANKS;
@@ -3309,10 +4011,12 @@
         /* Deprecated old WD ... */
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "XML declaration must end-up with '?>'\n");
+	ctxt->wellFormed = 0;
 	NEXT;
     } else {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 	    ctxt->sax->error(ctxt, "parsing XML declaration: '?>' expected\n");
+	ctxt->wellFormed = 0;
 	MOVETO_ENDTAG(CUR_PTR);
 	NEXT;
     }
@@ -3377,7 +4081,19 @@
     /*
      * Wipe out everything which is before the first '<'
      */
-    SKIP_BLANKS;
+    if (IS_BLANK(CUR)) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt,
+	    "Extra spaces at the beginning of the document are not allowed\n");
+	ctxt->wellFormed = 0;
+	SKIP_BLANKS;
+    }
+
+    if (CUR == 0) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, "Document is empty\n");
+	ctxt->wellFormed = 0;
+    }
 
     /*
      * Check for the XMLDecl in the Prolog.
@@ -3434,11 +4150,19 @@
      */
     xmlParseMisc(ctxt);
 
+    if (CUR != 0) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt,
+	        "Extra content at the end of the document\n");
+	ctxt->wellFormed = 0;
+    }
+
     /*
      * SAX: end of the document processing.
      */
     if (ctxt->sax) 
         ctxt->sax->endDocument(ctxt);
+    if (! ctxt->wellFormed) return(-1);
     return(0);
 }
 
@@ -3446,6 +4170,8 @@
  * xmlSAXParseDoc :
  * @sax:  the SAX handler block
  * @cur:  a pointer to an array of CHAR
+ * @recovery:  work in recovery mode, i.e. tries to read no Well Formed
+ *             documents
  *
  * parse an XML in-memory document and build a tree.
  * It use the given SAX function block to handle the parsing callback.
@@ -3454,7 +4180,7 @@
  * return values: the resulting document tree
  */
 
-xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur) {
+xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery) {
     xmlDocPtr ret;
     xmlParserCtxtPtr ctxt;
     xmlParserInputPtr input;
@@ -3485,7 +4211,12 @@
 
 
     xmlParseDocument(ctxt);
-    ret = ctxt->doc;
+    if ((ctxt->wellFormed) || recovery) ret = ctxt->doc;
+    else {
+       ret = NULL;
+       xmlFreeDoc(ctxt->doc);
+       ctxt->doc = NULL;
+    }
     free(ctxt->nodeTab);
     free(ctxt->inputTab);
     if (input->filename != NULL)
@@ -3506,13 +4237,29 @@
  */
 
 xmlDocPtr xmlParseDoc(CHAR *cur) {
-    return(xmlSAXParseDoc(NULL, cur));
+    return(xmlSAXParseDoc(NULL, cur, 0));
+}
+
+/**
+ * xmlRecoverDoc :
+ * @cur:  a pointer to an array of CHAR
+ *
+ * parse an XML in-memory document and build a tree.
+ * In the case the document is not Well Formed, a tree is built anyway
+ * 
+ * return values: the resulting document tree
+ */
+
+xmlDocPtr xmlRecoverDoc(CHAR *cur) {
+    return(xmlSAXParseDoc(NULL, cur, 1));
 }
 
 /**
  * xmlSAXParseFile :
  * @sax:  the SAX handler block
  * @filename:  the filename
+ * @recovery:  work in recovery mode, i.e. tries to read no Well Formed
+ *             documents
  *
  * parse an XML file and build a tree. Automatic support for ZLIB/Compress
  * compressed document is provided by default if found at compile-time.
@@ -3522,7 +4269,8 @@
  * return values: the resulting document tree
  */
 
-xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename) {
+xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
+                          int recovery) {
     xmlDocPtr ret;
 #ifdef HAVE_ZLIB_H
     gzFile input;
@@ -3624,7 +4372,12 @@
 
     xmlParseDocument(ctxt);
 
-    ret = ctxt->doc;
+    if ((ctxt->wellFormed) || recovery) ret = ctxt->doc;
+    else {
+       ret = NULL;
+       xmlFreeDoc(ctxt->doc);
+       ctxt->doc = NULL;
+    }
     free(buffer);
     free(ctxt->nodeTab);
     free(ctxt->inputTab);
@@ -3647,7 +4400,22 @@
  */
 
 xmlDocPtr xmlParseFile(const char *filename) {
-    return(xmlSAXParseFile(NULL, filename));
+    return(xmlSAXParseFile(NULL, filename, 0));
+}
+
+/**
+ * xmlRecoverFile :
+ * @filename:  the filename
+ *
+ * parse an XML file and build a tree. Automatic support for ZLIB/Compress
+ * compressed document is provided by default if found at compile-time.
+ * In the case the document is not Well Formed, a tree is built anyway
+ *
+ * return values: the resulting document tree
+ */
+
+xmlDocPtr xmlRecoverFile(const char *filename) {
+    return(xmlSAXParseFile(NULL, filename, 1));
 }
 
 /**
@@ -3655,6 +4423,8 @@
  * @sax:  the SAX handler block
  * @cur:  an pointer to a char array
  * @size:  the siwe of the array
+ * @recovery:  work in recovery mode, i.e. tries to read no Well Formed
+ *             documents
  *
  * parse an XML in-memory block and use the given SAX function block
  * to handle the parsing callback. If sax is NULL, fallback to the default
@@ -3665,7 +4435,8 @@
  * return values: the resulting document tree
  */
 
-xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size) {
+xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size,
+                            int recovery) {
     xmlDocPtr ret;
     xmlParserCtxtPtr ctxt;
     xmlParserInputPtr input;
@@ -3702,7 +4473,12 @@
 
     xmlParseDocument(ctxt);
 
-    ret = ctxt->doc;
+    if ((ctxt->wellFormed) || recovery) ret = ctxt->doc;
+    else {
+       ret = NULL;
+       xmlFreeDoc(ctxt->doc);
+       ctxt->doc = NULL;
+    }
     free(ctxt->nodeTab);
     free(ctxt->inputTab);
     if (input->filename != NULL)
@@ -3724,7 +4500,22 @@
  */
 
 xmlDocPtr xmlParseMemory(char *buffer, int size) {
-   return(xmlSAXParseMemory(NULL, buffer, size));
+   return(xmlSAXParseMemory(NULL, buffer, size, 0));
+}
+
+/**
+ * xmlRecoverMemory :
+ * @cur:  an pointer to a char array
+ * @size:  the size of the array
+ *
+ * parse an XML in-memory block and build a tree.
+ * In the case the document is not Well Formed, a tree is built anyway
+ * 
+ * return values: the resulting document tree
+ */
+
+xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
+   return(xmlSAXParseMemory(NULL, buffer, size, 1));
 }
 
 /**
@@ -3751,6 +4542,7 @@
 
   ctxt->sax = &xmlDefaultSAXHandler;
   ctxt->doc = NULL;
+  ctxt->wellFormed = 1;
   ctxt->record_info = 0;
   xmlInitNodeInfoSeq(&ctxt->node_seq);
 }
diff --git a/parser.h b/parser.h
index 4cd2ead..a06d481 100644
--- a/parser.h
+++ b/parser.h
@@ -3,7 +3,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #ifndef __XML_PARSER_H__
@@ -46,6 +46,7 @@
 typedef struct xmlParserCtxt {
     struct xmlSAXHandler *sax;        /* The SAX handler */
     xmlDocPtr doc;                    /* the document being built */
+    int            wellFormed;        /* is the document well formed */
 
     /* Input stream stack */
     xmlParserInputPtr  input;         /* Current input stream */
@@ -131,15 +132,8 @@
 #include "entities.h"
 
 /*
- * Interfaces
+ * CHAR handling
  */
-extern int xmlParseDocument(xmlParserCtxtPtr ctxt);
-extern xmlDocPtr xmlParseDoc(CHAR *cur);
-extern xmlDocPtr xmlParseMemory(char *buffer, int size);
-extern xmlDocPtr xmlParseFile(const char *filename);
-extern xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur);
-extern xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size);
-extern xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename);
 extern CHAR *xmlStrdup(const CHAR *input);
 extern CHAR *xmlStrndup(const CHAR *input, int n);
 extern CHAR *xmlStrchr(const CHAR *str, CHAR val);
@@ -149,6 +143,29 @@
 extern CHAR *xmlStrcat(CHAR *cur, const CHAR *add);
 extern CHAR *xmlStrncat(CHAR *cur, const CHAR *add, int len);
 
+/*
+ * Interfaces
+ */
+extern xmlDocPtr xmlParseDoc(CHAR *cur);
+extern xmlDocPtr xmlParseMemory(char *buffer, int size);
+extern xmlDocPtr xmlParseFile(const char *filename);
+
+/*
+ * Recovery mode 
+ */
+extern xmlDocPtr xmlRecoverDoc(CHAR *cur);
+extern xmlDocPtr xmlRecoverMemory(char *buffer, int size);
+extern xmlDocPtr xmlRecoverFile(const char *filename);
+
+/*
+ * Internal routines
+ */
+extern int xmlParseDocument(xmlParserCtxtPtr ctxt);
+extern xmlDocPtr xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery);
+extern xmlDocPtr xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer,
+                                   int size, int recovery);
+extern xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
+                                 int recovery);
 extern void xmlInitParserCtxt(xmlParserCtxtPtr ctx);
 extern void xmlClearParserCtxt(xmlParserCtxtPtr ctx);
 extern void xmlSetupParserForBuffer(xmlParserCtxtPtr ctx, const CHAR* buffer,
diff --git a/tester.c b/tester.c
index 6830917..945464e 100644
--- a/tester.c
+++ b/tester.c
@@ -3,7 +3,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #ifdef WIN32
@@ -32,13 +32,14 @@
 
 static int debug = 0;
 static int copy = 0;
+static int recovery = 0;
 
 /*
  * Note: there is a couple of errors introduced on purpose.
  */
 static CHAR buffer[] = 
 "\n\
-<?xml version=\"1.0\">\n\
+<?xml version=\"1.0\"?>\n\
 <?xml:namespace ns = \"http://www.ietf.org/standards/dav/\" prefix = \"D\"?>\n\
 <?xml:namespace ns = \"http://www.w3.com/standards/z39.50/\" prefix = \"Z\"?>\n\
 <D:propertyupdate>\n\
@@ -109,7 +110,10 @@
     /*
      * build an XML tree from a string;
      */
-    doc = xmlParseFile(filename);
+    if (recovery)
+	doc = xmlRecoverFile(filename);
+    else
+	doc = xmlParseFile(filename);
 
     /*
      * test intermediate copy if needed.
@@ -140,7 +144,10 @@
     /*
      * build an XML tree from a string;
      */
-    doc = xmlParseDoc(buf);
+    if (recovery)
+	doc = xmlRecoverDoc(buf);
+    else
+	doc = xmlParseDoc(buf);
 
     /*
      * test intermediate copy if needed.
@@ -174,6 +181,9 @@
 	    debug++;
 	else if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
 	    copy++;
+	else if ((!strcmp(argv[i], "-recover")) ||
+	         (!strcmp(argv[i], "--recover")))
+	    recovery++;
     }
     for (i = 1; i < argc ; i++) {
 	if (argv[i][0] != '-') {
diff --git a/tree.c b/tree.c
index e1dbd29..4d643d8 100644
--- a/tree.c
+++ b/tree.c
@@ -3,9 +3,9 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
- *
  * TODO Cleanup the Dump mechanism.
+ *
+ * Daniel.Veillard@w3.org
  */
 
 #include "config.h"
@@ -27,6 +27,15 @@
 
 static int xmlCompressMode = 0;
 
+#define UPDATE_LAST_CHILD(n) if ((n) != NULL) {				\
+    xmlNodePtr ulccur = (n)->childs;					\
+    if (ulccur == NULL) {						\
+        (n)->last = NULL;						\
+    } else {								\
+        while (ulccur->next != NULL) ulccur = ulccur->next;		\
+	(n)->last = ulccur;						\
+}   }
+
 /************************************************************************
  *									*
  *		Allocation and deallocation of basic structures		*
@@ -234,9 +243,10 @@
                     const CHAR *ExternalID, const CHAR *SystemID) {
     xmlDtdPtr cur;
 
-    if ((doc != NULL) && (doc->dtd != NULL)) {
+    if ((doc != NULL) && (doc->extSubset != NULL)) {
         fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
-	/* !!! */ (char *) name, doc->name, /* !!! */ (char *)doc->dtd->name);
+	    /* !!! */ (char *) name, doc->name,
+	    /* !!! */ (char *)doc->extSubset->name);
     }
 
     /*
@@ -263,7 +273,58 @@
     cur->elements = NULL;
     cur->entities = NULL;
     if (doc != NULL)
-	doc->dtd = cur;
+	doc->extSubset = cur;
+
+    return(cur);
+}
+
+/**
+ * xmlCreateIntSubset:
+ * @doc:  the document pointer
+ * @name:  the DTD name
+ * @ExternalID:  the external ID
+ * @SystemID:  the system ID
+ *
+ * Creatte the internal subset of a document
+ * return values: a pointer to the new DTD structure
+ */
+xmlDtdPtr
+xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
+                   const CHAR *ExternalID, const CHAR *SystemID) {
+    xmlDtdPtr cur;
+
+    if ((doc != NULL) && (doc->intSubset != NULL)) {
+        fprintf(stderr, 
+     "xmlCreateIntSubset(): document %s already have an internal subset\n",
+	    doc->name);
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new DTD and fill the fields.
+     */
+    cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
+    if (cur == NULL) {
+        fprintf(stderr, "xmlNewDtd : malloc failed\n");
+	return(NULL);
+    }
+
+    if (name != NULL)
+	cur->name = xmlStrdup(name); 
+    else
+        cur->name = NULL;
+    if (ExternalID != NULL)
+	cur->ExternalID = xmlStrdup(ExternalID); 
+    else
+        cur->ExternalID = NULL;
+    if (SystemID != NULL)
+	cur->SystemID = xmlStrdup(SystemID); 
+    else
+        cur->SystemID = NULL;
+    cur->elements = NULL;
+    cur->entities = NULL;
+    if (doc != NULL)
+	doc->intSubset = cur;
 
     return(cur);
 }
@@ -319,10 +380,10 @@
     cur->version = xmlStrdup(version); 
     cur->name = NULL;
     cur->root = NULL; 
-    cur->dtd = NULL;
+    cur->intSubset = NULL;
+    cur->extSubset = NULL;
     cur->oldNs = NULL;
     cur->encoding = NULL;
-    cur->entities = NULL;
     cur->standalone = -1;
     cur->compression = xmlCompressMode;
 #ifndef WITHOUT_CORBA
@@ -342,17 +403,18 @@
 void
 xmlFreeDoc(xmlDocPtr cur) {
     if (cur == NULL) {
+#ifdef DEBUG_TREE
         fprintf(stderr, "xmlFreeDoc : document == NULL\n");
+#endif
 	return;
     }
     free((char *) cur->version);
     if (cur->name != NULL) free((char *) cur->name);
     if (cur->encoding != NULL) free((char *) cur->encoding);
     if (cur->root != NULL) xmlFreeNode(cur->root);
-    if (cur->dtd != NULL) xmlFreeDtd(cur->dtd);
+    if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
+    if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
-    if (cur->entities != NULL)
-        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
     memset(cur, -1, sizeof(xmlDoc));
     free(cur);
 }
@@ -803,6 +865,7 @@
     cur->next = NULL;
     cur->prev = NULL;
     cur->childs = NULL;
+    cur->last = NULL;
     cur->properties = NULL;
     cur->name = xmlStrdup(name);
     cur->ns = ns;
@@ -834,8 +897,10 @@
     cur = xmlNewNode(ns, name);
     if (cur != NULL) {
         cur->doc = doc;
-	if (content != NULL)
+	if (content != NULL) {
 	    cur->childs = xmlStringGetNodeList(doc, content);
+	    UPDATE_LAST_CHILD(cur);
+	}
     }
     return(cur);
 }
@@ -867,6 +932,7 @@
     cur->next = NULL; 
     cur->prev = NULL; 
     cur->childs = NULL; 
+    cur->last = NULL; 
     cur->properties = NULL; 
     cur->type = XML_TEXT_NODE;
     cur->name = xmlStrdup(xmlStringText);
@@ -907,6 +973,7 @@
     cur->next = NULL; 
     cur->prev = NULL; 
     cur->childs = NULL; 
+    cur->last = NULL; 
     cur->properties = NULL; 
     if (name[0] == '&') {
         int len;
@@ -973,6 +1040,7 @@
     cur->prev = NULL; 
     cur->next = NULL; 
     cur->childs = NULL; 
+    cur->last = NULL; 
     cur->properties = NULL; 
     cur->type = XML_TEXT_NODE;
     cur->name = xmlStrdup(xmlStringText);
@@ -1030,6 +1098,7 @@
     cur->prev = NULL; 
     cur->next = NULL; 
     cur->childs = NULL; 
+    cur->last = NULL; 
     cur->properties = NULL; 
     cur->type = XML_COMMENT_NODE;
     cur->name = xmlStrdup(xmlStringText);
@@ -1104,11 +1173,12 @@
     cur->doc = parent->doc;
     if (parent->childs == NULL) {
         parent->childs = cur;
+	parent->last = cur;
     } else {
-        prev = parent->childs;
-	while (prev->next != NULL) prev = prev->next;
+        prev = parent->last;
 	prev->next = cur;
 	cur->prev = prev;
+	parent->last = cur;
     }
 
     return(cur);
@@ -1146,6 +1216,7 @@
      */
     cur->parent = parent;
     cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
+
     /*
      * Handle the case where parent->content != NULL, in that case it will
      * create a intermediate TEXT node.
@@ -1159,17 +1230,19 @@
 	    if (text->next != NULL)
 		text->next->prev = text;
 	    parent->childs = text;
+	    UPDATE_LAST_CHILD(parent);
 	    free(parent->content);
 	    parent->content = NULL;
 	}
     }
     if (parent->childs == NULL) {
         parent->childs = cur;
+	parent->last = cur;
     } else {
-        prev = parent->childs;
-	while (prev->next != NULL) prev = prev->next;
+        prev = parent->last;
 	prev->next = cur;
 	cur->prev = prev;
+	parent->last = cur;
     }
 
     return(cur);
@@ -1184,23 +1257,11 @@
  */
 xmlNodePtr
 xmlGetLastChild(xmlNodePtr parent) {
-    xmlNodePtr last;
-
     if (parent == NULL) {
         fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
 	return(NULL);
     }
-
-    /*
-     * add the new element at the end of the childs list.
-     */
-    if (parent->childs == NULL) {
-        return(NULL);
-    } else {
-        last = parent->childs;
-	while (last->next != NULL) last = last->next;
-    }
-    return(last);
+    return(parent->last);
 }
 
 /**
@@ -1264,6 +1325,8 @@
     }
     if ((cur->parent != NULL) && (cur->parent->childs == cur))
         cur->parent->childs = cur->next;
+    if ((cur->parent != NULL) && (cur->parent->last == cur))
+        cur->parent->last = cur->prev;
     if (cur->next != NULL)
         cur->next->prev = cur->prev;
     if (cur->prev != NULL)
@@ -1419,6 +1482,7 @@
     ret->next = NULL;
     ret->prev = NULL;
     ret->childs = NULL;
+    ret->last = NULL;
     ret->properties = NULL;
     if (node->name != NULL)
 	ret->name = xmlStrdup(node->name);
@@ -1469,6 +1533,7 @@
     }
     if (node->childs != NULL)
         ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
+    UPDATE_LAST_CHILD(ret);
     return(ret);
 }
 
@@ -1601,11 +1666,8 @@
     ret->standalone = doc->standalone;
     if (!recursive) return(ret);
 
-    if (doc->dtd != NULL)
-        ret->dtd = xmlCopyDtd(doc->dtd);
-    if (doc->entities != NULL)
-        ret->entities = (void *) xmlCopyEntitiesTable(
-	                    (xmlEntitiesTablePtr) doc->entities);
+    if (doc->intSubset != NULL)
+        ret->intSubset = xmlCopyDtd(doc->intSubset);
     if (doc->oldNs != NULL)
         ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
     if (doc->root != NULL)
@@ -1677,6 +1739,7 @@
 	    }
 	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
 	    cur->childs = xmlStringGetNodeList(cur->doc, content);
+	    UPDATE_LAST_CHILD(cur);
 	    break;
         case XML_ATTRIBUTE_NODE:
 	    break;
@@ -1688,6 +1751,7 @@
         case XML_COMMENT_NODE:
 	    if (cur->content != NULL) free(cur->content);
 	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
+	    cur->last = cur->childs = NULL;
 	    if (content != NULL)
 		cur->content = xmlStrdup(content);
 	    else 
@@ -1723,6 +1787,7 @@
 	    }
 	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
 	    cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
+	    UPDATE_LAST_CHILD(cur);
 	    break;
         case XML_ATTRIBUTE_NODE:
 	    break;
@@ -1734,6 +1799,7 @@
         case XML_COMMENT_NODE:
 	    if (cur->content != NULL) free(cur->content);
 	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
+	    cur->childs = cur->last = NULL;
 	    if (content != NULL)
 		cur->content = xmlStrndup(content, len);
 	    else 
@@ -1743,6 +1809,8 @@
 	    break;
         case XML_NOTATION_NODE:
 	    if (cur->content != NULL) free(cur->content);
+	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
+	    cur->childs = cur->last = NULL;
 	    if (content != NULL)
 		cur->content = xmlStrndup(content, len);
 	    else 
@@ -1772,24 +1840,22 @@
 	    xmlNodePtr last = NULL, new;
 
 	    if (cur->childs != NULL) {
-		last = cur->childs;
-		while (last->next != NULL) last = last->next;
+		last = cur->last;
 	    } else {
 	        if (cur->content != NULL) {
 		    cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
+		    UPDATE_LAST_CHILD(cur);
 		    free(cur->content);
 		    cur->content = NULL;
-		    if (cur->childs != NULL) {
-			last = cur->childs;
-			while (last->next != NULL) last = last->next;
-                    }
+		    last = cur->last;
 		}
 	    }
-	    new = xmlStringLenGetNodeList(cur->doc, content, len);
+	    new = xmlNewTextLen(content, len);
 	    if (new != NULL) {
 		xmlAddChild(cur, new);
-	        if ((last != NULL) && (last->next == new))
+	        if ((last != NULL) && (last->next == new)) {
 		    xmlTextMerge(last, new);
+		}
 	    }
 	    break;
 	}
@@ -1936,19 +2002,14 @@
  *
  * Search and get the value of an attribute associated to a node
  * This does the entity substitution.
- *
  * return values: the attribute value or NULL if not found.
  */
-const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
+CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
     xmlAttrPtr prop = node->properties;
 
     while (prop != NULL) {
-        if (!xmlStrcmp(prop->name, name)) {
-	    if (prop->val != NULL)
-		return(xmlNodeListGetString(node->doc, prop->val, 1));
-	    else
-	        return(xmlStrndup("", 1));
-	}
+        if (!xmlStrcmp(prop->name, name)) 
+	    return(xmlNodeListGetString(node->doc, prop->val, 1));
 	prop = prop->next;
     }
     return(NULL);
@@ -2188,10 +2249,10 @@
  */
 static void
 xmlDtdDump(xmlDocPtr doc) {
-    xmlDtdPtr cur = doc->dtd;
+    xmlDtdPtr cur = doc->intSubset;
 
     if (cur == NULL) {
-        fprintf(stderr, "xmlDtdDump : DTD == NULL\n");
+        fprintf(stderr, "xmlDtdDump : no internal subset\n");
 	return;
     }
     xmlBufferWriteChar("<!DOCTYPE ");
@@ -2207,15 +2268,13 @@
 	xmlBufferWriteCHAR(cur->SystemID);
 	xmlBufferWriteChar("\"");
     }
-    if ((cur->entities == NULL) && (doc->entities == NULL)) {
+    if (cur->entities == NULL) {
 	xmlBufferWriteChar(">\n");
 	return;
     }
     xmlBufferWriteChar(" [\n");
     if (cur->entities != NULL)
 	xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
-    if (doc->entities != NULL)
-	xmlDumpEntitiesTable((xmlEntitiesTablePtr) doc->entities);
     xmlBufferWriteChar("]");
 
     /* TODO !!! a lot more things to dump ... */
@@ -2239,13 +2298,13 @@
     }
     xmlBufferWriteChar(" ");
     xmlBufferWriteCHAR(cur->name);
-    xmlBufferWriteChar("=\"");
     value = xmlNodeListGetString(doc, cur->val, 0);
     if (value) {
+	xmlBufferWriteChar("=\"");
 	xmlBufferWriteCHAR(value);
+	xmlBufferWriteChar("\"");
 	free(value);
     }
-    xmlBufferWriteChar("\"");
 }
 
 /**
@@ -2401,7 +2460,7 @@
 	    break;
     }
     xmlBufferWriteChar("?>\n");
-    if ((cur->dtd != NULL) || (cur->entities != NULL))
+    if (cur->intSubset != NULL)
         xmlDtdDump(cur);
     if (cur->root != NULL) {
 	/* global namespace definitions, the old way */
@@ -2425,7 +2484,9 @@
 void
 xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
     if (cur == NULL) {
-        fprintf(stderr, "xmlDocDump : document == NULL\n");
+#ifdef DEBUG_TREE
+        fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
+#endif
 	*mem = NULL;
 	*size = 0;
 	return;
@@ -2501,7 +2562,9 @@
 void
 xmlDocDump(FILE *f, xmlDocPtr cur) {
     if (cur == NULL) {
+#ifdef DEBUG_TREE
         fprintf(stderr, "xmlDocDump : document == NULL\n");
+#endif
 	return;
     }
     buffer_index = 0;
diff --git a/tree.h b/tree.h
index 3921f7e..b6e26cf 100644
--- a/tree.h
+++ b/tree.h
@@ -4,7 +4,7 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
+ * Daniel.Veillard@w3.org
  */
 
 #ifndef __XML_TREE_H__
@@ -15,6 +15,8 @@
 extern "C" {
 #endif
 
+#include <stdio.h>
+
 /*
  * The different element types carried by an XML tree
  *
@@ -61,18 +63,51 @@
  * TODO !!!!
  */
 
+#define XML_ATTRIBUTE_NONE		1
+#define XML_ATTRIBUTE_REQUIRED		2
+#define XML_ATTRIBUTE_IMPLIED		3
+#define XML_ATTRIBUTE_FIXED		4
+
+#define XML_ATTRIBUTE_STRING		1
+#define XML_ATTRIBUTE_ID		2
+#define XML_ATTRIBUTE_IDREF		3
+#define XML_ATTRIBUTE_IDREFS		4
+#define XML_ATTRIBUTE_ENTITY		5
+#define XML_ATTRIBUTE_ENTITIES		6
+#define XML_ATTRIBUTE_NMTOKEN		7
+#define XML_ATTRIBUTE_NMTOKENS		8
+#define XML_ATTRIBUTE_ENUMERATED	9
+
 /*
  * a DTD Element definition.
  */
+#define XML_ELEMENT_CONTENT_PCDATA	1
+#define XML_ELEMENT_CONTENT_ELEMENT	2
+#define XML_ELEMENT_CONTENT_SEQ		3
+#define XML_ELEMENT_CONTENT_OR		4
+
+#define XML_ELEMENT_CONTENT_ONCE	1
+#define XML_ELEMENT_CONTENT_OPT		2
+#define XML_ELEMENT_CONTENT_MULT	3
+#define XML_ELEMENT_CONTENT_PLUS	4
+
+typedef struct xmlElementContent {
+    int            type;		/* PCDATA, ELEMENT, SEQ or OR */
+    int            ocur;		/* ONCE, OPT, MULT or PLUS */
+    const CHAR    *name;		/* Element name */
+    struct xmlElementContent *c1;	/* first child */
+    struct xmlElementContent *c2;	/* second child */
+} xmlElementContent, *xmlElementContentPtr;
+
 #define XML_ELEMENT_TYPE_EMPTY		1
 #define XML_ELEMENT_TYPE_ANY		2
 #define XML_ELEMENT_TYPE_MIXED		3
 #define XML_ELEMENT_TYPE_ELEMENT	4
 
 typedef struct xmlElement {
-    const CHAR    *name;	/* Element name */
-    int            type;	/* type (too simple, to extend ...) */
-    /* TODO !!! more needed */
+    const CHAR    *name;		/* Element name */
+    int            type;		/* The type */
+    xmlElementContentPtr content;	/* the allowed element content */
 } xmlElement, *xmlElementPtr;
 
 /*
@@ -132,6 +167,7 @@
     struct xmlNode *next;	/* next sibling link  */
     struct xmlNode *prev;	/* previous sibling link  */
     struct xmlNode *childs;	/* parent->childs link */
+    struct xmlNode *last;	/* last child link */
     struct xmlAttr *properties;	/* properties list */
     const CHAR     *name;       /* the name of the node, or the entity */
     xmlNs          *ns;         /* pointer to the associated namespace */
@@ -153,9 +189,9 @@
     const CHAR     *encoding;   /* encoding, if any */
     int             compression;/* level of zlib compression */
     int             standalone; /* standalone document (no external refs) */
-    struct xmlDtd  *dtd;	/* the document DTD if available */
+    struct xmlDtd  *intSubset;	/* the document internal subset */
+    struct xmlDtd  *extSubset;	/* the document external subset */
     struct xmlNs   *oldNs;	/* Global namespace, the old way */
-    void           *entities;   /* Hash table for general entities if any */
     struct xmlNode *root;	/* the document tree */
 } xmlDoc, *xmlDocPtr;
 
@@ -169,6 +205,8 @@
 /*
  * Creating/freeing new structures
  */
+extern xmlDtdPtr xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
+                    const CHAR *ExternalID, const CHAR *SystemID);
 extern xmlDtdPtr xmlNewDtd(xmlDocPtr doc, const CHAR *name,
                     const CHAR *ExternalID, const CHAR *SystemID);
 extern void xmlFreeDtd(xmlDtdPtr cur);
@@ -240,7 +278,7 @@
  */
 extern xmlAttrPtr xmlSetProp(xmlNodePtr node, const CHAR *name,
                              const CHAR *value);
-extern const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name);
+extern CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name);
 extern xmlNodePtr xmlStringGetNodeList(xmlDocPtr doc, const CHAR *value);
 extern xmlNodePtr xmlStringLenGetNodeList(xmlDocPtr doc, const CHAR *value,
                                           int len);
diff --git a/valid.c b/valid.c
new file mode 100644
index 0000000..215e463
--- /dev/null
+++ b/valid.c
@@ -0,0 +1,162 @@
+/*
+ * valid.c : part of the code use to do the DTD handling and the validity
+ *           checking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "valid.h"
+#include "parser.h"
+
+/****************************************************************
+ *								*
+ *	Util functions for data allocation/deallocation		*
+ *								*
+ ****************************************************************/
+
+/**
+ * xmlNewElementContent:
+ * @name:  the subelement name or NULL
+ * @type:  the type of element content decl
+ *
+ * Allocate an element content structure.
+ *
+ * return values: NULL if not, othervise the new element content structure
+ */
+xmlElementContentPtr
+xmlNewElementContent(CHAR *name, int type) {
+    xmlElementContentPtr ret;
+
+    switch(type) {
+	case XML_ELEMENT_CONTENT_ELEMENT:
+	    if (name == NULL) {
+	        fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
+	    }
+	    break;
+        case XML_ELEMENT_CONTENT_PCDATA:
+	case XML_ELEMENT_CONTENT_SEQ:
+	case XML_ELEMENT_CONTENT_OR:
+	    if (name != NULL) {
+	        fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
+	    }
+	    break;
+	default:
+	    fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
+	    exit(1);
+    }
+    ret = (xmlElementContentPtr) malloc(sizeof(xmlElementContent));
+    if (ret == NULL) {
+	fprintf(stderr, "xmlNewElementContent : out of memory!\n");
+	return(NULL);
+    }
+    ret->type = type;
+    ret->ocur = XML_ELEMENT_CONTENT_ONCE;
+    ret->name = xmlStrdup(name);
+    return(ret);
+}
+
+/**
+ * xmlNewElementContent:
+ * @name:  the subelement name or NULL
+ * @type:  the type of element content decl
+ *
+ * Free an element content structure. This is a recursive call !
+ */
+void
+xmlFreeElementContent(xmlElementContentPtr cur) {
+/* TODO !!! */
+}
+
+/****************************************************************
+ *								*
+ *	Registration of DTD declarations			*
+ *								*
+ ****************************************************************/
+
+
+/**
+ * xmlAddElementDecl:
+ * @name:  the entity name
+ *
+ * Register a new element declaration
+ *
+ * return values: NULL if not, othervise the entity
+ */
+xmlElementPtr
+xmlAddElementDecl(xmlDtdPtr dtd, char *name, int type, 
+                  xmlElementContentPtr content) {
+    xmlElementPtr ret;
+
+    if (dtd == NULL) {
+        fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
+	return(NULL);
+    }
+    if (name == NULL) {
+        fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
+	return(NULL);
+    }
+    switch (type) {
+        case XML_ELEMENT_TYPE_EMPTY:
+	    if (content != NULL) {
+	        fprintf(stderr,
+		        "xmlAddElementDecl: content != NULL for EMPTY\n");
+		return(NULL);
+	    }
+	    break;
+	case XML_ELEMENT_TYPE_ANY:
+	    if (content != NULL) {
+	        fprintf(stderr,
+		        "xmlAddElementDecl: content != NULL for ANY\n");
+		return(NULL);
+	    }
+	    break;
+	case XML_ELEMENT_TYPE_MIXED:
+	    if (content == NULL) {
+	        fprintf(stderr,
+		        "xmlAddElementDecl: content == NULL for MIXED\n");
+		return(NULL);
+	    }
+	    break;
+	case XML_ELEMENT_TYPE_ELEMENT:
+	    if (content == NULL) {
+	        fprintf(stderr,
+		        "xmlAddElementDecl: content == NULL for ELEMENT\n");
+		return(NULL);
+	    }
+	    break;
+	default:
+	    fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
+	    return(NULL);
+    }
+
+    /*
+     * Validity Check:
+     * Search the DTD for previous declarations of the ELEMENT
+     */
+    /* TODO */
+
+    /*
+     * Create and fill the structure.
+     */
+    ret = (xmlElementPtr) malloc(sizeof(xmlElement));
+    if (ret == NULL) {
+        fprintf(stderr, "xmlAddElementDecl: out of memory\n");
+	return(NULL);
+    }
+    ret->type = type;
+    ret->name = xmlStrdup(name);
+    ret->content = content;
+
+    /*
+     * Insert the structure in the DTD Element table
+     */
+    /* TODO */
+
+    return(ret);
+}
+
diff --git a/valid.h b/valid.h
new file mode 100644
index 0000000..d6765ff
--- /dev/null
+++ b/valid.h
@@ -0,0 +1,18 @@
+/*
+ * valid.h : interface to the DTD handling and the validity checking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+
+#ifndef __XML_VALID_H__
+#define __XML_VALID_H__
+#include "tree.h"
+
+extern xmlElementPtr xmlAddElementDecl(xmlDtdPtr dtd, char *name, int type, 
+                                       xmlElementContentPtr content);
+extern xmlElementContentPtr xmlNewElementContent(CHAR *name, int type);
+extern void xmlFreeElementContent(xmlElementContentPtr cur);
+#endif /* __XML_VALID_H__ */