Completed/revamped the SAX support, removed old namespace suppport, Daniel
diff --git a/SAX.c b/SAX.c
index b4a6cb1..7f9ea18 100644
--- a/SAX.c
+++ b/SAX.c
@@ -10,6 +10,8 @@
 #include <stdlib.h>
 #include "tree.h"
 #include "parser.h"
+#include "parserInternals.h"
+#include "valid.h"
 #include "entities.h"
 #include "xml-error.h"
 
@@ -81,6 +83,65 @@
 };
 
 /**
+ * isStandalone:
+ * @ctxt:  An XML parser context
+ *
+ * Is this document tagged standalone ?
+ *
+ * Returns 1 if true
+ */
+int
+isStandalone(xmlParserCtxtPtr ctxt)
+{
+    return(ctxt->myDoc->standalone == 1);
+}
+
+/**
+ * hasInternalSubset:
+ * @ctxt:  An XML parser context
+ *
+ * Does this document has an internal subset
+ *
+ * Returns 1 if true
+ */
+int
+hasInternalSubset(xmlParserCtxtPtr ctxt)
+{
+    return(ctxt->myDoc->intSubset != NULL);
+}
+
+/**
+ * hasExternalSubset:
+ * @ctxt:  An XML parser context
+ *
+ * Does this document has an external subset
+ *
+ * Returns 1 if true
+ */
+int
+hasExternalSubset(xmlParserCtxtPtr ctxt)
+{
+    return(ctxt->myDoc->extSubset != NULL);
+}
+
+/**
+ * hasInternalSubset:
+ * @ctxt:  An XML parser context
+ *
+ * Does this document has an internal subset
+ */
+void
+internalSubset(xmlParserCtxtPtr ctxt, const CHAR *name,
+	       const CHAR *ExternalID, const CHAR *SystemID)
+{
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.internalSubset(%s, %s, %s)\n",
+            name, ExternalID, SystemID);
+#endif
+    xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
+}
+
+/**
  * resolveEntity:
  * @ctxt:  An XML parser context
  * @publicId: The public ID of the entity
@@ -102,10 +163,107 @@
     fprintf(stderr, "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
 #endif
 
+    /*
+     * TODO : not 100% sure that the appropriate handling in that case.
+     */
     return(NULL);
 }
 
 /**
+ * getEntity:
+ * @ctxt:  An XML parser context
+ * @name: The entity name
+ *
+ * Get an entity by name
+ *
+ * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
+ */
+xmlEntityPtr
+getEntity(xmlParserCtxtPtr ctxt, const CHAR *name)
+{
+    xmlEntityPtr ret;
+
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.getEntity(%s)\n", name);
+#endif
+
+    ret = xmlGetDocEntity(ctxt->myDoc, name);
+    return(ret);
+}
+
+
+/**
+ * entityDecl:
+ * @ctxt:  An XML parser context
+ * @name:  the entity name 
+ * @type:  the entity type 
+ * @publicId: The public ID of the entity
+ * @systemId: The system ID of the entity
+ * @content: the entity value (without processing).
+ *
+ * An entity definition has been parsed
+ */
+void
+entityDecl(xmlParserCtxtPtr ctxt, const CHAR *name, int type,
+          const CHAR *publicId, const CHAR *systemId, CHAR *content)
+{
+
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
+            name, type, publicId, systemId, content);
+#endif
+    xmlAddDocEntity(ctxt->myDoc, name, type, publicId, systemId, content);
+}
+
+/**
+ * attributeDecl:
+ * @ctxt:  An XML parser context
+ * @name:  the attribute name 
+ * @type:  the attribute type 
+ * @publicId: The public ID of the attribute
+ * @systemId: The system ID of the attribute
+ * @content: the attribute value (without processing).
+ *
+ * An attribute definition has been parsed
+ */
+void
+attributeDecl(xmlParserCtxtPtr ctxt, const CHAR *elem, const CHAR *name,
+              int type, int def, const CHAR *defaultValue,
+	      xmlEnumerationPtr tree)
+{
+
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
+            elem, name, type, def, defaultValue);
+#endif
+    xmlAddAttributeDecl(ctxt->myDoc->intSubset, elem, name, type, def,
+                        defaultValue, tree);
+}
+
+/**
+ * elementDecl:
+ * @ctxt:  An XML parser context
+ * @name:  the element name 
+ * @type:  the element type 
+ * @publicId: The public ID of the element
+ * @systemId: The system ID of the element
+ * @content: the element value (without processing).
+ *
+ * An element definition has been parsed
+ */
+void
+elementDecl(xmlParserCtxtPtr ctxt, const CHAR *name, int type,
+	    xmlElementContentPtr content)
+{
+
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.elementDecl(%s, %d, ...)\n",
+            name, type);
+#endif
+    xmlAddElementDecl(ctxt->myDoc->intSubset, name, type, content);
+}
+
+/**
  * notationDecl:
  * @ctxt:  An XML parser context
  * @name: The name of the notation
@@ -122,6 +280,7 @@
 #ifdef DEBUG_SAX
     fprintf(stderr, "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
 #endif
+    xmlAddNotationDecl(ctxt->myDoc->intSubset, name, publicId, systemId);
 }
 
 /**
@@ -171,9 +330,19 @@
 void
 startDocument(xmlParserCtxtPtr ctxt)
 {
+    xmlDocPtr doc;
+
 #ifdef DEBUG_SAX
     fprintf(stderr, "SAX.startDocument()\n");
 #endif
+    doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
+    if (doc != NULL) {
+	if (ctxt->encoding != NULL)
+	    doc->encoding = xmlStrdup(ctxt->encoding);
+	else
+	    doc->encoding = NULL;
+	doc->standalone = ctxt->standalone;
+    }
 }
 
 /**
@@ -191,19 +360,151 @@
 }
 
 /**
+ * attribute:
+ * @ctxt:  An XML parser context
+ * @name:  The attribute name
+ * @value:  The attribute value
+ *
+ * Handle an attribute that has been read by the parser.
+ * The default handling is to convert the attribute into an
+ * DOM subtree and past it in a new xmlAttr element added to
+ * the element.
+ */
+void
+attribute(xmlParserCtxtPtr ctxt, const CHAR *fullname, const CHAR *value)
+{
+    xmlAttrPtr ret;
+    CHAR *name;
+    CHAR *ns;
+
+/****************
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.attribute(%s, %s)\n", fullname, value);
+#endif
+ ****************/
+    /*
+     * Split the full name into a namespace prefix and the tag name
+     */
+    name = xmlSplitQName(fullname, &ns);
+
+    /*
+     * Check whether it's a namespace definition
+     */
+    if ((ns == NULL) &&
+        (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
+        (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
+	/* a default namespace definition */
+	xmlNewNs(ctxt->node, value, NULL);
+	if (name != NULL) 
+	    free(name);
+	return;
+    }
+    if ((ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
+        (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
+	/* a standard namespace definition */
+	xmlNewNs(ctxt->node, value, name);
+	free(ns);
+	if (name != NULL) 
+	    free(name);
+	return;
+    }
+
+    ret = xmlNewProp(ctxt->node, name, NULL);
+    if (ret != NULL)
+	ret->val = xmlStringGetNodeList(ctxt->myDoc, value);
+    if (name != NULL) 
+	free(name);
+    if (ns != NULL) 
+	free(ns);
+}
+
+/**
  * startElement:
  * @ctxt:  An XML parser context
  * @name:  The element name
+ * @atts:  An array of name/value attributes pairs, NULL terminated
  *
  * called when an opening tag has been processed.
  * TODO We currently have a small pblm with the arguments ...
  */
 void
-startElement(xmlParserCtxtPtr ctxt, const CHAR *name)
+startElement(xmlParserCtxtPtr ctxt, const CHAR *fullname, const CHAR **atts)
 {
+    xmlNodePtr ret;
+    xmlNodePtr parent = ctxt->node;
+    xmlNsPtr ns;
+    CHAR *name;
+    CHAR *prefix;
+    const CHAR *att;
+    const CHAR *value;
+
+    int i;
+
 #ifdef DEBUG_SAX
-    fprintf(stderr, "SAX.startElement(%s)\n", name);
+    fprintf(stderr, "SAX.startElement(%s)\n", fullname);
 #endif
+    /*
+     * Split the full name into a namespace prefix and the tag name
+     */
+    name = xmlSplitQName(fullname, &prefix);
+
+
+    /*
+     * Note : the namespace resolution is deferred until the end of the
+     *        attributes parsing, since local namespace can be defined as
+     *        an attribute at this level.
+     */
+    ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
+    if (ret == NULL) return;
+    if (ctxt->myDoc->root == NULL)
+        ctxt->myDoc->root = ret;
+
+    /*
+     * We are parsing a new node.
+     */
+    nodePush(ctxt, ret);
+
+    /*
+     * Link the child element
+     */
+    if (parent != NULL)
+	xmlAddChild(parent, ctxt->node);
+
+    /*
+     * process all the attributes.
+     */
+    if (atts != NULL) {
+        i = 0;
+	att = atts[i++];
+	value = atts[i++];
+        while ((att != NULL) && (value != NULL)) {
+	    /*
+	     * Handle one pair of attribute/value
+	     */
+	    attribute(ctxt, att, value);
+
+	    /*
+	     * Next ones
+	     */
+	    att = atts[i++];
+	    value = atts[i++];
+	}
+    }
+
+    /*
+     * Search the namespace, note that since the attributes have been
+     * processed, the local namespaces are available.
+     */
+    ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
+    if ((ns == NULL) && (parent != NULL))
+	ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
+    xmlSetNs(ret, ns);
+
+    if (prefix != NULL)
+	free(prefix);
+    if (name != NULL)
+	free(name);
+
 }
 
 /**
@@ -216,47 +517,65 @@
 void
 endElement(xmlParserCtxtPtr ctxt, const CHAR *name)
 {
+    xmlParserNodeInfo node_info;
+    xmlNodePtr cur = ctxt->node;
+
 #ifdef DEBUG_SAX
-    fprintf(stderr, "SAX.endElement(%s)\n", name);
+    if (name == NULL)
+        fprintf(stderr, "SAX.endElement(NULL)\n");
+    else
+	fprintf(stderr, "SAX.endElement(%s)\n", name);
 #endif
+    
+    /* Capture end position and add node */
+    if (cur != NULL && ctxt->record_info) {
+      node_info.end_pos = ctxt->input->cur - ctxt->input->base;
+      node_info.end_line = ctxt->input->line;
+      node_info.node = cur;
+      xmlParserAddNodeInfo(ctxt, &node_info);
+    }
+
+    /*
+     * end of parsing of this node.
+     */
+    nodePop(ctxt);
 }
 
 /**
- * attribute:
+ * reference:
  * @ctxt:  An XML parser context
- * @name:  The attribute name
- * @value:  The attribute value
+ * @name:  The entity name
  *
- * called when an attribute has been read by the parser.
- * The default handling is to convert the attribute into an
- * DOM subtree and past it in a new xmlAttr element added to
- * the element.
+ * called when an entity reference is detected. 
  */
 void
-attribute(xmlParserCtxtPtr ctxt, const CHAR *name, const CHAR *value)
+reference(xmlParserCtxtPtr ctxt, const CHAR *name)
 {
+    xmlNodePtr ret;
+
 #ifdef DEBUG_SAX
-    fprintf(stderr, "SAX.attribute(%s, %s)\n", name, value);
+    fprintf(stderr, "SAX.reference(%s)\n", name);
 #endif
+    ret = xmlNewReference(ctxt->myDoc, name);
+    xmlAddChild(ctxt->node, ret);
 }
 
 /**
  * characters:
  * @ctxt:  An XML parser context
  * @ch:  a CHAR string
- * @start: the first char in the string
  * @len: the number of CHAR
  *
  * receiving some chars from the parser.
  * Question: how much at a time ???
  */
 void
-characters(xmlParserCtxtPtr ctxt, const CHAR *ch, int start, int len)
+characters(xmlParserCtxtPtr ctxt, const CHAR *ch, int len)
 {
     xmlNodePtr lastChild;
 
 #ifdef DEBUG_SAX
-    fprintf(stderr, "SAX.characters(%.30s, %d, %d)\n", ch, start, len);
+    fprintf(stderr, "SAX.characters(%.30s, %d)\n", ch, len);
 #endif
     /*
      * Handle the data if any. If there is no child
@@ -266,12 +585,12 @@
 
     lastChild = xmlGetLastChild(ctxt->node);
     if (lastChild == NULL)
-	xmlNodeAddContentLen(ctxt->node, &ch[start], len);
+	xmlNodeAddContentLen(ctxt->node, ch, len);
     else {
 	if (xmlNodeIsText(lastChild))
-	    xmlTextConcat(lastChild, &ch[start], len);
+	    xmlTextConcat(lastChild, ch, len);
 	else {
-	    lastChild = xmlNewTextLen(&ch[start], len);
+	    lastChild = xmlNewTextLen(ch, len);
 	    xmlAddChild(ctxt->node, lastChild);
 	}
     }
@@ -281,17 +600,16 @@
  * ignorableWhitespace:
  * @ctxt:  An XML parser context
  * @ch:  a CHAR string
- * @start: the first char in the string
  * @len: the number of CHAR
  *
  * receiving some ignorable whitespaces from the parser.
  * Question: how much at a time ???
  */
 void
-ignorableWhitespace(xmlParserCtxtPtr ctxt, const CHAR *ch, int start, int len)
+ignorableWhitespace(xmlParserCtxtPtr ctxt, const CHAR *ch, int len)
 {
 #ifdef DEBUG_SAX
-    fprintf(stderr, "SAX.ignorableWhitespace(%.30s, %d, %d)\n", ch, start, len);
+    fprintf(stderr, "SAX.ignorableWhitespace(%.30s, %d)\n", ch, len);
 #endif
 }
 
@@ -313,19 +631,173 @@
 #endif
 }
 
+/**
+ * globalNamespace:
+ * @ctxt:  An XML parser context
+ * @href:  the namespace associated URN
+ * @prefix: the namespace prefix
+ *
+ * An old global namespace has been parsed.
+ */
+void
+globalNamespace(xmlParserCtxtPtr ctxt, const CHAR *href, const CHAR *prefix)
+{
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.globalNamespace(%s, %s)\n", href, prefix);
+#endif
+    xmlNewGlobalNs(ctxt->myDoc, href, prefix);
+}
+
+/**
+ * setNamespace:
+ * @ctxt:  An XML parser context
+ * @name:  the namespace prefix
+ *
+ * Set the current element namespace.
+ */
+void
+setNamespace(xmlParserCtxtPtr ctxt, const CHAR *name)
+{
+    xmlNsPtr ns;
+    xmlNodePtr parent;
+
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.setNamespace(%s)\n", name);
+#endif
+    ns = xmlSearchNs(ctxt->myDoc, ctxt->node, name);
+    if (ns == NULL) { /* ctxt->node may not have a parent yet ! */
+        if (ctxt->nodeNr >= 2) {
+	    parent = ctxt->nodeTab[ctxt->nodeNr - 2];
+	    if (parent != NULL)
+		ns = xmlSearchNs(ctxt->myDoc, parent, name);
+	}
+    }
+    xmlSetNs(ctxt->node, ns);
+}
+
+/**
+ * getNamespace:
+ * @ctxt:  An XML parser context
+ *
+ * Get the current element namespace.
+ */
+xmlNsPtr
+getNamespace(xmlParserCtxtPtr ctxt)
+{
+    xmlNsPtr ret;
+
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.getNamespace()\n");
+#endif
+    ret = ctxt->node->ns;
+    return(ret);
+}
+
+/**
+ * checkNamespace:
+ * @ctxt:  An XML parser context
+ * @namespace: the namespace to check against
+ *
+ * Check that the current element namespace is the same as the
+ * one read upon parsing.
+ */
+int
+checkNamespace(xmlParserCtxtPtr ctxt, CHAR *namespace)
+{
+    xmlNodePtr cur = ctxt->node;
+
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.checkNamespace(%s)\n", namespace);
+#endif
+
+    /*
+     * Check that the Name in the ETag is the same as in the STag.
+     */
+    if (namespace == NULL) {
+        if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		 "End tags for %s don't hold the namespace %s\n",
+		                 cur->name, cur->ns->prefix);
+	    ctxt->wellFormed = 0;
+	}
+    } else {
+        if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		 "End tags %s holds a prefix %s not used by the open tag\n",
+		                 cur->name, namespace);
+	    ctxt->wellFormed = 0;
+	} else if (strcmp(namespace, cur->ns->prefix)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+    "Start and End tags for %s don't use the same namespaces: %s and %s\n",
+	                         cur->name, cur->ns->prefix, namespace);
+	    ctxt->wellFormed = 0;
+	} else
+	    return(1);
+    }
+    return(0);
+}
+
+/**
+ * namespaceDecl:
+ * @ctxt:  An XML parser context
+ * @href:  the namespace associated URN
+ * @prefix: the namespace prefix
+ *
+ * A namespace has been parsed.
+ */
+void
+namespaceDecl(xmlParserCtxtPtr ctxt, const CHAR *href, const CHAR *prefix)
+{
+#ifdef DEBUG_SAX
+    if (prefix == NULL)
+	fprintf(stderr, "SAX.namespaceDecl(%s, NULL)\n", href);
+    else
+	fprintf(stderr, "SAX.namespaceDecl(%s, %s)\n", href, prefix);
+#endif
+    xmlNewNs(ctxt->node, href, prefix);
+}
+
+/**
+ * comment:
+ * @ctxt:  An XML parser context
+ * @value:  the comment content
+ *
+ * A comment has been parsed.
+ */
+void
+comment(xmlParserCtxtPtr ctxt, const CHAR *value)
+{
+#ifdef DEBUG_SAX
+    fprintf(stderr, "SAX.comment(%s)\n", value);
+#endif
+    xmlNewDocComment(ctxt->myDoc, value);
+}
+
 xmlSAXHandler xmlDefaultSAXHandler = {
+    internalSubset,
+    isStandalone,
+    hasInternalSubset,
+    hasExternalSubset,
     resolveEntity,
+    getEntity,
+    entityDecl,
     notationDecl,
+    attributeDecl,
+    elementDecl,
     unparsedEntityDecl,
     setDocumentLocator,
     startDocument,
     endDocument,
     startElement,
     endElement,
-    attribute,
+    reference,
     characters,
     ignorableWhitespace,
     processingInstruction,
+    comment,
     xmlParserWarning,
     xmlParserError,
     xmlParserError,
@@ -339,7 +811,15 @@
 void
 xmlDefaultSAXHandlerInit(void)
 {
+    xmlDefaultSAXHandler.internalSubset = internalSubset;
+    xmlDefaultSAXHandler.isStandalone = isStandalone;
+    xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
+    xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
     xmlDefaultSAXHandler.resolveEntity = resolveEntity;
+    xmlDefaultSAXHandler.getEntity = getEntity;
+    xmlDefaultSAXHandler.entityDecl = entityDecl;
+    xmlDefaultSAXHandler.attributeDecl = attributeDecl;
+    xmlDefaultSAXHandler.elementDecl = elementDecl;
     xmlDefaultSAXHandler.notationDecl = notationDecl;
     xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
     xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
@@ -347,10 +827,11 @@
     xmlDefaultSAXHandler.endDocument = endDocument;
     xmlDefaultSAXHandler.startElement = startElement;
     xmlDefaultSAXHandler.endElement = endElement;
-    xmlDefaultSAXHandler.attribute = attribute;
+    xmlDefaultSAXHandler.reference = reference;
     xmlDefaultSAXHandler.characters = characters;
     xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
     xmlDefaultSAXHandler.processingInstruction = processingInstruction;
+    xmlDefaultSAXHandler.comment = comment;
     xmlDefaultSAXHandler.warning = xmlParserWarning;
     xmlDefaultSAXHandler.error = xmlParserError;
     xmlDefaultSAXHandler.fatalError = xmlParserError;