diff --git a/ChangeLog b/ChangeLog index b02c16cb..b00df458 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Sat Apr 21 16:12:59 CEST 2001 Daniel Veillard + + * valid.c: cleanup, more useful debugging + * parserInternals.c: cleanup vctxt.nodeTab (de)allocation + * xmlIO.c: entity loading is printed as an error when validating + Sat Apr 21 12:25:49 CEST 2001 Daniel Veillard * valid.c: fixed to validate within entities diff --git a/parserInternals.c b/parserInternals.c index 37cb19e7..b9fd3cf4 100644 --- a/parserInternals.c +++ b/parserInternals.c @@ -277,17 +277,7 @@ xmlSetFeature(xmlParserCtxtPtr ctxt, const char *name, void *value) { ctxt->vctxt.warning = xmlParserValidityWarning; if (ctxt->vctxt.error == NULL) ctxt->vctxt.error = xmlParserValidityError; - /* Allocate the Node stack */ - ctxt->vctxt.nodeTab = (xmlNodePtr *) - xmlMalloc(4 * sizeof(xmlNodePtr)); - if (ctxt->vctxt.nodeTab == NULL) { - ctxt->vctxt.nodeMax = 0; - ctxt->validate = 0; - return(-1); - } - ctxt->vctxt.nodeNr = 0; - ctxt->vctxt.nodeMax = 4; - ctxt->vctxt.node = NULL; + ctxt->vctxt.nodeMax = 0; } ctxt->validate = newvalidate; } else if (!strcmp(name, "keep blanks")) { @@ -2223,20 +2213,7 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) ctxt->vctxt.warning = NULL; else ctxt->vctxt.warning = xmlParserValidityWarning; - /* Allocate the Node stack */ - ctxt->vctxt.nodeTab = (xmlNodePtr *) xmlMalloc(4 * sizeof(xmlNodePtr)); - if (ctxt->vctxt.nodeTab == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlInitParserCtxt: out of memory\n"); - ctxt->vctxt.nodeMax = 0; - ctxt->validate = 0; - ctxt->vctxt.error = NULL; - ctxt->vctxt.warning = NULL; - } else { - ctxt->vctxt.nodeNr = 0; - ctxt->vctxt.nodeMax = 4; - ctxt->vctxt.node = NULL; - } + ctxt->vctxt.nodeMax = 0; } else { ctxt->vctxt.error = NULL; ctxt->vctxt.warning = NULL; @@ -2283,7 +2260,6 @@ xmlFreeParserCtxt(xmlParserCtxtPtr ctxt) if (ctxt->intSubName != NULL) xmlFree((char *) ctxt->intSubName); if (ctxt->extSubURI != NULL) xmlFree((char *) ctxt->extSubURI); if (ctxt->extSubSystem != NULL) xmlFree((char *) ctxt->extSubSystem); - if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab); if ((ctxt->sax != NULL) && (ctxt->sax != &xmlDefaultSAXHandler)) xmlFree(ctxt->sax); if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory); diff --git a/valid.c b/valid.c index 48f7e15a..a1bb5bac 100644 --- a/valid.c +++ b/valid.c @@ -28,14 +28,22 @@ #include #include -#define ALLOW_UNDETERMINISTIC_MODELS - /* * Generic function for accessing stacks in the Validity Context */ #define PUSH_AND_POP(scope, type, name) \ scope int name##VPush(xmlValidCtxtPtr ctxt, type value) { \ + if (ctxt->name##Max <= 0) { \ + ctxt->name##Max = 4; \ + ctxt->name##Tab = (type *) xmlMalloc( \ + ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \ + if (ctxt->name##Tab == NULL) { \ + xmlGenericError(xmlGenericErrorContext, \ + "malloc failed !\n"); \ + return(0); \ + } \ + } \ if (ctxt->name##Nr >= ctxt->name##Max) { \ ctxt->name##Max *= 2; \ ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \ @@ -63,8 +71,6 @@ scope type name##VPop(xmlValidCtxtPtr ctxt) { \ return(ret); \ } \ -#ifdef ALLOW_UNDETERMINISTIC_MODELS - /* * I will use a home made algorithm less complex and easier to * debug/maintin than a generic NFA -> DFA state based algo. The @@ -133,9 +139,6 @@ vstateVPop(xmlValidCtxtPtr ctxt) { return(ctxt->vstateNr); } - -#endif /* ALLOW_UNDETERMINISTIC_MODELS */ - PUSH_AND_POP(static, xmlNodePtr, node) /* #define DEBUG_VALID_ALGO */ @@ -3228,270 +3231,6 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, return(ret); } -#ifndef ALLOW_UNDETERMINISTIC_MODELS - -/* Find the next XML_ELEMENT_NODE, subject to the content constraints. - * Return -1 if we found something unexpected, or 1 otherwise. - */ - -static int -xmlValidateFindNextElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child, - xmlElementContentPtr cont) -{ - DEBUG_VALID_MSG("skipping to next element"); - while (*child && (*child)->type != XML_ELEMENT_NODE) { - switch ((*child)->type) { - /* - * If there is an entity declared and it's not empty - * Push the current node on the stack and process with the - * entity content. - */ - case XML_ENTITY_REF_NODE: - if (((*child)->children != NULL) && - ((*child)->children->children != NULL)) { - nodeVPush(ctxt, *child); - *child = (*child)->children->children; - continue; - } - break; - - /* These things are ignored (skipped) during validation. */ - case XML_PI_NODE: - case XML_COMMENT_NODE: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - break; - - case XML_TEXT_NODE: - if (xmlIsBlankNode(*child) - && (cont->type == XML_ELEMENT_CONTENT_ELEMENT - || cont->type == XML_ELEMENT_CONTENT_SEQ - || cont->type == XML_ELEMENT_CONTENT_OR)) - break; - DEBUG_VALID_MSG("failed non-blank"); - return(-1); - - default: - DEBUG_VALID_MSG("failed unknown type"); - return(-1); - } - *child = (*child)->next; - } -#ifdef DEBUG_VALID_ALGO - if (*child != NULL) { - DEBUG_VALID_MSG((*child)->name); - } - DEBUG_VALID_MSG("found ..."); -#endif - - return(1); -} - -int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child, - xmlElementContentPtr cont); - -/** - * xmlValidateElementTypeExpr: - * @ctxt: the validation context - * @child: pointer to the child list - * @cont: pointer to the content declaration - * - * Try to validate the content of an element of type element - * but don't handle the occurence factor - * - * returns 1 if valid or 0 and -1 if PCDATA stuff is found, - * also update child value in-situ. - */ - -static int -xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child, - xmlElementContentPtr cont) { - xmlNodePtr cur; - int ret = 1; - - if (cont == NULL) return(-1); - DEBUG_VALID_STATE(*child, cont) - ret = xmlValidateFindNextElement(ctxt, child, cont); - if (ret < 0) - return(-1); - DEBUG_VALID_STATE(*child, cont) - switch (cont->type) { - case XML_ELEMENT_CONTENT_PCDATA: - if (*child == NULL) return(0); - if ((*child)->type == XML_TEXT_NODE) { - DEBUG_VALID_MSG("pcdata found"); - return(1); - } - return(0); - case XML_ELEMENT_CONTENT_ELEMENT: - if (*child == NULL) return(0); - ret = (xmlStrEqual((*child)->name, cont->name)); - if (ret == 1) { - DEBUG_VALID_MSG("element found, skip to next"); - while ((*child)->next == NULL) { - if (((*child)->parent != NULL) && - ((*child)->parent->type == XML_ENTITY_DECL)) { - *child = nodeVPop(ctxt); - } else - break; - } - *child = (*child)->next; - } - return(ret); - case XML_ELEMENT_CONTENT_OR: - cur = *child; - ret = xmlValidateElementTypeElement(ctxt, child, cont->c1); - if (ret == -1) return(-1); - if (ret == 1) { - DEBUG_VALID_MSG("or succeeded first branch"); - return(1); - } - /* rollback and retry the other path */ - *child = cur; - ret = xmlValidateElementTypeElement(ctxt, child, cont->c2); - if (ret == -1) return(-1); - if (ret == 0) { - DEBUG_VALID_MSG("or failed both branches"); - *child = cur; - return(0); - } - DEBUG_VALID_MSG("or succeeded second branch"); - return(1); - case XML_ELEMENT_CONTENT_SEQ: - cur = *child; - ret = xmlValidateElementTypeElement(ctxt, child, cont->c1); - if (ret == -1) return(-1); - if (ret == 0) { - DEBUG_VALID_MSG("sequence failed"); - *child = cur; - return(0); - } - ret = xmlValidateElementTypeElement(ctxt, child, cont->c2); - if (ret == -1) return(-1); - if (ret == 0) { - *child = cur; - return(0); - } - DEBUG_VALID_MSG("sequence succeeded"); - return(1); - } - return(ret); -} - -/** - * xmlValidateElementTypeElement: - * @ctxt: the validation context - * @child: pointer to the child list - * @cont: pointer to the content declaration - * - * Try to validate the content of an element of type element - * yeah, Yet Another Regexp Implementation, and recursive - * - * returns 1 if valid or 0 and -1 if PCDATA stuff is found, - * also update child and content values in-situ. - */ - -int -xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child, - xmlElementContentPtr cont) { - xmlNodePtr cur; - int ret; - - if (cont == NULL) return(-1); - - DEBUG_VALID_STATE(*child, cont) - ret = xmlValidateFindNextElement(ctxt, child, cont); - if (ret < 0) - return(-1); - DEBUG_VALID_STATE(*child, cont) - cur = *child; - ret = xmlValidateElementTypeExpr(ctxt, child, cont); - if (ret == -1) return(-1); - switch (cont->ocur) { - case XML_ELEMENT_CONTENT_ONCE: - if (ret == 1) { - DEBUG_VALID_MSG("once found, skip to next"); - /* skip ignorable elems */ - while ((*child != NULL) && - ((*child)->type == XML_PI_NODE - || (*child)->type == XML_COMMENT_NODE - || (*child)->type == XML_XINCLUDE_START - || (*child)->type == XML_XINCLUDE_END)) { - while ((*child)->next == NULL) { - if (((*child)->parent != NULL) && - ((*child)->parent->type == XML_ENTITY_REF_NODE)) { - *child = (*child)->parent; - } else - break; - } - *child = (*child)->next; - } - return(1); - } - *child = cur; - return(0); - case XML_ELEMENT_CONTENT_OPT: - if (ret == 0) { - *child = cur; - return(1); - } - if (ret == 1) { - DEBUG_VALID_MSG("optional found, skip to next"); - /* skip ignorable elems */ - while ((*child != NULL) && - ((*child)->type == XML_PI_NODE - || (*child)->type == XML_COMMENT_NODE - || (*child)->type == XML_XINCLUDE_START - || (*child)->type == XML_XINCLUDE_END)) { - while ((*child)->next == NULL) { - if (((*child)->parent != NULL) && - ((*child)->parent->type == XML_ENTITY_REF_NODE)) { - *child = (*child)->parent; - } else - break; - } - *child = (*child)->next; - } - return(1); - } - break; - case XML_ELEMENT_CONTENT_MULT: - if (ret == 0) { - *child = cur; - break; - } - /* no break on purpose */ - case XML_ELEMENT_CONTENT_PLUS: - if (ret == 0) { - *child = cur; - return(0); - } - DEBUG_VALID_MSG("mult/plus found"); - if (ret == -1) return(-1); - cur = *child; - do { - if (*child == NULL) - break; /* while */ - if ((*child)->type == XML_TEXT_NODE - && xmlIsBlankNode(*child)) { - *child = (*child)->next; - continue; - } - ret = xmlValidateElementTypeExpr(ctxt, child, cont); - if (ret == 1) - cur = *child; - } while (ret == 1); - if (ret == -1) return(-1); - *child = cur; - break; - } - if (ret == -1) return(-1); - - return(xmlValidateFindNextElement(ctxt, child, cont)); -} - -#else /* ALLOW_UNDETERMINISTIC_MODELS */ - /** * xmlValidateSkipIgnorable: * @ctxt: the validation context @@ -3832,11 +3571,74 @@ analyze: return(1); } +/** + * xmlSprintfElements: + * @buf: an output buffer + * @content: An element + * @glob: 1 if one must print the englobing parenthesis, 0 otherwise + * + * This will dump the list of elements to the buffer + * Intended just for the debug routine + */ +static void +xmlSprintfElements(char *buf, xmlNodePtr node, int glob) { + xmlNodePtr cur; + + if (node == NULL) return; + if (glob) strcat(buf, "("); + cur = node; + while (cur != NULL) { + switch (cur->type) { + case XML_ELEMENT_NODE: + strcat(buf, (char *) cur->name); + if (cur->next != NULL) + strcat(buf, " "); + break; + case XML_TEXT_NODE: + if (xmlIsBlankNode(cur)) + break; + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + strcat(buf, "CDATA"); + if (cur->next != NULL) + strcat(buf, " "); + break; + case XML_ATTRIBUTE_NODE: + case XML_DOCUMENT_NODE: +#ifdef LIBXML_SGML_ENABLED + case XML_SGML_DOCUMENT_NODE: +#endif + case XML_HTML_DOCUMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_NOTATION_NODE: + case XML_NAMESPACE_DECL: + strcat(buf, "???"); + if (cur->next != NULL) + strcat(buf, " "); + break; + case XML_ENTITY_NODE: + case XML_PI_NODE: + case XML_DTD_NODE: + case XML_COMMENT_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + break; + } + cur = cur->next; + } + if (glob) strcat(buf, ")"); +} + /** * xmlValidateElementContent: * @ctxt: the validation context * @child: the child list * @cont: pointer to the content declaration + * @warn: emit the error message * * Try to validate the content model of an element * @@ -3845,9 +3647,9 @@ analyze: static int xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, - xmlElementContentPtr cont) { + xmlElementContentPtr cont, int warn) { int ret; - xmlNodePtr repl = NULL, last = NULL, tmp; + xmlNodePtr repl = NULL, last = NULL, cur, tmp; /* * Allocate the stack @@ -3878,21 +3680,22 @@ xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, * sufficient to run the validation process on it */ DEBUG_VALID_MSG("Found an entity reference, linearizing"); - while (child != NULL) { - switch (child->type) { + cur = child; + while (cur != NULL) { + switch (cur->type) { case XML_ENTITY_REF_NODE: /* * Push the current node to be able to roll back * and process within the entity */ - if ((child->children != NULL) && - (child->children->children != NULL)) { - nodeVPush(ctxt, child); - child = child->children->children; + if ((cur->children != NULL) && + (cur->children->children != NULL)) { + nodeVPush(ctxt, cur); + cur = cur->children->children; continue; } case XML_TEXT_NODE: - if (xmlIsBlankNode(child)) + if (xmlIsBlankNode(cur)) break; case XML_ELEMENT_NODE: /* @@ -3907,9 +3710,9 @@ xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, ret = -1; goto done; } - tmp->type = child->type; - tmp->name = child->name; - tmp->ns = child->ns; + tmp->type = cur->type; + tmp->name = cur->name; + tmp->ns = cur->ns; tmp->next = NULL; if (repl == NULL) repl = last = tmp; @@ -3924,12 +3727,12 @@ xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, /* * Switch to next element */ - child = child->next; - while (child == NULL) { - child = nodeVPop(ctxt); - if (child == NULL) + cur = cur->next; + while (cur == NULL) { + cur = nodeVPop(ctxt); + if (cur == NULL) break; - child = child->next; + cur = cur->next; } } @@ -3945,6 +3748,29 @@ xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, STATE = 0; ret = xmlValidateElementType(ctxt); } + if ((warn) && (ret != 1)) { + char expr[5000]; + char list[5000]; + + expr[0] = 0; + xmlSprintfElementContent(expr, cont, 1); + list[0] = 0; + if (repl != NULL) + xmlSprintfElements(list, repl, 1); + else + xmlSprintfElements(list, child, 1); + + if ((child->parent != NULL) && (child->parent->name != NULL)) { + VERROR(ctxt->userData, + "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n", + child->parent->name, expr, list); + } else { + VERROR(ctxt->userData, + "Element content doesn't follow the Dtd\nExpecting %s, got %s\n", + expr, list); + } + ret = 0; + } done: @@ -3957,11 +3783,18 @@ done: repl = tmp; } ctxt->vstateMax = 0; - xmlFree(ctxt->vstateTab); + if (ctxt->vstateTab != NULL) { + xmlFree(ctxt->vstateTab); + ctxt->vstateTab = NULL; + } + ctxt->nodeMax = 0; + if (ctxt->nodeTab != NULL) { + xmlFree(ctxt->nodeTab); + ctxt->nodeTab = NULL; + } return(ret); } -#endif /* ALLOW_UNDETERMINISTIC_MODELS */ /** * xmlSprintfElementChilds: @@ -4229,45 +4062,8 @@ child_ok: case XML_ELEMENT_TYPE_ELEMENT: child = elem->children; cont = elemDecl->content; -#ifdef ALLOW_UNDETERMINISTIC_MODELS - ret = xmlValidateElementContent(ctxt, child, cont); - if (ret != 1) { - char expr[1000]; - char list[2000]; - - expr[0] = 0; - xmlSprintfElementContent(expr, cont, 1); - list[0] = 0; - xmlSprintfElementChilds(list, elem, 1); - - VERROR(ctxt->userData, - "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n", - elem->name, expr, list); - ret = 0; - } -#else - ret = xmlValidateElementTypeElement(ctxt, &child, cont); - while ((child != NULL) && (child->type == XML_TEXT_NODE) && - (xmlIsBlankNode(child))) { - child = child->next; - continue; - } - if ((ret == 0) || (child != NULL)) { - char expr[1000]; - char list[2000]; - - expr[0] = 0; - xmlSprintfElementContent(expr, cont, 1); - list[0] = 0; - xmlSprintfElementChilds(list, elem, 1); - - VERROR(ctxt->userData, - "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n", - elem->name, expr, list); - ret = 0; - } + ret = xmlValidateElementContent(ctxt, child, cont, 1); break; -#endif } /* [ VC: Required Attribute ] */ @@ -4293,7 +4089,8 @@ child_ok: if (nameSpace == NULL) { if (qualified < 0) qualified = 0; - } else if (!xmlStrEqual(nameSpace->prefix, attr->prefix)) { + } else if (!xmlStrEqual(nameSpace->prefix, + attr->prefix)) { if (qualified < 1) qualified = 1; } else diff --git a/xmlIO.c b/xmlIO.c index 2f3257b6..9560fb87 100644 --- a/xmlIO.c +++ b/xmlIO.c @@ -1598,14 +1598,22 @@ xmlDefaultExternalEntityLoader(const char *URL, const char *ID, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL); #endif if (URL == NULL) { - if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) + if ((ctxt->validate) && (ctxt->sax != NULL) && + (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt, + "failed to load external entity \"%s\"\n", ID); + else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n", ID); return(NULL); } ret = xmlNewInputFromFile(ctxt, URL); if (ret == NULL) { - if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) + if ((ctxt->validate) && (ctxt->sax != NULL) && + (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt, + "failed to load external entity \"%s\"\n", URL); + else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n", URL); }