1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-07-29 11:41:22 +03:00

- Large resync between W3C and Gnome tree

- configure.in: 2.1.0 prerelease
- example/Makefile.am example/gjobread.c tree.h: work on
  libxml1 libxml2 convergence.
- nanoftp, nanohttp.c: fixed stalled connections probs
- HTMLtree.c SAX.c : support for attribute without values in
  HTML for andersca
- valid.c: Fixed most validation + namespace problems
- HTMLparser.c: start document callback for andersca
- debugXML.c xpath.c: lots of XPath fixups from Picdar Technology
- parser.h, SAX.c: serious speed improvement for large
  CDATA blocks
- encoding.[ch] xmlIO.[ch]: Improved seriously saving to
  different encoding
- config.h.in parser.c xmllint.c: added xmlCheckVersion()
  and the LIBXML_TEST_VERSION macro
Daniel
This commit is contained in:
Daniel Veillard
2000-06-28 23:40:59 +00:00
parent c310d56482
commit be803967db
41 changed files with 2877 additions and 1562 deletions

331
valid.c
View File

@ -154,6 +154,61 @@ void xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
/************************************************************************
* *
* QName handling helper *
* *
************************************************************************/
/**
* xmlSplitQName2:
* @name: an XML parser context
* @prefix: a xmlChar **
*
* parse an XML qualified name string
*
* [NS 5] QName ::= (Prefix ':')? LocalPart
*
* [NS 6] Prefix ::= NCName
*
* [NS 7] LocalPart ::= NCName
*
* Returns NULL if not a QName, otherwise the local part, and prefix
* is updated to get the Prefix if any.
*/
xmlChar *
xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
int len = 0;
xmlChar *ret = NULL;
*prefix = NULL;
/* xml: prefix is not really a namespace */
if ((name[0] == 'x') && (name[1] == 'm') &&
(name[2] == 'l') && (name[3] == ':'))
return(NULL);
/* nasty but valid */
if (name[0] == ':')
return(NULL);
/*
* we are not trying to validate but just to cut, and yes it will
* work even if this is as set of UTF-8 encoded chars
*/
while ((name[len] != 0) && (name[len] != ':'))
len++;
if (name[len] == 0)
return(NULL);
*prefix = xmlStrndup(name, len);
ret = xmlStrdup(&name[len + 1]);
return(ret);
}
/****************************************************************
* *
* Util functions for data allocation/deallocation *
@ -428,6 +483,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
xmlElementContentPtr content) {
xmlElementPtr ret, cur;
xmlElementTablePtr table;
xmlChar *ns, *uqname;
int i;
if (dtd == NULL) {
@ -472,6 +528,13 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
return(NULL);
}
/*
* check if name is a QName
*/
uqname = xmlSplitQName2(name, &ns);
if (uqname != NULL)
name = uqname;
/*
* Create the Element table if needed.
*/
@ -489,7 +552,10 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
*/
for (i = 0;i < table->nb_elements;i++) {
cur = table->table[i];
if (!xmlStrcmp(cur->name, name)) {
if ((ns != NULL) && (cur->prefix == NULL)) continue;
if ((ns == NULL) && (cur->prefix != NULL)) continue;
if ((!xmlStrcmp(cur->name, name)) &&
((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
/*
* The element is already defined in this Dtd.
*/
@ -527,6 +593,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
*/
ret->etype = type;
ret->name = xmlStrdup(name);
ret->prefix = ns;
ret->content = xmlCopyElementContent(content);
ret->attributes = xmlScanAttributeDecl(dtd, name);
table->nb_elements++;
@ -543,6 +610,8 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
ret->prev = dtd->last;
dtd->last = (xmlNodePtr) ret;
}
if (uqname != NULL)
xmlFree(uqname);
return(ret);
}
@ -559,6 +628,8 @@ xmlFreeElement(xmlElementPtr elem) {
xmlFreeElementContent(elem->content);
if (elem->name != NULL)
xmlFree((xmlChar *) elem->name);
if (elem->prefix != NULL)
xmlFree((xmlChar *) elem->prefix);
memset(elem, -1, sizeof(xmlElement));
xmlFree(elem);
}
@ -896,7 +967,7 @@ xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
*
* Register a new attribute declaration
*
* Returns NULL if not, othervise the entity
* Returns NULL if not new, othervise the attribute decl
*/
xmlAttributePtr
xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
@ -981,6 +1052,7 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
*/
VWARNING(ctxt->userData, "Attribute %s on %s: already defined\n",
elem, name);
return(NULL);
}
}
@ -1157,6 +1229,10 @@ xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
xmlBufferWriteChar(buf, "<!ATTLIST ");
xmlBufferWriteCHAR(buf, attr->elem);
xmlBufferWriteChar(buf, " ");
if (attr->prefix != NULL) {
xmlBufferWriteCHAR(buf, attr->prefix);
xmlBufferWriteChar(buf, ":");
}
xmlBufferWriteCHAR(buf, attr->name);
switch (attr->atype) {
case XML_ATTRIBUTE_CDATA:
@ -2066,6 +2142,7 @@ xmlElementPtr
xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
xmlElementTablePtr table;
xmlElementPtr cur;
xmlChar *uqname = NULL, *prefix = NULL;
int i;
if (dtd == NULL) return(NULL);
@ -2077,6 +2154,59 @@ xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
if (!xmlStrcmp(cur->name, name))
return(cur);
}
/*
* Specific case if name is a QName.
*/
uqname = xmlSplitQName2(name, &prefix);
if (uqname == NULL) return(NULL);
for (i = 0;i < table->nb_elements;i++) {
cur = table->table[i];
if ((!xmlStrcmp(cur->name, uqname)) &&
((prefix == cur->prefix) ||
((prefix != NULL) && (cur->prefix != NULL) &&
(!xmlStrcmp(cur->prefix, prefix))))) {
if (prefix != NULL) xmlFree(prefix);
if (uqname != NULL) xmlFree(uqname);
return(cur);
}
}
if (prefix != NULL) xmlFree(prefix);
if (uqname != NULL) xmlFree(uqname);
return(NULL);
}
/**
* xmlGetDtdQElementDesc:
* @dtd: a pointer to the DtD to search
* @name: the element name
* @prefix: the element namespace prefix
*
* Search the Dtd for the description of this element
*
* returns the xmlElementPtr if found or NULL
*/
xmlElementPtr
xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
const xmlChar *prefix) {
xmlElementTablePtr table;
xmlElementPtr cur;
int i;
if (dtd == NULL) return(NULL);
if (dtd->elements == NULL) return(NULL);
table = dtd->elements;
for (i = 0;i < table->nb_elements;i++) {
cur = table->table[i];
if (!xmlStrcmp(cur->name, name) &&
((prefix == cur->prefix) ||
((prefix != NULL) && (cur->prefix != NULL) &&
(!xmlStrcmp(cur->prefix, prefix)))))
return(cur);
}
return(NULL);
}
@ -2096,6 +2226,7 @@ xmlAttributePtr
xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
xmlAttributeTablePtr table;
xmlAttributePtr cur;
xmlChar *uqname = NULL, *prefix = NULL;
int i;
if (dtd == NULL) return(NULL);
@ -2108,6 +2239,63 @@ xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
(!xmlStrcmp(cur->elem, elem)))
return(cur);
}
/*
* Specific case if name is a QName.
*/
uqname = xmlSplitQName2(name, &prefix);
if (uqname == NULL) return(NULL);
for (i = 0;i < table->nb_attributes;i++) {
cur = table->table[i];
if ((!xmlStrcmp(cur->name, uqname)) &&
(!xmlStrcmp(cur->elem, elem)) &&
((prefix == cur->prefix) ||
((prefix != NULL) && (cur->prefix != NULL) &&
(!xmlStrcmp(cur->prefix, prefix))))) {
if (prefix != NULL) xmlFree(prefix);
if (uqname != NULL) xmlFree(uqname);
return(cur);
}
}
if (prefix != NULL) xmlFree(prefix);
if (uqname != NULL) xmlFree(uqname);
return(NULL);
}
/**
* xmlGetDtdQAttrDesc:
* @dtd: a pointer to the DtD to search
* @elem: the element name
* @name: the attribute name
* @prefix: the attribute namespace prefix
*
* Search the Dtd for the description of this qualified attribute on
* this element.
*
* returns the xmlAttributePtr if found or NULL
*/
xmlAttributePtr
xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
const xmlChar *prefix) {
xmlAttributeTablePtr table;
xmlAttributePtr cur;
int i;
if (dtd == NULL) return(NULL);
if (dtd->attributes == NULL) return(NULL);
table = dtd->attributes;
for (i = 0;i < table->nb_attributes;i++) {
cur = table->table[i];
if ((!xmlStrcmp(cur->name, name)) &&
(!xmlStrcmp(cur->elem, elem)) &&
((prefix == cur->prefix) ||
((prefix != NULL) && (cur->prefix != NULL) &&
(!xmlStrcmp(cur->prefix, prefix)))))
return(cur);
}
return(NULL);
}
@ -2586,13 +2774,25 @@ xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
const xmlChar *name, const xmlChar *value) {
xmlChar *ret, *dst;
const xmlChar *src;
xmlAttributePtr attrDecl;
xmlAttributePtr attrDecl = NULL;
if (doc == NULL) return(NULL);
if (elem == NULL) return(NULL);
if (name == NULL) return(NULL);
if (value == NULL) return(NULL);
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
xmlChar qname[500];
#ifdef HAVE_SNPRINTF
snprintf((char *) qname, sizeof(qname), "%s:%s",
elem->ns->prefix, elem->name);
#else
sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
#endif
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
if ((attrDecl == NULL) && (doc->extSubset != NULL))
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
}
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
if ((attrDecl == NULL) && (doc->extSubset != NULL))
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
@ -2850,7 +3050,7 @@ int
xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
/* xmlElementPtr elemDecl; */
xmlAttributePtr attrDecl;
xmlAttributePtr attrDecl = NULL;
int val;
int ret = 1;
@ -2858,9 +3058,42 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
if ((elem == NULL) || (elem->name == NULL)) return(0);
if ((attr == NULL) || (attr->name == NULL)) return(0);
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
if ((attrDecl == NULL) && (doc->extSubset != NULL))
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
xmlChar qname[500];
#ifdef HAVE_SNPRINTF
snprintf((char *) qname, sizeof(qname), "%s:%s",
elem->ns->prefix, elem->name);
#else
sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
#endif
if (attr->ns != NULL) {
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
attr->name, attr->ns->prefix);
if ((attrDecl == NULL) && (doc->extSubset != NULL))
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
attr->name, attr->ns->prefix);
} else {
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
if ((attrDecl == NULL) && (doc->extSubset != NULL))
attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
qname, attr->name);
}
}
if (attrDecl == NULL) {
if (attr->ns != NULL) {
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
attr->name, attr->ns->prefix);
if ((attrDecl == NULL) && (doc->extSubset != NULL))
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
attr->name, attr->ns->prefix);
} else {
attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
elem->name, attr->name);
if ((attrDecl == NULL) && (doc->extSubset != NULL))
attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
elem->name, attr->name);
}
}
/* Validity Constraint: Attribute Value Type */
@ -3274,7 +3507,7 @@ xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
int
xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
xmlNodePtr elem) {
xmlElementPtr elemDecl;
xmlElementPtr elemDecl = NULL;
xmlElementContentPtr cont;
xmlAttributePtr attr;
xmlNodePtr child;
@ -3347,9 +3580,25 @@ xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
}
if (elem->name == NULL) return(0);
elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
if ((elemDecl == NULL) && (doc->extSubset != NULL))
elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
/*
* Fetch the declaration for the qualified name
*/
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
elem->name, elem->ns->prefix);
if ((elemDecl == NULL) && (doc->extSubset != NULL))
elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
elem->name, elem->ns->prefix);
}
/*
* Fetch the declaration for the non qualified name
*/
if (elemDecl == NULL) {
elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
if ((elemDecl == NULL) && (doc->extSubset != NULL))
elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
}
if (elemDecl == NULL) {
VERROR(ctxt->userData, "No declaration for element %s\n",
elem->name);
@ -3375,6 +3624,34 @@ xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
while (child != NULL) {
if (child->type == XML_ELEMENT_NODE) {
name = child->name;
if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
xmlChar qname[500];
#ifdef HAVE_SNPRINTF
snprintf((char *) qname, sizeof(qname), "%s:%s",
child->ns->prefix, child->name);
#else
sprintf(qname, "%s:%s", child->name, child->ns->prefix);
#endif
cont = elemDecl->content;
while (cont != NULL) {
if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
if (!xmlStrcmp(cont->name, qname)) break;
} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
(cont->c1 != NULL) &&
(cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
if (!xmlStrcmp(cont->c1->name, qname)) break;
} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
(cont->c1 == NULL) ||
(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
/* Internal error !!! */
fprintf(stderr, "Internal: MIXED struct bad\n");
break;
}
cont = cont->c2;
}
if (cont != NULL)
goto child_ok;
}
cont = elemDecl->content;
while (cont != NULL) {
if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
@ -3399,6 +3676,7 @@ xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
ret = 0;
}
}
child_ok:
child = child->next;
}
break;
@ -3518,15 +3796,32 @@ xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
VERROR(ctxt->userData, "Not valid: no root element\n");
return(0);
}
/*
* Check first the document root against the NQName
*/
if (xmlStrcmp(doc->intSubset->name, root->name)) {
if ((xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) ||
(xmlStrcmp(root->name, BAD_CAST "html"))) {
VERROR(ctxt->userData,
"Not valid: root and DtD name do not match '%s' and '%s'\n",
root->name, doc->intSubset->name);
return(0);
}
if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
xmlChar qname[500];
#ifdef HAVE_SNPRINTF
snprintf((char *) qname, sizeof(qname), "%s:%s",
root->ns->prefix, root->name);
#else
sprintf(qname, "%s:%s", root->name, root->ns->prefix);
#endif
if (!xmlStrcmp(doc->intSubset->name, qname))
goto name_ok;
}
if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
(!xmlStrcmp(root->name, BAD_CAST "html")))
goto name_ok;
VERROR(ctxt->userData,
"Not valid: root and DtD name do not match '%s' and '%s'\n",
root->name, doc->intSubset->name);
return(0);
}
name_ok:
return(1);
}