- debugXML.c hash.c tree.h valid.c : some changes related to
the validation suport to improve speed with DocBook
- result/VC/OneID2 result/VC/OneID3 : this slightly changes
the way validation errors get reported
Daniel
diff --git a/ChangeLog b/ChangeLog
index 6088f43..b111098 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Apr 18 15:06:30 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+ * debugXML.c hash.c tree.h valid.c : some changes related to
+ the validation suport to improve speed with DocBook
+ * result/VC/OneID2 result/VC/OneID3 : this slightly changes
+ the way validation errors get reported
+
Wed Apr 18 11:42:47 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* HTMLparser.c HTMLtree.c: applied part of the patches provided
diff --git a/debugXML.c b/debugXML.c
index f9f1c8b..03b1128 100644
--- a/debugXML.c
+++ b/debugXML.c
@@ -239,6 +239,9 @@
} else
fprintf(output, "PBM ELEMDECL noname!!!");
switch (elem->etype) {
+ case XML_ELEMENT_TYPE_UNDEFINED:
+ fprintf(output, ", UNDEFINED");
+ break;
case XML_ELEMENT_TYPE_EMPTY:
fprintf(output, ", EMPTY");
break;
diff --git a/hash.c b/hash.c
index 45946ca..ec15745 100644
--- a/hash.c
+++ b/hash.c
@@ -27,6 +27,11 @@
#include <libxml/hash.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
+#include <libxml/xmlerror.h>
+
+#define MAX_HASH_LEN 8
+
+/* #define DEBUG_GROW */
/*
* A single entry in the hash table
@@ -55,13 +60,29 @@
* Calculate the hash key
*/
static unsigned long
-xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *string) {
+xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name,
+ const xmlChar *name2, const xmlChar *name3) {
unsigned long value = 0L;
char ch;
- while ((ch = *string++) != 0) {
- /* value *= 31; */
- value += (unsigned long)ch;
+ if (name != NULL) {
+ value += 30 * (*name);
+ while ((ch = *name++) != 0) {
+ /* value *= 31; */
+ value += (unsigned long)ch;
+ }
+ }
+ if (name2 != NULL) {
+ while ((ch = *name2++) != 0) {
+ /* value *= 31; */
+ value += (unsigned long)ch;
+ }
+ }
+ if (name3 != NULL) {
+ while ((ch = *name3++) != 0) {
+ /* value *= 31; */
+ value += (unsigned long)ch;
+ }
}
return (value % table->size);
}
@@ -96,6 +117,77 @@
}
/**
+ * xmlHashGrow:
+ * @table: the hash table
+ * @size: the new size of the hash table
+ *
+ * resize the hash table
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+int
+xmlHashGrow(xmlHashTablePtr table, int size) {
+ unsigned long key;
+ int oldsize, i;
+ xmlHashEntryPtr iter, next;
+ struct _xmlHashEntry **oldtable;
+#ifdef DEBUG_GROW
+ unsigned long nbElem = 0;
+#endif
+
+ if (table == NULL)
+ return(-1);
+ if (size < 8)
+ return(-1);
+ if (size > 8 * 2048)
+ return(-1);
+
+ oldsize = table->size;
+ oldtable = table->table;
+ if (oldtable == NULL)
+ return(-1);
+
+ table->table = xmlMalloc(size * sizeof(xmlHashEntry));
+ if (table->table == NULL) {
+ table->table = oldtable;
+ return(-1);
+ }
+ memset(table->table, 0, size * sizeof(xmlHashEntry));
+ table->size = size;
+
+ for (i = 0; i < oldsize; i++) {
+ iter = oldtable[i];
+ while (iter) {
+ next = iter->next;
+
+ /*
+ * put back the entry in the new table
+ */
+
+ key = xmlHashComputeKey(table, iter->name, iter->name2,
+ iter->name3);
+ iter->next = table->table[key];
+ table->table[key] = iter;
+
+#ifdef DEBUG_GROW
+ nbElem++;
+#endif
+
+ iter = next;
+ }
+ }
+
+ xmlFree(oldtable);
+
+#ifdef DEBUG_GROW
+ xmlGenericError(xmlGenericErrorContext,
+ "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem);
+#endif
+
+ return(0);
+}
+
+/**
* xmlHashFree:
* @table: the hash table
* @f: the deallocator function for items in the hash
@@ -116,14 +208,14 @@
iter = table->table[i];
while (iter) {
next = iter->next;
+ if (f)
+ f(iter->payload, iter->name);
if (iter->name)
xmlFree(iter->name);
if (iter->name2)
xmlFree(iter->name2);
if (iter->name3)
xmlFree(iter->name3);
- if (f)
- f(iter->payload, iter->name);
iter->payload = NULL;
xmlFree(iter);
iter = next;
@@ -257,7 +349,7 @@
xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
const xmlChar *name2, const xmlChar *name3,
void *userdata) {
- unsigned long key;
+ unsigned long key, len = 0;
xmlHashEntryPtr entry;
xmlHashEntryPtr insert;
@@ -267,7 +359,7 @@
/*
* Check for duplicate and insertion location.
*/
- key = xmlHashComputeKey(table, name);
+ key = xmlHashComputeKey(table, name, name2, name3);
if (table->table[key] == NULL) {
insert = NULL;
} else {
@@ -277,6 +369,7 @@
(xmlStrEqual(insert->name2, name2)) &&
(xmlStrEqual(insert->name3, name3)))
return(-1);
+ len++;
}
if ((xmlStrEqual(insert->name, name)) &&
(xmlStrEqual(insert->name2, name2)) &&
@@ -300,6 +393,10 @@
insert->next = entry;
}
table->nbElems++;
+
+ if (len > MAX_HASH_LEN)
+ xmlHashGrow(table, MAX_HASH_LEN * table->size);
+
return(0);
}
@@ -332,7 +429,7 @@
/*
* Check for duplicate and insertion location.
*/
- key = xmlHashComputeKey(table, name);
+ key = xmlHashComputeKey(table, name, name2, name3);
if (table->table[key] == NULL) {
insert = NULL;
} else {
@@ -397,7 +494,7 @@
return(NULL);
if (name == NULL)
return(NULL);
- key = xmlHashComputeKey(table, name);
+ key = xmlHashComputeKey(table, name, name2, name3);
for (entry = table->table[key]; entry != NULL; entry = entry->next) {
if ((xmlStrEqual(entry->name, name)) &&
(xmlStrEqual(entry->name2, name2)) &&
@@ -544,8 +641,8 @@
* Returns 0 if the removal succeeded and -1 in case of error or not found.
*/
int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
- xmlHashDeallocator f) {
- return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
+ xmlHashDeallocator f) {
+ return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
}
/**
@@ -561,8 +658,8 @@
* Returns 0 if the removal succeeded and -1 in case of error or not found.
*/
int xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, xmlHashDeallocator f) {
- return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
+ const xmlChar *name2, xmlHashDeallocator f) {
+ return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
}
/**
@@ -579,43 +676,42 @@
* Returns 0 if the removal succeeded and -1 in case of error or not found.
*/
int xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
- const xmlChar *name2, const xmlChar *name3,
- xmlHashDeallocator f) {
- unsigned long key;
- xmlHashEntryPtr entry;
- xmlHashEntryPtr prev = NULL;
+ const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) {
+ unsigned long key;
+ xmlHashEntryPtr entry;
+ xmlHashEntryPtr prev = NULL;
- if (table == NULL || name == NULL)
- return(-1);
+ if (table == NULL || name == NULL)
+ return(-1);
- key = xmlHashComputeKey(table, name);
- if (table->table[key] == NULL) {
- return(-1);
- } else {
- for (entry = table->table[key]; entry != NULL; entry = entry->next) {
- if (xmlStrEqual(entry->name, name) &&
- xmlStrEqual(entry->name2, name2) &&
- xmlStrEqual(entry->name3, name3)) {
- if(f)
- f(entry->payload, entry->name);
- entry->payload = NULL;
- if(entry->name)
- xmlFree(entry->name);
- if(entry->name2)
- xmlFree(entry->name2);
- if(entry->name3)
- xmlFree(entry->name3);
- if(prev)
- prev->next = entry->next;
- else
- table->table[key] = entry->next;
- xmlFree(entry);
- table->nbElems--;
- return(0);
- }
- prev = entry;
- }
- return(-1);
- }
+ key = xmlHashComputeKey(table, name, name2, name3);
+ if (table->table[key] == NULL) {
+ return(-1);
+ } else {
+ for (entry = table->table[key]; entry != NULL; entry = entry->next) {
+ if (xmlStrEqual(entry->name, name) &&
+ xmlStrEqual(entry->name2, name2) &&
+ xmlStrEqual(entry->name3, name3)) {
+ if(f)
+ f(entry->payload, entry->name);
+ entry->payload = NULL;
+ if(entry->name)
+ xmlFree(entry->name);
+ if(entry->name2)
+ xmlFree(entry->name2);
+ if(entry->name3)
+ xmlFree(entry->name3);
+ if(prev)
+ prev->next = entry->next;
+ else
+ table->table[key] = entry->next;
+ xmlFree(entry);
+ table->nbElems--;
+ return(0);
+ }
+ prev = entry;
+ }
+ return(-1);
+ }
}
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index 47e0212..ce86711 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -172,6 +172,7 @@
};
typedef enum {
+ XML_ELEMENT_TYPE_UNDEFINED = 0,
XML_ELEMENT_TYPE_EMPTY = 1,
XML_ELEMENT_TYPE_ANY,
XML_ELEMENT_TYPE_MIXED,
diff --git a/result/VC/OneID2 b/result/VC/OneID2
index b1e2ed5..a67c893 100644
--- a/result/VC/OneID2
+++ b/result/VC/OneID2
@@ -1,6 +1,6 @@
+./test/VC/OneID2:3: validity error: Element doc has too may ID attributes defined : id
+<!ATTLIST doc id ID #IMPLIED>
+ ^
./test/VC/OneID2:3: validity error: Element doc has 2 ID attribute defined in the internal subset : id
<!ATTLIST doc id ID #IMPLIED>
^
-./test/VC/OneID2:4: validity error: Element doc has too may ID attributes defined : val
-<!ELEMENT doc (#PCDATA)>
- ^
diff --git a/result/VC/OneID3 b/result/VC/OneID3
index d1742de..336caf8 100644
--- a/result/VC/OneID3
+++ b/result/VC/OneID3
@@ -1,3 +1,6 @@
-test/VC/dtds/doc.dtd:2: validity error: Element doc has ID attributes defined in the internal and external subset : val
+test/VC/dtds/doc.dtd:2: validity error: Element doc has too may ID attributes defined : val
+<!ATTLIST doc val ID #IMPLIED>
+ ^
+test/VC/dtds/doc.dtd:2: validity error: Element doc has 2 ID attribute defined in the external subset : val
<!ATTLIST doc val ID #IMPLIED>
^
diff --git a/tree.h b/tree.h
index 47e0212..ce86711 100644
--- a/tree.h
+++ b/tree.h
@@ -172,6 +172,7 @@
};
typedef enum {
+ XML_ELEMENT_TYPE_UNDEFINED = 0,
XML_ELEMENT_TYPE_EMPTY = 1,
XML_ELEMENT_TYPE_ANY,
XML_ELEMENT_TYPE_MIXED,
diff --git a/valid.c b/valid.c
index 822adeb..c3a0739 100644
--- a/valid.c
+++ b/valid.c
@@ -161,6 +161,8 @@
(doc->extSubset == NULL)) return(0)
xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
+static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
+ int create);
xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
/************************************************************************
@@ -507,6 +509,7 @@
xmlElementContentPtr content) {
xmlElementPtr ret;
xmlElementTablePtr table;
+ xmlAttributePtr oldAttributes = NULL;
xmlChar *ns, *uqname;
if (dtd == NULL) {
@@ -575,38 +578,73 @@
return(NULL);
}
- ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
- if (ret == NULL) {
- xmlGenericError(xmlGenericErrorContext,
- "xmlAddElementDecl: out of memory\n");
- return(NULL);
+ /*
+ * lookup old attributes inserted on an undefined element in the
+ * internal subset.
+ */
+ if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
+ ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
+ if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
+ oldAttributes = ret->attributes;
+ ret->attributes = NULL;
+ xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
+ xmlFreeElement(ret);
+ }
}
- memset(ret, 0, sizeof(xmlElement));
- ret->type = XML_ELEMENT_DECL;
/*
- * fill the structure.
+ * The element may already be present if one of its attribute
+ * was registered first
+ */
+ ret = xmlHashLookup2(table, name, ns);
+ if (ret != NULL) {
+ if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
+ /*
+ * The element is already defined in this Dtd.
+ */
+ VERROR(ctxt->userData, "Redefinition of element %s\n", name);
+ if (uqname != NULL)
+ xmlFree(uqname);
+ return(NULL);
+ }
+ } else {
+ ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
+ if (ret == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "xmlAddElementDecl: out of memory\n");
+ return(NULL);
+ }
+ memset(ret, 0, sizeof(xmlElement));
+ ret->type = XML_ELEMENT_DECL;
+
+ /*
+ * fill the structure.
+ */
+ ret->name = xmlStrdup(name);
+ ret->prefix = ns;
+
+ /*
+ * Validity Check:
+ * Insertion must not fail
+ */
+ if (xmlHashAddEntry2(table, name, ns, ret)) {
+ /*
+ * The element is already defined in this Dtd.
+ */
+ VERROR(ctxt->userData, "Redefinition of element %s\n", name);
+ xmlFreeElement(ret);
+ if (uqname != NULL)
+ xmlFree(uqname);
+ return(NULL);
+ }
+ }
+
+ /*
+ * Finish to fill the structure.
*/
ret->etype = type;
- ret->name = xmlStrdup(name);
- ret->prefix = ns;
ret->content = xmlCopyElementContent(content);
- ret->attributes = xmlScanAttributeDecl(dtd, name);
-
- /*
- * Validity Check:
- * Insertion must not fail
- */
- if (xmlHashAddEntry2(table, name, ns, ret)) {
- /*
- * The element is already defined in this Dtd.
- */
- VERROR(ctxt->userData, "Redefinition of element %s\n", name);
- xmlFreeElement(ret);
- if (uqname != NULL)
- xmlFree(uqname);
- return(NULL);
- }
+ ret->attributes = oldAttributes;
/*
* Link it to the Dtd
@@ -910,7 +948,7 @@
ret ++;
if (ret > 1)
VERROR(ctxt->userData,
- "Element %s has too may ID attributes defined : %s\n",
+ "Element %s has too many ID attributes defined : %s\n",
elem->name, cur->name);
}
cur = cur->nexth;
@@ -1078,7 +1116,7 @@
* Validity Check:
* Multiple ID per element
*/
- elemDef = xmlGetDtdElementDesc(dtd, elem);
+ elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
if (elemDef != NULL) {
if ((type == XML_ATTRIBUTE_ID) &&
(xmlScanIDAttributeDecl(NULL, elemDef) != 0))
@@ -1999,16 +2037,80 @@
xmlChar *uqname = NULL, *prefix = NULL;
if (dtd == NULL) return(NULL);
- if (dtd->elements == NULL) return(NULL);
+ if (dtd->elements == NULL)
+ return(NULL);
table = (xmlElementTablePtr) dtd->elements;
uqname = xmlSplitQName2(name, &prefix);
- if (uqname != NULL) {
- cur = xmlHashLookup2(table, uqname, prefix);
- if (prefix != NULL) xmlFree(prefix);
- if (uqname != NULL) xmlFree(uqname);
- } else
- cur = xmlHashLookup2(table, name, NULL);
+ if (uqname != NULL)
+ name = uqname;
+ cur = xmlHashLookup2(table, name, prefix);
+ if (prefix != NULL) xmlFree(prefix);
+ if (uqname != NULL) xmlFree(uqname);
+ return(cur);
+}
+/**
+ * xmlGetDtdElementDesc2:
+ * @dtd: a pointer to the DtD to search
+ * @name: the element name
+ * @create: create an empty description if not found
+ *
+ * Search the Dtd for the description of this element
+ *
+ * returns the xmlElementPtr if found or NULL
+ */
+
+xmlElementPtr
+xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
+ xmlElementTablePtr table;
+ xmlElementPtr cur;
+ xmlChar *uqname = NULL, *prefix = NULL;
+
+ if (dtd == NULL) return(NULL);
+ if (dtd->elements == NULL) {
+ if (!create)
+ return(NULL);
+ /*
+ * Create the Element table if needed.
+ */
+ table = (xmlElementTablePtr) dtd->elements;
+ if (table == NULL) {
+ table = xmlCreateElementTable();
+ dtd->elements = (void *) table;
+ }
+ if (table == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "xmlGetDtdElementDesc: Table creation failed!\n");
+ return(NULL);
+ }
+ }
+ table = (xmlElementTablePtr) dtd->elements;
+
+ uqname = xmlSplitQName2(name, &prefix);
+ if (uqname != NULL)
+ name = uqname;
+ cur = xmlHashLookup2(table, name, prefix);
+ if ((cur == NULL) && (create)) {
+ cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
+ if (cur == NULL) {
+ xmlGenericError(xmlGenericErrorContext,
+ "xmlGetDtdElementDesc: out of memory\n");
+ return(NULL);
+ }
+ memset(cur, 0, sizeof(xmlElement));
+ cur->type = XML_ELEMENT_DECL;
+
+ /*
+ * fill the structure.
+ */
+ cur->name = xmlStrdup(name);
+ cur->prefix = xmlStrdup(prefix);
+ cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
+
+ xmlHashAddEntry2(table, name, prefix, cur);
+ }
+ if (prefix != NULL) xmlFree(prefix);
+ if (uqname != NULL) xmlFree(uqname);
return(cur);
}
@@ -2169,6 +2271,8 @@
elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
if (elemDecl == NULL) return(-1);
switch (elemDecl->etype) {
+ case XML_ELEMENT_TYPE_UNDEFINED:
+ return(-1);
case XML_ELEMENT_TYPE_ELEMENT:
return(0);
case XML_ELEMENT_TYPE_EMPTY:
@@ -2788,22 +2892,25 @@
/* VC: Unique Element Type Declaration */
tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
- if ((tst != NULL ) && (tst != elem)) {
+ if ((tst != NULL ) && (tst != elem) &&
+ (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
VERROR(ctxt->userData, "Redefinition of element %s\n",
elem->name);
ret = 0;
}
tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
- if ((tst != NULL ) && (tst != elem)) {
+ if ((tst != NULL ) && (tst != elem) &&
+ (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
VERROR(ctxt->userData, "Redefinition of element %s\n",
elem->name);
ret = 0;
}
- /* One ID per Element Type */
+ /* One ID per Element Type
+ * already done when registering the attribute
if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
ret = 0;
- }
+ } */
return(ret);
}
@@ -3426,6 +3533,10 @@
/* Check taht the element content matches the definition */
switch (elemDecl->etype) {
+ case XML_ELEMENT_TYPE_UNDEFINED:
+ VERROR(ctxt->userData, "No declaration for element %s\n",
+ elem->name);
+ return(0);
case XML_ELEMENT_TYPE_EMPTY:
if (elem->children != NULL) {
VERROR(ctxt->userData,