diff --git a/ChangeLog b/ChangeLog index 712a1d50..f7f3575a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Mon Feb 24 18:14:16 CET 2003 Daniel Veillard + + * tree.c: fixed xmlSetProp and al. when the node passed is not an + element. + * relaxng.c: fixed bugs 7.3 (though not complete) and memory leaks + found 373 test schemas: 369 success 4 failures + found 529 test instances: 525 success 4 failures + * check-relaxng-test-suite.py: added memory debug reporting + Mon Feb 24 12:41:54 CET 2003 Daniel Veillard * uri.c parser.c: some warning removal on Igor's patch diff --git a/check-relaxng-test-suite.py b/check-relaxng-test-suite.py index 5363a818..6f65264a 100755 --- a/check-relaxng-test-suite.py +++ b/check-relaxng-test-suite.py @@ -7,6 +7,8 @@ import StringIO sys.path.append("python") import libxml2 +# Memory debug specific +libxml2.debugMemory(1) debug = 0 # @@ -97,6 +99,7 @@ def handle_valid(node, schema): nb_instances_failed = nb_instances_failed + 1 else: nb_instances_success = nb_instances_success + 1 + doc.freeDoc() # # handle an invalid instance @@ -136,6 +139,7 @@ def handle_invalid(node, schema): nb_instances_failed = nb_instances_failed + 1 else: nb_instances_success = nb_instances_success + 1 + doc.freeDoc() # # handle an incorrect test @@ -364,3 +368,14 @@ print "\nTOTAL:\nfound %d test schemas: %d success %d failures" % ( nb_schemas_tests, nb_schemas_success, nb_schemas_failed) print "found %d test instances: %d success %d failures" % ( nb_instances_tests, nb_instances_success, nb_instances_failed) + +testsuite.freeDoc() + +# Memory debug specific +libxml2.relaxNGCleanupTypes() +libxml2.cleanupParser() +if libxml2.debugMemory(1) == 0: + print "OK" +else: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory() diff --git a/relaxng.c b/relaxng.c index 8b04b260..2f91afed 100644 --- a/relaxng.c +++ b/relaxng.c @@ -309,6 +309,7 @@ struct _xmlRelaxNGDocument { xmlRelaxNGPtr schema; /* the schema */ }; + /************************************************************************ * * * Preliminary type checking interfaces * @@ -969,7 +970,6 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL, */ doc = xmlRelaxNGCleanupDoc(ctxt, doc); if (doc == NULL) { - /* xmlFreeDoc(ctxt->include); */ ctxt->inc = NULL; return(NULL); } @@ -988,7 +988,6 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL, ctxt->error(ctxt->userData, "xmlRelaxNG: included document is empty %s\n", URL); ctxt->nbErrors++; - xmlFreeDoc(doc); return (NULL); } if (!IS_RELAXNG(root, "grammar")) { @@ -997,7 +996,6 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL, "xmlRelaxNG: included document %s root is not a grammar\n", URL); ctxt->nbErrors++; - xmlFreeDoc(doc); return (NULL); } @@ -1248,7 +1246,6 @@ xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL, */ doc = xmlRelaxNGCleanupDoc(ctxt, doc); if (doc == NULL) { - xmlFreeDoc(ctxt->document); ctxt->doc = NULL; return(NULL); } @@ -2052,11 +2049,14 @@ xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { return(def); } +static const xmlChar *invalidName = BAD_CAST "\1"; + /** - * xmlRelaxNGCompareElemDefLists: - * @ctxt: a Relax-NG parser context - * @defs1: the first list of element defs - * @defs2: the second list of element defs + * xmlRelaxNGCompareNameClasses: + * @defs1: the first element/attribute defs + * @defs2: the second element/attribute defs + * @name: the restriction on the name + * @ns: the restriction on the namespace * * Compare the 2 lists of element definitions. The comparison is * that if both lists do not accept the same QNames, it returns 1 @@ -2065,6 +2065,103 @@ xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { * Returns 1 disttinct, 0 if equal */ static int +xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, + xmlRelaxNGDefinePtr def2) { + int ret = 1; + xmlNode node; + xmlNs ns; + xmlRelaxNGValidCtxt ctxt; + ctxt.flags = FLAGS_IGNORABLE; + + if ((def1->type == XML_RELAXNG_ELEMENT) || + (def1->type == XML_RELAXNG_ATTRIBUTE)) { + if (def2->type == XML_RELAXNG_TEXT) + return(1); + if (def1->name != NULL) { + node.name = def1->name; + } else { + node.name = invalidName; + } + node.ns = &ns; + if (def1->ns != NULL) { + if (def1->ns[0] == 0) { + node.ns = NULL; + } else { + ns.href = def1->ns; + } + } else { + ns.href = invalidName; + } + if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) { + if (def1->nameClass != NULL) { + ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2); + } else { + ret = 0; + } + } else { + ret = 1; + } + } else if (def1->type == XML_RELAXNG_TEXT) { + if (def2->type == XML_RELAXNG_TEXT) + return(0); + return(1); + } else if (def1->type == XML_RELAXNG_EXCEPT) { + xmlRelaxNGDefinePtr tmp = def1->content; + TODO + ret = 0; + } else { + TODO + ret = 0; + } + if (ret == 0) + return(ret); + if ((def2->type == XML_RELAXNG_ELEMENT) || + (def2->type == XML_RELAXNG_ATTRIBUTE)) { + if (def2->name != NULL) { + node.name = def2->name; + } else { + node.name = invalidName; + } + node.ns = &ns; + if (def2->ns != NULL) { + if (def2->ns[0] == 0) { + node.ns = NULL; + } else { + ns.href = def2->ns; + } + } else { + ns.href = invalidName; + } + if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) { + if (def2->nameClass != NULL) { + ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1); + } else { + ret = 0; + } + } else { + ret = 1; + } + } else { + TODO + ret = 0; + } + + return(ret); +} + +/** + * xmlRelaxNGCompareElemDefLists: + * @ctxt: a Relax-NG parser context + * @defs1: the first list of element/attribute defs + * @defs2: the second list of element/attribute defs + * + * Compare the 2 lists of element or attribute definitions. The comparison + * is that if both lists do not accept the same QNames, it returns 1 + * If the 2 lists can accept the same QName the comparison returns 0 + * + * Returns 1 disttinct, 0 if equal + */ +static int xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr *def1, xmlRelaxNGDefinePtr *def2) { @@ -2076,16 +2173,8 @@ xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, return(1); while (*def1 != NULL) { while ((*def2) != NULL) { - if ((*def1)->name == NULL) { - if (xmlStrEqual((*def2)->ns, (*def1)->ns)) - return(0); - } else if ((*def2)->name == NULL) { - if (xmlStrEqual((*def2)->ns, (*def1)->ns)) - return(0); - } else if (xmlStrEqual((*def1)->name, (*def2)->name)) { - if (xmlStrEqual((*def2)->ns, (*def1)->ns)) - return(0); - } + if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0) + return(0); def2++; } def2 = basedef2; @@ -4656,6 +4745,9 @@ xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) { if (ctxt->documents != NULL) xmlHashFree(ctxt->documents, (xmlHashDeallocator) xmlRelaxNGFreeDocument); + if (ctxt->includes != NULL) + xmlHashFree(ctxt->includes, (xmlHashDeallocator) + xmlRelaxNGFreeInclude); if (ctxt->docTab != NULL) xmlFree(ctxt->docTab); if (ctxt->incTab != NULL) @@ -4912,6 +5004,8 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) { delete = cur; goto skip_children; } + if (ns != NULL) + xmlFree(ns); xmlFree(URL); cur->_private = docu; } else if (xmlStrEqual(cur->name, BAD_CAST "include")) { @@ -5311,11 +5405,14 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n", ctxt->URL); ctxt->nbErrors++; + xmlFreeDoc(doc); return (NULL); } ret = xmlRelaxNGParseDocument(ctxt, root); - if (ret == NULL) + if (ret == NULL) { + xmlFreeDoc(doc); return(NULL); + } /* * Check the ref/defines links @@ -5345,6 +5442,7 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) ctxt->document = NULL; ret->documents = ctxt->documents; ctxt->documents = NULL; + ret->includes = ctxt->includes; ctxt->includes = NULL; ret->defNr = ctxt->defNr; @@ -6221,96 +6319,6 @@ xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, return(ret); } -/** - * xmlRelaxNGValidateTryPermutation: - * @ctxt: a Relax-NG validation context - * @groups: the array of groups - * @nbgroups: the number of groups in the array - * @array: the permutation to try - * @len: the size of the set - * - * Try to validate a permutation for the group of definitions. - * - * Returns 0 if the validation succeeded or an error code. - */ -static int -xmlRelaxNGValidateTryPermutation(xmlRelaxNGValidCtxtPtr ctxt, - xmlRelaxNGDefinePtr rule, - xmlNodePtr *array, int len) { - int i, ret; - - if (len > 0) { - /* - * One only need the next pointer set-up to do the validation - */ - for (i = 0;i < (len - 1);i++) - array[i]->next = array[i + 1]; - array[i]->next = NULL; - - /* - * Now try to validate the sequence - */ - ctxt->state->seq = array[0]; - ret = xmlRelaxNGValidateDefinition(ctxt, rule); - } else { - ctxt->state->seq = NULL; - ret = xmlRelaxNGValidateDefinition(ctxt, rule); - } - - /* - * the sequence must be fully consumed - */ - if (ctxt->state->seq != NULL) - return(-1); - - return(ret); -} - -/** - * xmlRelaxNGValidateWalkPermutations: - * @ctxt: a Relax-NG validation context - * @groups: the array of groups - * @nbgroups: the number of groups in the array - * @nodes: the set of nodes - * @array: the current state of the parmutation - * @len: the size of the set - * @level: a pointer to the level variable - * @k: the index in the array to fill - * - * Validate a set of nodes for a groups of definitions, will try the - * full set of permutations - * - * Returns 0 if the validation succeeded or an error code. - */ -static int -xmlRelaxNGValidateWalkPermutations(xmlRelaxNGValidCtxtPtr ctxt, - xmlRelaxNGDefinePtr rule, xmlNodePtr *nodes, - xmlNodePtr *array, int len, - int *level, int k) { - int i, ret; - - if ((k >= 0) && (k < len)) - array[k] = nodes[*level]; - *level = *level + 1; - if (*level == len) { - ret = xmlRelaxNGValidateTryPermutation(ctxt, rule, array, len); - if (ret == 0) - return(0); - } else { - for (i = 0;i < len;i++) { - if (array[i] == NULL) { - ret = xmlRelaxNGValidateWalkPermutations(ctxt, rule, - nodes, array, len, level, i); - if (ret == 0) - return(0); - } - } - } - *level = *level - 1; - array[k] = NULL; - return(-1); -} - /** * xmlRelaxNGNodeMatchesList: * @node: the node @@ -6355,91 +6363,6 @@ xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) { return(0); } -/** - * xmlRelaxNGValidatePartGroup: - * @ctxt: a Relax-NG validation context - * @groups: the array of groups - * @nbgroups: the number of groups in the array - * @nodes: the set of nodes - * @len: the size of the set of nodes - * - * Validate a set of nodes for a groups of definitions - * - * Returns 0 if the validation succeeded or an error code. - */ -static int -xmlRelaxNGValidatePartGroup(xmlRelaxNGValidCtxtPtr ctxt, - xmlRelaxNGInterleaveGroupPtr *groups, - int nbgroups, xmlNodePtr *nodes, int len) { - int level, ret = -1, i, j, k, top_j, max_j; - xmlNodePtr *array = NULL, *list, oldseq; - xmlRelaxNGInterleaveGroupPtr group; - - list = (xmlNodePtr *) xmlMalloc(len * sizeof(xmlNodePtr)); - if (list == NULL) { - return(-1); - } - array = (xmlNodePtr *) xmlMalloc(len * sizeof(xmlNodePtr)); - if (array == NULL) { - xmlFree(list); - return(-1); - } - memset(array, 0, len * sizeof(xmlNodePtr)); - - /* - * Partition the elements and validate the subsets. - */ - oldseq = ctxt->state->seq; - max_j = -1; - for (i = 0;i < nbgroups;i++) { - group = groups[i]; - if (group == NULL) - continue; - k = 0; - top_j = -1; - for (j = 0;j < len;j++) { - if (nodes[j] == NULL) - continue; - if (xmlRelaxNGNodeMatchesList(nodes[j], group->defs)) { - list[k++] = nodes[j]; - nodes[j] = NULL; - top_j = j; - } - } - if (top_j > max_j) - max_j = top_j; - ctxt->state->seq = oldseq; - if (k > 1) { - memset(array, 0, k * sizeof(xmlNodePtr)); - level = -1; - ret = xmlRelaxNGValidateWalkPermutations(ctxt, group->rule, - list, array, k, &level, -1); - } else { - ret = xmlRelaxNGValidateTryPermutation(ctxt, group->rule, list, k); - } - if (ret != 0) { - ctxt->state->seq = oldseq; - break; - } - } - - for (j = 0;j < max_j;j++) { - if (nodes[j] != NULL) { - TODO /* problem, one of the nodes didn't got a match */ - } - } - if (ret == 0) { - if (max_j + 1 < len) - ctxt->state->seq = nodes[max_j + 1]; - else - ctxt->state->seq = NULL; - } - - xmlFree(list); - xmlFree(array); - return(ret); -} - /** * xmlRelaxNGValidateInterleave: * @ctxt: a Relax-NG validation context @@ -6455,7 +6378,7 @@ xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, int ret = 0, i, nbgroups, left; xmlRelaxNGPartitionPtr partitions; xmlRelaxNGInterleaveGroupPtr group = NULL; - xmlNodePtr cur, start, last, lastchg = NULL, lastelem; + xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem; xmlNodePtr *list = NULL, *lasts = NULL; if (define->data != NULL) { diff --git a/tree.c b/tree.c index 7fc306c2..1a03a5ab 100644 --- a/tree.c +++ b/tree.c @@ -1402,6 +1402,8 @@ xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { #endif return(NULL); } + if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) + return(NULL); /* * Allocate a new property and fill the fields. @@ -5699,7 +5701,7 @@ xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { xmlAttrPtr prop; xmlDocPtr doc; - if ((node == NULL) || (name == NULL)) + if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) return(NULL); doc = node->doc; prop = node->properties;