fixed bug #92518 validation error were not covering namespace

* SAX.c valid.c include/libxml/valid.h: fixed bug #92518 validation
  error were not covering namespace declarations.
* result/valid/dia.xml test/valid/dia.xml: the test wasn't valid,
  it was missing the attribute declaration for the namespace
* result/VC/NS3: the fix now report breakages in that test
Daniel
diff --git a/ChangeLog b/ChangeLog
index 77e68ed..441a0a1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Thu Sep 26 17:33:46 CEST 2002 Daniel Veillard <daniel@veillard.com>
+
+	* SAX.c valid.c include/libxml/valid.h: fixed bug #92518 validation
+	  error were not covering namespace declarations.
+	* result/valid/dia.xml test/valid/dia.xml: the test wasn't valid,
+	  it was missing the attribute declaration for the namespace
+	* result/VC/NS3: the fix now report breakages in that test
+
 Thu Sep 26 14:39:07 CEST 2002 Daniel Veillard <daniel@veillard.com>
 
 	* HTMLtree.c: fixing bug #94241 on HTML boolean attributes
diff --git a/SAX.c b/SAX.c
index 9cf06a0..c8452eb 100644
--- a/SAX.c
+++ b/SAX.c
@@ -795,18 +795,20 @@
 }
 
 /**
- * attribute:
+ * my_attribute:
  * @ctx: the user data (XML parser context)
  * @fullname:  The attribute name, including namespace prefix
  * @value:  The attribute value
+ * @prefix: the prefix on the element node
  *
  * 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(void *ctx, const xmlChar *fullname, const xmlChar *value)
+static void
+my_attribute(void *ctx, const xmlChar *fullname, const xmlChar *value,
+	     const xmlChar *prefix)
 {
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
     xmlAttrPtr ret;
@@ -847,6 +849,8 @@
     if ((!ctxt->html) && (ns == NULL) &&
         (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
         (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
+	xmlNsPtr nsret;
+
 	if (value[0] != 0) {
 	    xmlURIPtr uri;
 
@@ -866,7 +870,16 @@
 	}
 
 	/* a default namespace definition */
-	xmlNewNs(ctxt->node, value, NULL);
+	nsret = xmlNewNs(ctxt->node, value, NULL);
+
+	/*
+	 * Validate also for namespace decls, they are attributes from
+	 * an XML-1.0 perspective
+	 */
+        if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
+	    ctxt->myDoc && ctxt->myDoc->intSubset)
+	    ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
+					   ctxt->node, prefix, nsret, value);
 	if (name != NULL) 
 	    xmlFree(name);
 	if (nval != NULL)
@@ -876,23 +889,24 @@
     if ((!ctxt->html) &&
 	(ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
         (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
-	/*
-	 * Validate also for namespace decls, they are attributes from
-	 * an XML-1.0 perspective
-	 TODO ... doesn't map well with current API
-        if (ctxt->validate && ctxt->wellFormed &&
-	    ctxt->myDoc && ctxt->myDoc->intSubset)
-	    ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
-					       ctxt->node, ret, value);
-	 */
+	xmlNsPtr nsret;
+
 	if (value[0] == 0) {
 	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 		ctxt->sax->error(ctxt->userData, 
 		     "Empty namespace name for prefix %s\n", name);
 	}
 	/* a standard namespace definition */
-	xmlNewNs(ctxt->node, value, name);
+	nsret = xmlNewNs(ctxt->node, value, name);
 	xmlFree(ns);
+	/*
+	 * Validate also for namespace decls, they are attributes from
+	 * an XML-1.0 perspective
+	 */
+        if (nsret != NULL && ctxt->validate && ctxt->wellFormed &&
+	    ctxt->myDoc && ctxt->myDoc->intSubset)
+	    ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc,
+					   ctxt->node, prefix, nsret, value);
 	if (name != NULL) 
 	    xmlFree(name);
 	if (nval != NULL)
@@ -988,6 +1002,23 @@
 	xmlFree(ns);
 }
 
+/**
+ * attribute:
+ * @ctx: the user data (XML parser context)
+ * @fullname:  The attribute name, including namespace prefix
+ * @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(void *ctx, const xmlChar *fullname, const xmlChar *value)
+{
+    my_attribute(ctx, fullname, value, NULL);
+}
+
 /*
  * xmlCheckDefaultedAttributes:
  *
@@ -1256,7 +1287,7 @@
 	    while ((att != NULL) && (value != NULL)) {
 		if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l') &&
 		    (att[3] == 'n') && (att[4] == 's'))
-		    attribute(ctxt, att, value);
+		    my_attribute(ctxt, att, value, prefix);
 
 		att = atts[i++];
 		value = atts[i++];
diff --git a/include/libxml/valid.h b/include/libxml/valid.h
index 5535dd9..4cc5f97 100644
--- a/include/libxml/valid.h
+++ b/include/libxml/valid.h
@@ -264,6 +264,12 @@
 					 xmlNodePtr	elem,
 					 xmlAttrPtr attr,
 					 const xmlChar *value);
+int		xmlValidateOneNamespace	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 xmlNodePtr elem,
+					 const xmlChar *prefix,
+					 xmlNsPtr ns,
+					 const xmlChar *value);
 int		xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,
 					 xmlDocPtr doc);
 int		xmlValidateNotationUse	(xmlValidCtxtPtr ctxt,
diff --git a/result/VC/NS3 b/result/VC/NS3
index 3e8cb74..4868dc5 100644
--- a/result/VC/NS3
+++ b/result/VC/NS3
@@ -1,3 +1,9 @@
+./test/VC/NS3:9: validity error: Value for attribute xmlns of foo is different from default "http://example.com/fooo"
+xmlns="http://example.com/foo" xmlns:foo="http://example.com/fo" foo:info="toto
+                                                                              ^
+./test/VC/NS3:9: validity error: Value for attribute xmlns of foo must be "http://example.com/fooo"
+xmlns="http://example.com/foo" xmlns:foo="http://example.com/fo" foo:info="toto
+                                                                              ^
 ./test/VC/NS3:9: validity error: Element foo namespace name for default namespace does not match the DTD
 mlns="http://example.com/foo" xmlns:foo="http://example.com/fo" foo:info="toto"
                                                                               ^
diff --git a/result/valid/dia.xml b/result/valid/dia.xml
index 12282be..01e3253 100644
--- a/result/valid/dia.xml
+++ b/result/valid/dia.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0"?>
 <!DOCTYPE dia:diagram [
 <!ELEMENT dia:diagram (dia:diagramdata , dia:layer*)>
+<!ATTLIST dia:diagram xmlns:dia CDATA #FIXED "http://www.lysator.liu.se/~alla/dia/">
 <!ELEMENT dia:diagramdata (dia:attribute)*>
 <!ELEMENT dia:layer (dia:object | dia:group)*>
 <!ATTLIST dia:layer dia:name CDATA #REQUIRED>
diff --git a/test/valid/dia.xml b/test/valid/dia.xml
index b6441ab..3ab3d06 100644
--- a/test/valid/dia.xml
+++ b/test/valid/dia.xml
@@ -1,6 +1,9 @@
 <?xml version="1.0"?>
 <!DOCTYPE dia:diagram [
 <!ELEMENT dia:diagram (dia:diagramdata, (dia:layer)*) >
+<!ATTLIST dia:diagram
+          xmlns:dia CDATA #FIXED "http://www.lysator.liu.se/~alla/dia/">
+          
 
 <!ELEMENT dia:diagramdata (dia:attribute)* >
 
diff --git a/valid.c b/valid.c
index 9ebdbf5..58ab756 100644
--- a/valid.c
+++ b/valid.c
@@ -3817,6 +3817,232 @@
     return(ret);
 }
 
+/**
+ * xmlValidateOneNamespace:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element instance
+ * @ns:  an namespace declaration instance
+ * @value:  the attribute value (without entities processing)
+ *
+ * Try to validate a single namespace declaration for an element
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Attribute Value Type ]
+ *  - [ VC: Fixed Attribute Default ]
+ *  - [ VC: Entity Name ]
+ *  - [ VC: Name Token ]
+ *  - [ VC: ID ]
+ *  - [ VC: IDREF ]
+ *  - [ VC: Entity Name ]
+ *  - [ VC: Notation Attributes ]
+ *
+ * The ID/IDREF uniqueness and matching are done separately
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
+    /* xmlElementPtr elemDecl; */
+    xmlAttributePtr attrDecl =  NULL;
+    int val;
+    int ret = 1;
+
+    CHECK_DTD;
+    if ((elem == NULL) || (elem->name == NULL)) return(0);
+    if ((ns == NULL) || (ns->href == NULL)) return(0);
+
+    if (prefix != NULL) {
+	xmlChar qname[500];
+	snprintf((char *) qname, sizeof(qname), "%s:%s",
+		 prefix, elem->name);
+        qname[sizeof(qname) - 1] = 0;
+	if (ns->prefix != NULL) {
+	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
+		                          ns->prefix, BAD_CAST "xmlns");
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
+					  ns->prefix, BAD_CAST "xmlns");
+	} else {
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname,
+		                         BAD_CAST "xmlns");
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname,
+			                 BAD_CAST "xmlns");
+	}
+    }
+    if (attrDecl == NULL) {
+	if (ns->prefix != NULL) {
+	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
+		                          ns->prefix, BAD_CAST "xmlns");
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
+					      ns->prefix, BAD_CAST "xmlns");
+	} else {
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
+		                         elem->name, BAD_CAST "xmlns");
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
+					     elem->name, BAD_CAST "xmlns");
+	}
+    }
+
+
+    /* Validity Constraint: Attribute Value Type */
+    if (attrDecl == NULL) {
+	VECTXT(ctxt, elem);
+	if (ns->prefix != NULL) {
+	    VERROR(ctxt->userData,
+		   "No declaration for attribute xmlns:%s of element %s\n",
+		   ns->prefix, elem->name);
+	} else {
+	    VERROR(ctxt->userData,
+		   "No declaration for attribute xmlns of element %s\n",
+		   elem->name);
+	}
+	return(0);
+    }
+
+    val = xmlValidateAttributeValue(attrDecl->atype, value);
+    if (val == 0) {
+	VECTXT(ctxt, elem);
+	if (ns->prefix != NULL) {
+	    VERROR(ctxt->userData,
+	       "Syntax of value for attribute xmlns:%s of %s is not valid\n",
+		   ns->prefix, elem->name);
+	} else {
+	    VERROR(ctxt->userData,
+	       "Syntax of value for attribute xmlns of %s is not valid\n",
+		   elem->name);
+	}
+        ret = 0;
+    }
+
+    /* Validity constraint: Fixed Attribute Default */
+    if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
+	if (!xmlStrEqual(value, attrDecl->defaultValue)) {
+	    VECTXT(ctxt, elem);
+	    if (ns->prefix != NULL) {
+		VERROR(ctxt->userData,
+       "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
+		       ns->prefix, elem->name, attrDecl->defaultValue);
+	    } else {
+		VERROR(ctxt->userData,
+       "Value for attribute xmlns of %s is different from default \"%s\"\n",
+		       elem->name, attrDecl->defaultValue);
+	    }
+	    ret = 0;
+	}
+    }
+
+    /* Validity Constraint: ID uniqueness */
+    if (attrDecl->atype == XML_ATTRIBUTE_ID) {
+        if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
+	    ret = 0;
+    }
+
+    if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
+	(attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
+        if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
+	    ret = 0;
+    }
+
+    /* Validity Constraint: Notation Attributes */
+    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
+        xmlEnumerationPtr tree = attrDecl->tree;
+        xmlNotationPtr nota;
+
+        /* First check that the given NOTATION was declared */
+	nota = xmlGetDtdNotationDesc(doc->intSubset, value);
+	if (nota == NULL)
+	    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
+	
+	if (nota == NULL) {
+	    VECTXT(ctxt, elem);
+	    if (ns->prefix != NULL) {
+		VERROR(ctxt->userData,
+       "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
+		       value, ns->prefix, elem->name);
+	    } else {
+		VERROR(ctxt->userData,
+       "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
+		       value, elem->name);
+	    }
+	    ret = 0;
+        }
+
+	/* Second, verify that it's among the list */
+	while (tree != NULL) {
+	    if (xmlStrEqual(tree->name, value)) break;
+	    tree = tree->next;
+	}
+	if (tree == NULL) {
+	    VECTXT(ctxt, elem);
+	    if (ns->prefix != NULL) {
+		VERROR(ctxt->userData,
+"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
+		       value, ns->prefix, elem->name);
+	    } else {
+		VERROR(ctxt->userData,
+"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
+		       value, elem->name);
+	    }
+	    ret = 0;
+	}
+    }
+
+    /* Validity Constraint: Enumeration */
+    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
+        xmlEnumerationPtr tree = attrDecl->tree;
+	while (tree != NULL) {
+	    if (xmlStrEqual(tree->name, value)) break;
+	    tree = tree->next;
+	}
+	if (tree == NULL) {
+	    VECTXT(ctxt, elem);
+	    if (ns->prefix != NULL) {
+		VERROR(ctxt->userData,
+"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
+		       value, ns->prefix, elem->name);
+	    } else {
+		VERROR(ctxt->userData,
+"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
+		       value, elem->name);
+	    }
+	    ret = 0;
+	}
+    }
+
+    /* Fixed Attribute Default */
+    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
+        (!xmlStrEqual(attrDecl->defaultValue, value))) {
+	VECTXT(ctxt, elem);
+	if (ns->prefix != NULL) {
+	    VERROR(ctxt->userData,
+		   "Value for attribute xmlns:%s of %s must be \"%s\"\n",
+		   ns->prefix, elem->name, attrDecl->defaultValue);
+	} else {
+	    VERROR(ctxt->userData,
+		   "Value for attribute xmlns of %s must be \"%s\"\n",
+		   elem->name, attrDecl->defaultValue);
+	}
+        ret = 0;
+    }
+
+    /* Extra check for the attribute value */
+    if (ns->prefix != NULL) {
+	ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
+					  attrDecl->atype, value);
+    } else {
+	ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
+					  attrDecl->atype, value);
+    }
+
+    return(ret);
+}
+
 #ifndef  LIBXML_REGEXP_ENABLED
 /**
  * xmlValidateSkipIgnorable: