diff --git a/ChangeLog b/ChangeLog index 6088f43c..b111098f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Apr 18 15:06:30 CEST 2001 Daniel Veillard + + * 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 * HTMLparser.c HTMLtree.c: applied part of the patches provided diff --git a/debugXML.c b/debugXML.c index f9f1c8b8..03b1128f 100644 --- a/debugXML.c +++ b/debugXML.c @@ -239,6 +239,9 @@ xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) { } 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 45946ca0..ec15745a 100644 --- a/hash.c +++ b/hash.c @@ -27,6 +27,11 @@ #include #include #include +#include + +#define MAX_HASH_LEN 8 + +/* #define DEBUG_GROW */ /* * A single entry in the hash table @@ -55,13 +60,29 @@ struct _xmlHashTable { * 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); } @@ -95,6 +116,77 @@ xmlHashCreate(int size) { return(NULL); } +/** + * 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 @@ -116,14 +208,14 @@ xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) { 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 @@ int 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 @@ xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name, /* * 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 @@ xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name, (xmlStrEqual(insert->name2, name2)) && (xmlStrEqual(insert->name3, name3))) return(-1); + len++; } if ((xmlStrEqual(insert->name, name)) && (xmlStrEqual(insert->name2, name2)) && @@ -300,6 +393,10 @@ xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name, insert->next = entry; } table->nbElems++; + + if (len > MAX_HASH_LEN) + xmlHashGrow(table, MAX_HASH_LEN * table->size); + return(0); } @@ -332,7 +429,7 @@ xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name, /* * 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 @@ xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, 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 @@ xmlHashSize(xmlHashTablePtr table) { * 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 @@ int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, * 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 @@ int xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, * 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 47e02129..ce867115 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -172,6 +172,7 @@ struct _xmlElementContent { }; 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 b1e2ed5e..a67c8933 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 + + ^ ./test/VC/OneID2:3: validity error: Element doc has 2 ID attribute defined in the internal subset : id ^ -./test/VC/OneID2:4: validity error: Element doc has too may ID attributes defined : val - - ^ diff --git a/result/VC/OneID3 b/result/VC/OneID3 index d1742de5..336caf84 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 + + ^ +test/VC/dtds/doc.dtd:2: validity error: Element doc has 2 ID attribute defined in the external subset : val ^ diff --git a/tree.h b/tree.h index 47e02129..ce867115 100644 --- a/tree.h +++ b/tree.h @@ -172,6 +172,7 @@ struct _xmlElementContent { }; 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 822adebd..c3a07397 100644 --- a/valid.c +++ b/valid.c @@ -161,6 +161,8 @@ void xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) { (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 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, xmlElementContentPtr content) { xmlElementPtr ret; xmlElementTablePtr table; + xmlAttributePtr oldAttributes = NULL; xmlChar *ns, *uqname; if (dtd == NULL) { @@ -575,38 +578,73 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, 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 @@ xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { 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 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem, * 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 @@ xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { 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 @@ xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) { 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 @@ xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, /* 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 @@ xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, /* 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,