File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / valid.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:31 2014 UTC (10 years ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    1: /*
    2:  * valid.c : part of the code use to do the DTD handling and the validity
    3:  *           checking
    4:  *
    5:  * See Copyright for the status of this software.
    6:  *
    7:  * daniel@veillard.com
    8:  */
    9: 
   10: #define IN_LIBXML
   11: #include "libxml.h"
   12: 
   13: #include <string.h>
   14: 
   15: #ifdef HAVE_STDLIB_H
   16: #include <stdlib.h>
   17: #endif
   18: 
   19: #include <libxml/xmlmemory.h>
   20: #include <libxml/hash.h>
   21: #include <libxml/uri.h>
   22: #include <libxml/valid.h>
   23: #include <libxml/parser.h>
   24: #include <libxml/parserInternals.h>
   25: #include <libxml/xmlerror.h>
   26: #include <libxml/list.h>
   27: #include <libxml/globals.h>
   28: 
   29: static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
   30: 	                           int create);
   31: /* #define DEBUG_VALID_ALGO */
   32: /* #define DEBUG_REGEXP_ALGO */
   33: 
   34: #define TODO								\
   35:     xmlGenericError(xmlGenericErrorContext,				\
   36: 	    "Unimplemented block at %s:%d\n",				\
   37:             __FILE__, __LINE__);
   38: 
   39: #ifdef LIBXML_VALID_ENABLED
   40: static int
   41: xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
   42:                                   const xmlChar *value);
   43: #endif
   44: /************************************************************************
   45:  *									*
   46:  *			Error handling routines				*
   47:  *									*
   48:  ************************************************************************/
   49: 
   50: /**
   51:  * xmlVErrMemory:
   52:  * @ctxt:  an XML validation parser context
   53:  * @extra:  extra informations
   54:  *
   55:  * Handle an out of memory error
   56:  */
   57: static void
   58: xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
   59: {
   60:     xmlGenericErrorFunc channel = NULL;
   61:     xmlParserCtxtPtr pctxt = NULL;
   62:     void *data = NULL;
   63: 
   64:     if (ctxt != NULL) {
   65:         channel = ctxt->error;
   66:         data = ctxt->userData;
   67: 	/* Use the special values to detect if it is part of a parsing
   68: 	   context */
   69: 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
   70: 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
   71: 	    long delta = (char *) ctxt - (char *) ctxt->userData;
   72: 	    if ((delta > 0) && (delta < 250))
   73: 		pctxt = ctxt->userData;
   74: 	}
   75:     }
   76:     if (extra)
   77:         __xmlRaiseError(NULL, channel, data,
   78:                         pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
   79:                         XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
   80:                         "Memory allocation failed : %s\n", extra);
   81:     else
   82:         __xmlRaiseError(NULL, channel, data,
   83:                         pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
   84:                         XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
   85:                         "Memory allocation failed\n");
   86: }
   87: 
   88: /**
   89:  * xmlErrValid:
   90:  * @ctxt:  an XML validation parser context
   91:  * @error:  the error number
   92:  * @extra:  extra informations
   93:  *
   94:  * Handle a validation error
   95:  */
   96: static void
   97: xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
   98:             const char *msg, const char *extra)
   99: {
  100:     xmlGenericErrorFunc channel = NULL;
  101:     xmlParserCtxtPtr pctxt = NULL;
  102:     void *data = NULL;
  103: 
  104:     if (ctxt != NULL) {
  105:         channel = ctxt->error;
  106:         data = ctxt->userData;
  107: 	/* Use the special values to detect if it is part of a parsing
  108: 	   context */
  109: 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
  110: 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
  111: 	    long delta = (char *) ctxt - (char *) ctxt->userData;
  112: 	    if ((delta > 0) && (delta < 250))
  113: 		pctxt = ctxt->userData;
  114: 	}
  115:     }
  116:     if (extra)
  117:         __xmlRaiseError(NULL, channel, data,
  118:                         pctxt, NULL, XML_FROM_VALID, error,
  119:                         XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
  120:                         msg, extra);
  121:     else
  122:         __xmlRaiseError(NULL, channel, data,
  123:                         pctxt, NULL, XML_FROM_VALID, error,
  124:                         XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
  125:                         "%s", msg);
  126: }
  127: 
  128: #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
  129: /**
  130:  * xmlErrValidNode:
  131:  * @ctxt:  an XML validation parser context
  132:  * @node:  the node raising the error
  133:  * @error:  the error number
  134:  * @str1:  extra informations
  135:  * @str2:  extra informations
  136:  * @str3:  extra informations
  137:  *
  138:  * Handle a validation error, provide contextual informations
  139:  */
  140: static void
  141: xmlErrValidNode(xmlValidCtxtPtr ctxt,
  142:                 xmlNodePtr node, xmlParserErrors error,
  143:                 const char *msg, const xmlChar * str1,
  144:                 const xmlChar * str2, const xmlChar * str3)
  145: {
  146:     xmlStructuredErrorFunc schannel = NULL;
  147:     xmlGenericErrorFunc channel = NULL;
  148:     xmlParserCtxtPtr pctxt = NULL;
  149:     void *data = NULL;
  150: 
  151:     if (ctxt != NULL) {
  152:         channel = ctxt->error;
  153:         data = ctxt->userData;
  154: 	/* Use the special values to detect if it is part of a parsing
  155: 	   context */
  156: 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
  157: 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
  158: 	    long delta = (char *) ctxt - (char *) ctxt->userData;
  159: 	    if ((delta > 0) && (delta < 250))
  160: 		pctxt = ctxt->userData;
  161: 	}
  162:     }
  163:     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
  164:                     XML_ERR_ERROR, NULL, 0,
  165:                     (const char *) str1,
  166:                     (const char *) str1,
  167:                     (const char *) str3, 0, 0, msg, str1, str2, str3);
  168: }
  169: #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
  170: 
  171: #ifdef LIBXML_VALID_ENABLED
  172: /**
  173:  * xmlErrValidNodeNr:
  174:  * @ctxt:  an XML validation parser context
  175:  * @node:  the node raising the error
  176:  * @error:  the error number
  177:  * @str1:  extra informations
  178:  * @int2:  extra informations
  179:  * @str3:  extra informations
  180:  *
  181:  * Handle a validation error, provide contextual informations
  182:  */
  183: static void
  184: xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
  185:                 xmlNodePtr node, xmlParserErrors error,
  186:                 const char *msg, const xmlChar * str1,
  187:                 int int2, const xmlChar * str3)
  188: {
  189:     xmlStructuredErrorFunc schannel = NULL;
  190:     xmlGenericErrorFunc channel = NULL;
  191:     xmlParserCtxtPtr pctxt = NULL;
  192:     void *data = NULL;
  193: 
  194:     if (ctxt != NULL) {
  195:         channel = ctxt->error;
  196:         data = ctxt->userData;
  197: 	/* Use the special values to detect if it is part of a parsing
  198: 	   context */
  199: 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
  200: 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
  201: 	    long delta = (char *) ctxt - (char *) ctxt->userData;
  202: 	    if ((delta > 0) && (delta < 250))
  203: 		pctxt = ctxt->userData;
  204: 	}
  205:     }
  206:     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
  207:                     XML_ERR_ERROR, NULL, 0,
  208:                     (const char *) str1,
  209:                     (const char *) str3,
  210:                     NULL, int2, 0, msg, str1, int2, str3);
  211: }
  212: 
  213: /**
  214:  * xmlErrValidWarning:
  215:  * @ctxt:  an XML validation parser context
  216:  * @node:  the node raising the error
  217:  * @error:  the error number
  218:  * @str1:  extra information
  219:  * @str2:  extra information
  220:  * @str3:  extra information
  221:  *
  222:  * Handle a validation error, provide contextual information
  223:  */
  224: static void
  225: xmlErrValidWarning(xmlValidCtxtPtr ctxt,
  226:                 xmlNodePtr node, xmlParserErrors error,
  227:                 const char *msg, const xmlChar * str1,
  228:                 const xmlChar * str2, const xmlChar * str3)
  229: {
  230:     xmlStructuredErrorFunc schannel = NULL;
  231:     xmlGenericErrorFunc channel = NULL;
  232:     xmlParserCtxtPtr pctxt = NULL;
  233:     void *data = NULL;
  234: 
  235:     if (ctxt != NULL) {
  236:         channel = ctxt->warning;
  237:         data = ctxt->userData;
  238: 	/* Use the special values to detect if it is part of a parsing
  239: 	   context */
  240: 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
  241: 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
  242: 	    long delta = (char *) ctxt - (char *) ctxt->userData;
  243: 	    if ((delta > 0) && (delta < 250))
  244: 		pctxt = ctxt->userData;
  245: 	}
  246:     }
  247:     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
  248:                     XML_ERR_WARNING, NULL, 0,
  249:                     (const char *) str1,
  250:                     (const char *) str1,
  251:                     (const char *) str3, 0, 0, msg, str1, str2, str3);
  252: }
  253: 
  254: 
  255: 
  256: #ifdef LIBXML_REGEXP_ENABLED
  257: /*
  258:  * If regexp are enabled we can do continuous validation without the
  259:  * need of a tree to validate the content model. this is done in each
  260:  * callbacks.
  261:  * Each xmlValidState represent the validation state associated to the
  262:  * set of nodes currently open from the document root to the current element.
  263:  */
  264: 
  265: 
  266: typedef struct _xmlValidState {
  267:     xmlElementPtr	 elemDecl;	/* pointer to the content model */
  268:     xmlNodePtr           node;		/* pointer to the current node */
  269:     xmlRegExecCtxtPtr    exec;		/* regexp runtime */
  270: } _xmlValidState;
  271: 
  272: 
  273: static int
  274: vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
  275:     if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
  276: 	ctxt->vstateMax = 10;
  277: 	ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
  278: 		              sizeof(ctxt->vstateTab[0]));
  279:         if (ctxt->vstateTab == NULL) {
  280: 	    xmlVErrMemory(ctxt, "malloc failed");
  281: 	    return(-1);
  282: 	}
  283:     }
  284: 
  285:     if (ctxt->vstateNr >= ctxt->vstateMax) {
  286:         xmlValidState *tmp;
  287: 
  288: 	tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
  289: 	             2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
  290:         if (tmp == NULL) {
  291: 	    xmlVErrMemory(ctxt, "realloc failed");
  292: 	    return(-1);
  293: 	}
  294: 	ctxt->vstateMax *= 2;
  295: 	ctxt->vstateTab = tmp;
  296:     }
  297:     ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
  298:     ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
  299:     ctxt->vstateTab[ctxt->vstateNr].node = node;
  300:     if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
  301: 	if (elemDecl->contModel == NULL)
  302: 	    xmlValidBuildContentModel(ctxt, elemDecl);
  303: 	if (elemDecl->contModel != NULL) {
  304: 	    ctxt->vstateTab[ctxt->vstateNr].exec =
  305: 		xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
  306: 	} else {
  307: 	    ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
  308: 	    xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
  309: 	                    XML_ERR_INTERNAL_ERROR,
  310: 			    "Failed to build content model regexp for %s\n",
  311: 			    node->name, NULL, NULL);
  312: 	}
  313:     }
  314:     return(ctxt->vstateNr++);
  315: }
  316: 
  317: static int
  318: vstateVPop(xmlValidCtxtPtr ctxt) {
  319:     xmlElementPtr elemDecl;
  320: 
  321:     if (ctxt->vstateNr < 1) return(-1);
  322:     ctxt->vstateNr--;
  323:     elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
  324:     ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
  325:     ctxt->vstateTab[ctxt->vstateNr].node = NULL;
  326:     if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
  327: 	xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
  328:     }
  329:     ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
  330:     if (ctxt->vstateNr >= 1)
  331: 	ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
  332:     else
  333: 	ctxt->vstate = NULL;
  334:     return(ctxt->vstateNr);
  335: }
  336: 
  337: #else /* not LIBXML_REGEXP_ENABLED */
  338: /*
  339:  * If regexp are not enabled, it uses a home made algorithm less
  340:  * complex and easier to
  341:  * debug/maintain than a generic NFA -> DFA state based algo. The
  342:  * only restriction is on the deepness of the tree limited by the
  343:  * size of the occurs bitfield
  344:  *
  345:  * this is the content of a saved state for rollbacks
  346:  */
  347: 
  348: #define ROLLBACK_OR	0
  349: #define ROLLBACK_PARENT	1
  350: 
  351: typedef struct _xmlValidState {
  352:     xmlElementContentPtr cont;	/* pointer to the content model subtree */
  353:     xmlNodePtr           node;	/* pointer to the current node in the list */
  354:     long                 occurs;/* bitfield for multiple occurrences */
  355:     unsigned char        depth; /* current depth in the overall tree */
  356:     unsigned char        state; /* ROLLBACK_XXX */
  357: } _xmlValidState;
  358: 
  359: #define MAX_RECURSE 25000
  360: #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
  361: #define CONT ctxt->vstate->cont
  362: #define NODE ctxt->vstate->node
  363: #define DEPTH ctxt->vstate->depth
  364: #define OCCURS ctxt->vstate->occurs
  365: #define STATE ctxt->vstate->state
  366: 
  367: #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
  368: #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
  369: 
  370: #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
  371: #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
  372: 
  373: static int
  374: vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
  375: 	    xmlNodePtr node, unsigned char depth, long occurs,
  376: 	    unsigned char state) {
  377:     int i = ctxt->vstateNr - 1;
  378: 
  379:     if (ctxt->vstateNr > MAX_RECURSE) {
  380: 	return(-1);
  381:     }
  382:     if (ctxt->vstateTab == NULL) {
  383: 	ctxt->vstateMax = 8;
  384: 	ctxt->vstateTab = (xmlValidState *) xmlMalloc(
  385: 		     ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
  386: 	if (ctxt->vstateTab == NULL) {
  387: 	    xmlVErrMemory(ctxt, "malloc failed");
  388: 	    return(-1);
  389: 	}
  390:     }
  391:     if (ctxt->vstateNr >= ctxt->vstateMax) {
  392:         xmlValidState *tmp;
  393: 
  394:         tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
  395: 	             2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
  396:         if (tmp == NULL) {
  397: 	    xmlVErrMemory(ctxt, "malloc failed");
  398: 	    return(-1);
  399: 	}
  400: 	ctxt->vstateMax *= 2;
  401: 	ctxt->vstateTab = tmp;
  402: 	ctxt->vstate = &ctxt->vstateTab[0];
  403:     }
  404:     /*
  405:      * Don't push on the stack a state already here
  406:      */
  407:     if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
  408: 	(ctxt->vstateTab[i].node == node) &&
  409: 	(ctxt->vstateTab[i].depth == depth) &&
  410: 	(ctxt->vstateTab[i].occurs == occurs) &&
  411: 	(ctxt->vstateTab[i].state == state))
  412: 	return(ctxt->vstateNr);
  413:     ctxt->vstateTab[ctxt->vstateNr].cont = cont;
  414:     ctxt->vstateTab[ctxt->vstateNr].node = node;
  415:     ctxt->vstateTab[ctxt->vstateNr].depth = depth;
  416:     ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
  417:     ctxt->vstateTab[ctxt->vstateNr].state = state;
  418:     return(ctxt->vstateNr++);
  419: }
  420: 
  421: static int
  422: vstateVPop(xmlValidCtxtPtr ctxt) {
  423:     if (ctxt->vstateNr <= 1) return(-1);
  424:     ctxt->vstateNr--;
  425:     ctxt->vstate = &ctxt->vstateTab[0];
  426:     ctxt->vstate->cont =  ctxt->vstateTab[ctxt->vstateNr].cont;
  427:     ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
  428:     ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
  429:     ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
  430:     ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
  431:     return(ctxt->vstateNr);
  432: }
  433: 
  434: #endif /* LIBXML_REGEXP_ENABLED */
  435: 
  436: static int
  437: nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
  438: {
  439:     if (ctxt->nodeMax <= 0) {
  440:         ctxt->nodeMax = 4;
  441:         ctxt->nodeTab =
  442:             (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
  443:                                      sizeof(ctxt->nodeTab[0]));
  444:         if (ctxt->nodeTab == NULL) {
  445: 	    xmlVErrMemory(ctxt, "malloc failed");
  446:             ctxt->nodeMax = 0;
  447:             return (0);
  448:         }
  449:     }
  450:     if (ctxt->nodeNr >= ctxt->nodeMax) {
  451:         xmlNodePtr *tmp;
  452:         tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
  453: 			      ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
  454:         if (tmp == NULL) {
  455: 	    xmlVErrMemory(ctxt, "realloc failed");
  456:             return (0);
  457:         }
  458:         ctxt->nodeMax *= 2;
  459: 	ctxt->nodeTab = tmp;
  460:     }
  461:     ctxt->nodeTab[ctxt->nodeNr] = value;
  462:     ctxt->node = value;
  463:     return (ctxt->nodeNr++);
  464: }
  465: static xmlNodePtr
  466: nodeVPop(xmlValidCtxtPtr ctxt)
  467: {
  468:     xmlNodePtr ret;
  469: 
  470:     if (ctxt->nodeNr <= 0)
  471:         return (NULL);
  472:     ctxt->nodeNr--;
  473:     if (ctxt->nodeNr > 0)
  474:         ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
  475:     else
  476:         ctxt->node = NULL;
  477:     ret = ctxt->nodeTab[ctxt->nodeNr];
  478:     ctxt->nodeTab[ctxt->nodeNr] = NULL;
  479:     return (ret);
  480: }
  481: 
  482: #ifdef DEBUG_VALID_ALGO
  483: static void
  484: xmlValidPrintNode(xmlNodePtr cur) {
  485:     if (cur == NULL) {
  486: 	xmlGenericError(xmlGenericErrorContext, "null");
  487: 	return;
  488:     }
  489:     switch (cur->type) {
  490: 	case XML_ELEMENT_NODE:
  491: 	    xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
  492: 	    break;
  493: 	case XML_TEXT_NODE:
  494: 	    xmlGenericError(xmlGenericErrorContext, "text ");
  495: 	    break;
  496: 	case XML_CDATA_SECTION_NODE:
  497: 	    xmlGenericError(xmlGenericErrorContext, "cdata ");
  498: 	    break;
  499: 	case XML_ENTITY_REF_NODE:
  500: 	    xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
  501: 	    break;
  502: 	case XML_PI_NODE:
  503: 	    xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
  504: 	    break;
  505: 	case XML_COMMENT_NODE:
  506: 	    xmlGenericError(xmlGenericErrorContext, "comment ");
  507: 	    break;
  508: 	case XML_ATTRIBUTE_NODE:
  509: 	    xmlGenericError(xmlGenericErrorContext, "?attr? ");
  510: 	    break;
  511: 	case XML_ENTITY_NODE:
  512: 	    xmlGenericError(xmlGenericErrorContext, "?ent? ");
  513: 	    break;
  514: 	case XML_DOCUMENT_NODE:
  515: 	    xmlGenericError(xmlGenericErrorContext, "?doc? ");
  516: 	    break;
  517: 	case XML_DOCUMENT_TYPE_NODE:
  518: 	    xmlGenericError(xmlGenericErrorContext, "?doctype? ");
  519: 	    break;
  520: 	case XML_DOCUMENT_FRAG_NODE:
  521: 	    xmlGenericError(xmlGenericErrorContext, "?frag? ");
  522: 	    break;
  523: 	case XML_NOTATION_NODE:
  524: 	    xmlGenericError(xmlGenericErrorContext, "?nota? ");
  525: 	    break;
  526: 	case XML_HTML_DOCUMENT_NODE:
  527: 	    xmlGenericError(xmlGenericErrorContext, "?html? ");
  528: 	    break;
  529: #ifdef LIBXML_DOCB_ENABLED
  530: 	case XML_DOCB_DOCUMENT_NODE:
  531: 	    xmlGenericError(xmlGenericErrorContext, "?docb? ");
  532: 	    break;
  533: #endif
  534: 	case XML_DTD_NODE:
  535: 	    xmlGenericError(xmlGenericErrorContext, "?dtd? ");
  536: 	    break;
  537: 	case XML_ELEMENT_DECL:
  538: 	    xmlGenericError(xmlGenericErrorContext, "?edecl? ");
  539: 	    break;
  540: 	case XML_ATTRIBUTE_DECL:
  541: 	    xmlGenericError(xmlGenericErrorContext, "?adecl? ");
  542: 	    break;
  543: 	case XML_ENTITY_DECL:
  544: 	    xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
  545: 	    break;
  546: 	case XML_NAMESPACE_DECL:
  547: 	    xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
  548: 	    break;
  549: 	case XML_XINCLUDE_START:
  550: 	    xmlGenericError(xmlGenericErrorContext, "incstart ");
  551: 	    break;
  552: 	case XML_XINCLUDE_END:
  553: 	    xmlGenericError(xmlGenericErrorContext, "incend ");
  554: 	    break;
  555:     }
  556: }
  557: 
  558: static void
  559: xmlValidPrintNodeList(xmlNodePtr cur) {
  560:     if (cur == NULL)
  561: 	xmlGenericError(xmlGenericErrorContext, "null ");
  562:     while (cur != NULL) {
  563: 	xmlValidPrintNode(cur);
  564: 	cur = cur->next;
  565:     }
  566: }
  567: 
  568: static void
  569: xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
  570:     char expr[5000];
  571: 
  572:     expr[0] = 0;
  573:     xmlGenericError(xmlGenericErrorContext, "valid: ");
  574:     xmlValidPrintNodeList(cur);
  575:     xmlGenericError(xmlGenericErrorContext, "against ");
  576:     xmlSnprintfElementContent(expr, 5000, cont, 1);
  577:     xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
  578: }
  579: 
  580: static void
  581: xmlValidDebugState(xmlValidStatePtr state) {
  582:     xmlGenericError(xmlGenericErrorContext, "(");
  583:     if (state->cont == NULL)
  584: 	xmlGenericError(xmlGenericErrorContext, "null,");
  585:     else
  586: 	switch (state->cont->type) {
  587:             case XML_ELEMENT_CONTENT_PCDATA:
  588: 		xmlGenericError(xmlGenericErrorContext, "pcdata,");
  589: 		break;
  590:             case XML_ELEMENT_CONTENT_ELEMENT:
  591: 		xmlGenericError(xmlGenericErrorContext, "%s,",
  592: 			        state->cont->name);
  593: 		break;
  594:             case XML_ELEMENT_CONTENT_SEQ:
  595: 		xmlGenericError(xmlGenericErrorContext, "seq,");
  596: 		break;
  597:             case XML_ELEMENT_CONTENT_OR:
  598: 		xmlGenericError(xmlGenericErrorContext, "or,");
  599: 		break;
  600: 	}
  601:     xmlValidPrintNode(state->node);
  602:     xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
  603: 	    state->depth, state->occurs, state->state);
  604: }
  605: 
  606: static void
  607: xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
  608:     int i, j;
  609: 
  610:     xmlGenericError(xmlGenericErrorContext, "state: ");
  611:     xmlValidDebugState(ctxt->vstate);
  612:     xmlGenericError(xmlGenericErrorContext, " stack: %d ",
  613: 	    ctxt->vstateNr - 1);
  614:     for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
  615: 	xmlValidDebugState(&ctxt->vstateTab[j]);
  616:     xmlGenericError(xmlGenericErrorContext, "\n");
  617: }
  618: 
  619: /*****
  620: #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
  621:  *****/
  622: 
  623: #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
  624: #define DEBUG_VALID_MSG(m)					\
  625:     xmlGenericError(xmlGenericErrorContext, "%s\n", m);
  626: 
  627: #else
  628: #define DEBUG_VALID_STATE(n,c)
  629: #define DEBUG_VALID_MSG(m)
  630: #endif
  631: 
  632: /* TODO: use hash table for accesses to elem and attribute definitions */
  633: 
  634: 
  635: #define CHECK_DTD						\
  636:    if (doc == NULL) return(0);					\
  637:    else if ((doc->intSubset == NULL) &&				\
  638: 	    (doc->extSubset == NULL)) return(0)
  639: 
  640: #ifdef LIBXML_REGEXP_ENABLED
  641: 
  642: /************************************************************************
  643:  *									*
  644:  *		Content model validation based on the regexps		*
  645:  *									*
  646:  ************************************************************************/
  647: 
  648: /**
  649:  * xmlValidBuildAContentModel:
  650:  * @content:  the content model
  651:  * @ctxt:  the schema parser context
  652:  * @name:  the element name whose content is being built
  653:  *
  654:  * Generate the automata sequence needed for that type
  655:  *
  656:  * Returns 1 if successful or 0 in case of error.
  657:  */
  658: static int
  659: xmlValidBuildAContentModel(xmlElementContentPtr content,
  660: 		           xmlValidCtxtPtr ctxt,
  661: 		           const xmlChar *name) {
  662:     if (content == NULL) {
  663: 	xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
  664: 			"Found NULL content in content model of %s\n",
  665: 			name, NULL, NULL);
  666: 	return(0);
  667:     }
  668:     switch (content->type) {
  669: 	case XML_ELEMENT_CONTENT_PCDATA:
  670: 	    xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
  671: 			    "Found PCDATA in content model of %s\n",
  672: 		            name, NULL, NULL);
  673: 	    return(0);
  674: 	    break;
  675: 	case XML_ELEMENT_CONTENT_ELEMENT: {
  676: 	    xmlAutomataStatePtr oldstate = ctxt->state;
  677: 	    xmlChar fn[50];
  678: 	    xmlChar *fullname;
  679: 
  680: 	    fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
  681: 	    if (fullname == NULL) {
  682: 	        xmlVErrMemory(ctxt, "Building content model");
  683: 		return(0);
  684: 	    }
  685: 
  686: 	    switch (content->ocur) {
  687: 		case XML_ELEMENT_CONTENT_ONCE:
  688: 		    ctxt->state = xmlAutomataNewTransition(ctxt->am,
  689: 			    ctxt->state, NULL, fullname, NULL);
  690: 		    break;
  691: 		case XML_ELEMENT_CONTENT_OPT:
  692: 		    ctxt->state = xmlAutomataNewTransition(ctxt->am,
  693: 			    ctxt->state, NULL, fullname, NULL);
  694: 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
  695: 		    break;
  696: 		case XML_ELEMENT_CONTENT_PLUS:
  697: 		    ctxt->state = xmlAutomataNewTransition(ctxt->am,
  698: 			    ctxt->state, NULL, fullname, NULL);
  699: 		    xmlAutomataNewTransition(ctxt->am, ctxt->state,
  700: 			                     ctxt->state, fullname, NULL);
  701: 		    break;
  702: 		case XML_ELEMENT_CONTENT_MULT:
  703: 		    ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
  704: 					    ctxt->state, NULL);
  705: 		    xmlAutomataNewTransition(ctxt->am,
  706: 			    ctxt->state, ctxt->state, fullname, NULL);
  707: 		    break;
  708: 	    }
  709: 	    if ((fullname != fn) && (fullname != content->name))
  710: 		xmlFree(fullname);
  711: 	    break;
  712: 	}
  713: 	case XML_ELEMENT_CONTENT_SEQ: {
  714: 	    xmlAutomataStatePtr oldstate, oldend;
  715: 	    xmlElementContentOccur ocur;
  716: 
  717: 	    /*
  718: 	     * Simply iterate over the content
  719: 	     */
  720: 	    oldstate = ctxt->state;
  721: 	    ocur = content->ocur;
  722: 	    if (ocur != XML_ELEMENT_CONTENT_ONCE) {
  723: 		ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
  724: 		oldstate = ctxt->state;
  725: 	    }
  726: 	    do {
  727: 		xmlValidBuildAContentModel(content->c1, ctxt, name);
  728: 		content = content->c2;
  729: 	    } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
  730: 		     (content->ocur == XML_ELEMENT_CONTENT_ONCE));
  731: 	    xmlValidBuildAContentModel(content, ctxt, name);
  732: 	    oldend = ctxt->state;
  733: 	    ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
  734: 	    switch (ocur) {
  735: 		case XML_ELEMENT_CONTENT_ONCE:
  736: 		    break;
  737: 		case XML_ELEMENT_CONTENT_OPT:
  738: 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
  739: 		    break;
  740: 		case XML_ELEMENT_CONTENT_MULT:
  741: 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
  742: 		    xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
  743: 		    break;
  744: 		case XML_ELEMENT_CONTENT_PLUS:
  745: 		    xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
  746: 		    break;
  747: 	    }
  748: 	    break;
  749: 	}
  750: 	case XML_ELEMENT_CONTENT_OR: {
  751: 	    xmlAutomataStatePtr oldstate, oldend;
  752: 	    xmlElementContentOccur ocur;
  753: 
  754: 	    ocur = content->ocur;
  755: 	    if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
  756: 		(ocur == XML_ELEMENT_CONTENT_MULT)) {
  757: 		ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
  758: 			ctxt->state, NULL);
  759: 	    }
  760: 	    oldstate = ctxt->state;
  761: 	    oldend = xmlAutomataNewState(ctxt->am);
  762: 
  763: 	    /*
  764: 	     * iterate over the subtypes and remerge the end with an
  765: 	     * epsilon transition
  766: 	     */
  767: 	    do {
  768: 		ctxt->state = oldstate;
  769: 		xmlValidBuildAContentModel(content->c1, ctxt, name);
  770: 		xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
  771: 		content = content->c2;
  772: 	    } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
  773: 		     (content->ocur == XML_ELEMENT_CONTENT_ONCE));
  774: 	    ctxt->state = oldstate;
  775: 	    xmlValidBuildAContentModel(content, ctxt, name);
  776: 	    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
  777: 	    ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
  778: 	    switch (ocur) {
  779: 		case XML_ELEMENT_CONTENT_ONCE:
  780: 		    break;
  781: 		case XML_ELEMENT_CONTENT_OPT:
  782: 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
  783: 		    break;
  784: 		case XML_ELEMENT_CONTENT_MULT:
  785: 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
  786: 		    xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
  787: 		    break;
  788: 		case XML_ELEMENT_CONTENT_PLUS:
  789: 		    xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
  790: 		    break;
  791: 	    }
  792: 	    break;
  793: 	}
  794: 	default:
  795: 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
  796: 	                "ContentModel broken for element %s\n",
  797: 			(const char *) name);
  798: 	    return(0);
  799:     }
  800:     return(1);
  801: }
  802: /**
  803:  * xmlValidBuildContentModel:
  804:  * @ctxt:  a validation context
  805:  * @elem:  an element declaration node
  806:  *
  807:  * (Re)Build the automata associated to the content model of this
  808:  * element
  809:  *
  810:  * Returns 1 in case of success, 0 in case of error
  811:  */
  812: int
  813: xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
  814: 
  815:     if ((ctxt == NULL) || (elem == NULL))
  816: 	return(0);
  817:     if (elem->type != XML_ELEMENT_DECL)
  818: 	return(0);
  819:     if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
  820: 	return(1);
  821:     /* TODO: should we rebuild in this case ? */
  822:     if (elem->contModel != NULL) {
  823: 	if (!xmlRegexpIsDeterminist(elem->contModel)) {
  824: 	    ctxt->valid = 0;
  825: 	    return(0);
  826: 	}
  827: 	return(1);
  828:     }
  829: 
  830:     ctxt->am = xmlNewAutomata();
  831:     if (ctxt->am == NULL) {
  832: 	xmlErrValidNode(ctxt, (xmlNodePtr) elem,
  833: 	                XML_ERR_INTERNAL_ERROR,
  834: 	                "Cannot create automata for element %s\n",
  835: 		        elem->name, NULL, NULL);
  836: 	return(0);
  837:     }
  838:     ctxt->state = xmlAutomataGetInitState(ctxt->am);
  839:     xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
  840:     xmlAutomataSetFinalState(ctxt->am, ctxt->state);
  841:     elem->contModel = xmlAutomataCompile(ctxt->am);
  842:     if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
  843: 	char expr[5000];
  844: 	expr[0] = 0;
  845: 	xmlSnprintfElementContent(expr, 5000, elem->content, 1);
  846: 	xmlErrValidNode(ctxt, (xmlNodePtr) elem,
  847: 	                XML_DTD_CONTENT_NOT_DETERMINIST,
  848: 	       "Content model of %s is not determinist: %s\n",
  849: 	       elem->name, BAD_CAST expr, NULL);
  850: #ifdef DEBUG_REGEXP_ALGO
  851:         xmlRegexpPrint(stderr, elem->contModel);
  852: #endif
  853:         ctxt->valid = 0;
  854: 	ctxt->state = NULL;
  855: 	xmlFreeAutomata(ctxt->am);
  856: 	ctxt->am = NULL;
  857: 	return(0);
  858:     }
  859:     ctxt->state = NULL;
  860:     xmlFreeAutomata(ctxt->am);
  861:     ctxt->am = NULL;
  862:     return(1);
  863: }
  864: 
  865: #endif /* LIBXML_REGEXP_ENABLED */
  866: 
  867: /****************************************************************
  868:  *								*
  869:  *	Util functions for data allocation/deallocation		*
  870:  *								*
  871:  ****************************************************************/
  872: 
  873: /**
  874:  * xmlNewValidCtxt:
  875:  *
  876:  * Allocate a validation context structure.
  877:  *
  878:  * Returns NULL if not, otherwise the new validation context structure
  879:  */
  880: xmlValidCtxtPtr xmlNewValidCtxt(void) {
  881:     xmlValidCtxtPtr ret;
  882: 
  883:     if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
  884: 	xmlVErrMemory(NULL, "malloc failed");
  885: 	return (NULL);
  886:     }
  887: 
  888:     (void) memset(ret, 0, sizeof (xmlValidCtxt));
  889: 
  890:     return (ret);
  891: }
  892: 
  893: /**
  894:  * xmlFreeValidCtxt:
  895:  * @cur:  the validation context to free
  896:  *
  897:  * Free a validation context structure.
  898:  */
  899: void
  900: xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
  901:     if (cur->vstateTab != NULL)
  902:         xmlFree(cur->vstateTab);
  903:     if (cur->nodeTab != NULL)
  904:         xmlFree(cur->nodeTab);
  905:     xmlFree(cur);
  906: }
  907: 
  908: #endif /* LIBXML_VALID_ENABLED */
  909: 
  910: /**
  911:  * xmlNewDocElementContent:
  912:  * @doc:  the document
  913:  * @name:  the subelement name or NULL
  914:  * @type:  the type of element content decl
  915:  *
  916:  * Allocate an element content structure for the document.
  917:  *
  918:  * Returns NULL if not, otherwise the new element content structure
  919:  */
  920: xmlElementContentPtr
  921: xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
  922:                         xmlElementContentType type) {
  923:     xmlElementContentPtr ret;
  924:     xmlDictPtr dict = NULL;
  925: 
  926:     if (doc != NULL)
  927:         dict = doc->dict;
  928: 
  929:     switch(type) {
  930: 	case XML_ELEMENT_CONTENT_ELEMENT:
  931: 	    if (name == NULL) {
  932: 	        xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
  933: 			"xmlNewElementContent : name == NULL !\n",
  934: 			NULL);
  935: 	    }
  936: 	    break;
  937:         case XML_ELEMENT_CONTENT_PCDATA:
  938: 	case XML_ELEMENT_CONTENT_SEQ:
  939: 	case XML_ELEMENT_CONTENT_OR:
  940: 	    if (name != NULL) {
  941: 	        xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
  942: 			"xmlNewElementContent : name != NULL !\n",
  943: 			NULL);
  944: 	    }
  945: 	    break;
  946: 	default:
  947: 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
  948: 		    "Internal: ELEMENT content corrupted invalid type\n",
  949: 		    NULL);
  950: 	    return(NULL);
  951:     }
  952:     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
  953:     if (ret == NULL) {
  954: 	xmlVErrMemory(NULL, "malloc failed");
  955: 	return(NULL);
  956:     }
  957:     memset(ret, 0, sizeof(xmlElementContent));
  958:     ret->type = type;
  959:     ret->ocur = XML_ELEMENT_CONTENT_ONCE;
  960:     if (name != NULL) {
  961:         int l;
  962: 	const xmlChar *tmp;
  963: 
  964: 	tmp = xmlSplitQName3(name, &l);
  965: 	if (tmp == NULL) {
  966: 	    if (dict == NULL)
  967: 		ret->name = xmlStrdup(name);
  968: 	    else
  969: 	        ret->name = xmlDictLookup(dict, name, -1);
  970: 	} else {
  971: 	    if (dict == NULL) {
  972: 		ret->prefix = xmlStrndup(name, l);
  973: 		ret->name = xmlStrdup(tmp);
  974: 	    } else {
  975: 	        ret->prefix = xmlDictLookup(dict, name, l);
  976: 		ret->name = xmlDictLookup(dict, tmp, -1);
  977: 	    }
  978: 	}
  979:     }
  980:     return(ret);
  981: }
  982: 
  983: /**
  984:  * xmlNewElementContent:
  985:  * @name:  the subelement name or NULL
  986:  * @type:  the type of element content decl
  987:  *
  988:  * Allocate an element content structure.
  989:  * Deprecated in favor of xmlNewDocElementContent
  990:  *
  991:  * Returns NULL if not, otherwise the new element content structure
  992:  */
  993: xmlElementContentPtr
  994: xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
  995:     return(xmlNewDocElementContent(NULL, name, type));
  996: }
  997: 
  998: /**
  999:  * xmlCopyDocElementContent:
 1000:  * @doc:  the document owning the element declaration
 1001:  * @cur:  An element content pointer.
 1002:  *
 1003:  * Build a copy of an element content description.
 1004:  *
 1005:  * Returns the new xmlElementContentPtr or NULL in case of error.
 1006:  */
 1007: xmlElementContentPtr
 1008: xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
 1009:     xmlElementContentPtr ret = NULL, prev = NULL, tmp;
 1010:     xmlDictPtr dict = NULL;
 1011: 
 1012:     if (cur == NULL) return(NULL);
 1013: 
 1014:     if (doc != NULL)
 1015:         dict = doc->dict;
 1016: 
 1017:     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
 1018:     if (ret == NULL) {
 1019: 	xmlVErrMemory(NULL, "malloc failed");
 1020: 	return(NULL);
 1021:     }
 1022:     memset(ret, 0, sizeof(xmlElementContent));
 1023:     ret->type = cur->type;
 1024:     ret->ocur = cur->ocur;
 1025:     if (cur->name != NULL) {
 1026: 	if (dict)
 1027: 	    ret->name = xmlDictLookup(dict, cur->name, -1);
 1028: 	else
 1029: 	    ret->name = xmlStrdup(cur->name);
 1030:     }
 1031: 
 1032:     if (cur->prefix != NULL) {
 1033: 	if (dict)
 1034: 	    ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
 1035: 	else
 1036: 	    ret->prefix = xmlStrdup(cur->prefix);
 1037:     }
 1038:     if (cur->c1 != NULL)
 1039:         ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
 1040:     if (ret->c1 != NULL)
 1041: 	ret->c1->parent = ret;
 1042:     if (cur->c2 != NULL) {
 1043:         prev = ret;
 1044: 	cur = cur->c2;
 1045: 	while (cur != NULL) {
 1046: 	    tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
 1047: 	    if (tmp == NULL) {
 1048: 		xmlVErrMemory(NULL, "malloc failed");
 1049: 		return(ret);
 1050: 	    }
 1051: 	    memset(tmp, 0, sizeof(xmlElementContent));
 1052: 	    tmp->type = cur->type;
 1053: 	    tmp->ocur = cur->ocur;
 1054: 	    prev->c2 = tmp;
 1055: 	    if (cur->name != NULL) {
 1056: 		if (dict)
 1057: 		    tmp->name = xmlDictLookup(dict, cur->name, -1);
 1058: 		else
 1059: 		    tmp->name = xmlStrdup(cur->name);
 1060: 	    }
 1061: 
 1062: 	    if (cur->prefix != NULL) {
 1063: 		if (dict)
 1064: 		    tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
 1065: 		else
 1066: 		    tmp->prefix = xmlStrdup(cur->prefix);
 1067: 	    }
 1068: 	    if (cur->c1 != NULL)
 1069: 	        tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
 1070: 	    if (tmp->c1 != NULL)
 1071: 		tmp->c1->parent = ret;
 1072: 	    prev = tmp;
 1073: 	    cur = cur->c2;
 1074: 	}
 1075:     }
 1076:     return(ret);
 1077: }
 1078: 
 1079: /**
 1080:  * xmlCopyElementContent:
 1081:  * @cur:  An element content pointer.
 1082:  *
 1083:  * Build a copy of an element content description.
 1084:  * Deprecated, use xmlCopyDocElementContent instead
 1085:  *
 1086:  * Returns the new xmlElementContentPtr or NULL in case of error.
 1087:  */
 1088: xmlElementContentPtr
 1089: xmlCopyElementContent(xmlElementContentPtr cur) {
 1090:     return(xmlCopyDocElementContent(NULL, cur));
 1091: }
 1092: 
 1093: /**
 1094:  * xmlFreeDocElementContent:
 1095:  * @doc: the document owning the element declaration
 1096:  * @cur:  the element content tree to free
 1097:  *
 1098:  * Free an element content structure. The whole subtree is removed.
 1099:  */
 1100: void
 1101: xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
 1102:     xmlElementContentPtr next;
 1103:     xmlDictPtr dict = NULL;
 1104: 
 1105:     if (doc != NULL)
 1106:         dict = doc->dict;
 1107: 
 1108:     while (cur != NULL) {
 1109:         next = cur->c2;
 1110: 	switch (cur->type) {
 1111: 	    case XML_ELEMENT_CONTENT_PCDATA:
 1112: 	    case XML_ELEMENT_CONTENT_ELEMENT:
 1113: 	    case XML_ELEMENT_CONTENT_SEQ:
 1114: 	    case XML_ELEMENT_CONTENT_OR:
 1115: 		break;
 1116: 	    default:
 1117: 		xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
 1118: 			"Internal: ELEMENT content corrupted invalid type\n",
 1119: 			NULL);
 1120: 		return;
 1121: 	}
 1122: 	if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
 1123: 	if (dict) {
 1124: 	    if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
 1125: 	        xmlFree((xmlChar *) cur->name);
 1126: 	    if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
 1127: 	        xmlFree((xmlChar *) cur->prefix);
 1128: 	} else {
 1129: 	    if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
 1130: 	    if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
 1131: 	}
 1132: 	xmlFree(cur);
 1133: 	cur = next;
 1134:     }
 1135: }
 1136: 
 1137: /**
 1138:  * xmlFreeElementContent:
 1139:  * @cur:  the element content tree to free
 1140:  *
 1141:  * Free an element content structure. The whole subtree is removed.
 1142:  * Deprecated, use xmlFreeDocElementContent instead
 1143:  */
 1144: void
 1145: xmlFreeElementContent(xmlElementContentPtr cur) {
 1146:     xmlFreeDocElementContent(NULL, cur);
 1147: }
 1148: 
 1149: #ifdef LIBXML_OUTPUT_ENABLED
 1150: /**
 1151:  * xmlDumpElementContent:
 1152:  * @buf:  An XML buffer
 1153:  * @content:  An element table
 1154:  * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
 1155:  *
 1156:  * This will dump the content of the element table as an XML DTD definition
 1157:  */
 1158: static void
 1159: xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
 1160:     if (content == NULL) return;
 1161: 
 1162:     if (glob) xmlBufferWriteChar(buf, "(");
 1163:     switch (content->type) {
 1164:         case XML_ELEMENT_CONTENT_PCDATA:
 1165:             xmlBufferWriteChar(buf, "#PCDATA");
 1166: 	    break;
 1167: 	case XML_ELEMENT_CONTENT_ELEMENT:
 1168: 	    if (content->prefix != NULL) {
 1169: 		xmlBufferWriteCHAR(buf, content->prefix);
 1170: 		xmlBufferWriteChar(buf, ":");
 1171: 	    }
 1172: 	    xmlBufferWriteCHAR(buf, content->name);
 1173: 	    break;
 1174: 	case XML_ELEMENT_CONTENT_SEQ:
 1175: 	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
 1176: 	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
 1177: 		xmlDumpElementContent(buf, content->c1, 1);
 1178: 	    else
 1179: 		xmlDumpElementContent(buf, content->c1, 0);
 1180:             xmlBufferWriteChar(buf, " , ");
 1181: 	    if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
 1182: 	        ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
 1183: 		 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
 1184: 		xmlDumpElementContent(buf, content->c2, 1);
 1185: 	    else
 1186: 		xmlDumpElementContent(buf, content->c2, 0);
 1187: 	    break;
 1188: 	case XML_ELEMENT_CONTENT_OR:
 1189: 	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
 1190: 	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
 1191: 		xmlDumpElementContent(buf, content->c1, 1);
 1192: 	    else
 1193: 		xmlDumpElementContent(buf, content->c1, 0);
 1194:             xmlBufferWriteChar(buf, " | ");
 1195: 	    if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
 1196: 	        ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
 1197: 		 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
 1198: 		xmlDumpElementContent(buf, content->c2, 1);
 1199: 	    else
 1200: 		xmlDumpElementContent(buf, content->c2, 0);
 1201: 	    break;
 1202: 	default:
 1203: 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
 1204: 		    "Internal: ELEMENT content corrupted invalid type\n",
 1205: 		    NULL);
 1206:     }
 1207:     if (glob)
 1208:         xmlBufferWriteChar(buf, ")");
 1209:     switch (content->ocur) {
 1210:         case XML_ELEMENT_CONTENT_ONCE:
 1211: 	    break;
 1212:         case XML_ELEMENT_CONTENT_OPT:
 1213: 	    xmlBufferWriteChar(buf, "?");
 1214: 	    break;
 1215:         case XML_ELEMENT_CONTENT_MULT:
 1216: 	    xmlBufferWriteChar(buf, "*");
 1217: 	    break;
 1218:         case XML_ELEMENT_CONTENT_PLUS:
 1219: 	    xmlBufferWriteChar(buf, "+");
 1220: 	    break;
 1221:     }
 1222: }
 1223: 
 1224: /**
 1225:  * xmlSprintfElementContent:
 1226:  * @buf:  an output buffer
 1227:  * @content:  An element table
 1228:  * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
 1229:  *
 1230:  * Deprecated, unsafe, use xmlSnprintfElementContent
 1231:  */
 1232: void
 1233: xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
 1234: 	                 xmlElementContentPtr content ATTRIBUTE_UNUSED,
 1235: 			 int englob ATTRIBUTE_UNUSED) {
 1236: }
 1237: #endif /* LIBXML_OUTPUT_ENABLED */
 1238: 
 1239: /**
 1240:  * xmlSnprintfElementContent:
 1241:  * @buf:  an output buffer
 1242:  * @size:  the buffer size
 1243:  * @content:  An element table
 1244:  * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
 1245:  *
 1246:  * This will dump the content of the element content definition
 1247:  * Intended just for the debug routine
 1248:  */
 1249: void
 1250: xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
 1251:     int len;
 1252: 
 1253:     if (content == NULL) return;
 1254:     len = strlen(buf);
 1255:     if (size - len < 50) {
 1256: 	if ((size - len > 4) && (buf[len - 1] != '.'))
 1257: 	    strcat(buf, " ...");
 1258: 	return;
 1259:     }
 1260:     if (englob) strcat(buf, "(");
 1261:     switch (content->type) {
 1262:         case XML_ELEMENT_CONTENT_PCDATA:
 1263:             strcat(buf, "#PCDATA");
 1264: 	    break;
 1265: 	case XML_ELEMENT_CONTENT_ELEMENT:
 1266: 	    if (content->prefix != NULL) {
 1267: 		if (size - len < xmlStrlen(content->prefix) + 10) {
 1268: 		    strcat(buf, " ...");
 1269: 		    return;
 1270: 		}
 1271: 		strcat(buf, (char *) content->prefix);
 1272: 		strcat(buf, ":");
 1273: 	    }
 1274: 	    if (size - len < xmlStrlen(content->name) + 10) {
 1275: 		strcat(buf, " ...");
 1276: 		return;
 1277: 	    }
 1278: 	    if (content->name != NULL)
 1279: 		strcat(buf, (char *) content->name);
 1280: 	    break;
 1281: 	case XML_ELEMENT_CONTENT_SEQ:
 1282: 	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
 1283: 	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
 1284: 		xmlSnprintfElementContent(buf, size, content->c1, 1);
 1285: 	    else
 1286: 		xmlSnprintfElementContent(buf, size, content->c1, 0);
 1287: 	    len = strlen(buf);
 1288: 	    if (size - len < 50) {
 1289: 		if ((size - len > 4) && (buf[len - 1] != '.'))
 1290: 		    strcat(buf, " ...");
 1291: 		return;
 1292: 	    }
 1293:             strcat(buf, " , ");
 1294: 	    if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
 1295: 		 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
 1296: 		(content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
 1297: 		xmlSnprintfElementContent(buf, size, content->c2, 1);
 1298: 	    else
 1299: 		xmlSnprintfElementContent(buf, size, content->c2, 0);
 1300: 	    break;
 1301: 	case XML_ELEMENT_CONTENT_OR:
 1302: 	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
 1303: 	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
 1304: 		xmlSnprintfElementContent(buf, size, content->c1, 1);
 1305: 	    else
 1306: 		xmlSnprintfElementContent(buf, size, content->c1, 0);
 1307: 	    len = strlen(buf);
 1308: 	    if (size - len < 50) {
 1309: 		if ((size - len > 4) && (buf[len - 1] != '.'))
 1310: 		    strcat(buf, " ...");
 1311: 		return;
 1312: 	    }
 1313:             strcat(buf, " | ");
 1314: 	    if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
 1315: 		 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
 1316: 		(content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
 1317: 		xmlSnprintfElementContent(buf, size, content->c2, 1);
 1318: 	    else
 1319: 		xmlSnprintfElementContent(buf, size, content->c2, 0);
 1320: 	    break;
 1321:     }
 1322:     if (englob)
 1323:         strcat(buf, ")");
 1324:     switch (content->ocur) {
 1325:         case XML_ELEMENT_CONTENT_ONCE:
 1326: 	    break;
 1327:         case XML_ELEMENT_CONTENT_OPT:
 1328: 	    strcat(buf, "?");
 1329: 	    break;
 1330:         case XML_ELEMENT_CONTENT_MULT:
 1331: 	    strcat(buf, "*");
 1332: 	    break;
 1333:         case XML_ELEMENT_CONTENT_PLUS:
 1334: 	    strcat(buf, "+");
 1335: 	    break;
 1336:     }
 1337: }
 1338: 
 1339: /****************************************************************
 1340:  *								*
 1341:  *	Registration of DTD declarations			*
 1342:  *								*
 1343:  ****************************************************************/
 1344: 
 1345: /**
 1346:  * xmlFreeElement:
 1347:  * @elem:  An element
 1348:  *
 1349:  * Deallocate the memory used by an element definition
 1350:  */
 1351: static void
 1352: xmlFreeElement(xmlElementPtr elem) {
 1353:     if (elem == NULL) return;
 1354:     xmlUnlinkNode((xmlNodePtr) elem);
 1355:     xmlFreeDocElementContent(elem->doc, elem->content);
 1356:     if (elem->name != NULL)
 1357: 	xmlFree((xmlChar *) elem->name);
 1358:     if (elem->prefix != NULL)
 1359: 	xmlFree((xmlChar *) elem->prefix);
 1360: #ifdef LIBXML_REGEXP_ENABLED
 1361:     if (elem->contModel != NULL)
 1362: 	xmlRegFreeRegexp(elem->contModel);
 1363: #endif
 1364:     xmlFree(elem);
 1365: }
 1366: 
 1367: 
 1368: /**
 1369:  * xmlAddElementDecl:
 1370:  * @ctxt:  the validation context
 1371:  * @dtd:  pointer to the DTD
 1372:  * @name:  the entity name
 1373:  * @type:  the element type
 1374:  * @content:  the element content tree or NULL
 1375:  *
 1376:  * Register a new element declaration
 1377:  *
 1378:  * Returns NULL if not, otherwise the entity
 1379:  */
 1380: xmlElementPtr
 1381: xmlAddElementDecl(xmlValidCtxtPtr ctxt,
 1382:                   xmlDtdPtr dtd, const xmlChar *name,
 1383:                   xmlElementTypeVal type,
 1384: 		  xmlElementContentPtr content) {
 1385:     xmlElementPtr ret;
 1386:     xmlElementTablePtr table;
 1387:     xmlAttributePtr oldAttributes = NULL;
 1388:     xmlChar *ns, *uqname;
 1389: 
 1390:     if (dtd == NULL) {
 1391: 	return(NULL);
 1392:     }
 1393:     if (name == NULL) {
 1394: 	return(NULL);
 1395:     }
 1396: 
 1397:     switch (type) {
 1398:         case XML_ELEMENT_TYPE_EMPTY:
 1399: 	    if (content != NULL) {
 1400: 		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
 1401: 		        "xmlAddElementDecl: content != NULL for EMPTY\n",
 1402: 			NULL);
 1403: 		return(NULL);
 1404: 	    }
 1405: 	    break;
 1406: 	case XML_ELEMENT_TYPE_ANY:
 1407: 	    if (content != NULL) {
 1408: 		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
 1409: 		        "xmlAddElementDecl: content != NULL for ANY\n",
 1410: 			NULL);
 1411: 		return(NULL);
 1412: 	    }
 1413: 	    break;
 1414: 	case XML_ELEMENT_TYPE_MIXED:
 1415: 	    if (content == NULL) {
 1416: 		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
 1417: 		        "xmlAddElementDecl: content == NULL for MIXED\n",
 1418: 			NULL);
 1419: 		return(NULL);
 1420: 	    }
 1421: 	    break;
 1422: 	case XML_ELEMENT_TYPE_ELEMENT:
 1423: 	    if (content == NULL) {
 1424: 		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
 1425: 		        "xmlAddElementDecl: content == NULL for ELEMENT\n",
 1426: 			NULL);
 1427: 		return(NULL);
 1428: 	    }
 1429: 	    break;
 1430: 	default:
 1431: 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
 1432: 		    "Internal: ELEMENT decl corrupted invalid type\n",
 1433: 		    NULL);
 1434: 	    return(NULL);
 1435:     }
 1436: 
 1437:     /*
 1438:      * check if name is a QName
 1439:      */
 1440:     uqname = xmlSplitQName2(name, &ns);
 1441:     if (uqname != NULL)
 1442: 	name = uqname;
 1443: 
 1444:     /*
 1445:      * Create the Element table if needed.
 1446:      */
 1447:     table = (xmlElementTablePtr) dtd->elements;
 1448:     if (table == NULL) {
 1449: 	xmlDictPtr dict = NULL;
 1450: 
 1451: 	if (dtd->doc != NULL)
 1452: 	    dict = dtd->doc->dict;
 1453:         table = xmlHashCreateDict(0, dict);
 1454: 	dtd->elements = (void *) table;
 1455:     }
 1456:     if (table == NULL) {
 1457: 	xmlVErrMemory(ctxt,
 1458:             "xmlAddElementDecl: Table creation failed!\n");
 1459: 	if (uqname != NULL)
 1460: 	    xmlFree(uqname);
 1461: 	if (ns != NULL)
 1462: 	    xmlFree(ns);
 1463:         return(NULL);
 1464:     }
 1465: 
 1466:     /*
 1467:      * lookup old attributes inserted on an undefined element in the
 1468:      * internal subset.
 1469:      */
 1470:     if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
 1471: 	ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
 1472: 	if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
 1473: 	    oldAttributes = ret->attributes;
 1474: 	    ret->attributes = NULL;
 1475: 	    xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
 1476: 	    xmlFreeElement(ret);
 1477: 	}
 1478:     }
 1479: 
 1480:     /*
 1481:      * The element may already be present if one of its attribute
 1482:      * was registered first
 1483:      */
 1484:     ret = xmlHashLookup2(table, name, ns);
 1485:     if (ret != NULL) {
 1486: 	if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
 1487: #ifdef LIBXML_VALID_ENABLED
 1488: 	    /*
 1489: 	     * The element is already defined in this DTD.
 1490: 	     */
 1491: 	    xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
 1492: 	                    "Redefinition of element %s\n",
 1493: 			    name, NULL, NULL);
 1494: #endif /* LIBXML_VALID_ENABLED */
 1495: 	    if (uqname != NULL)
 1496: 		xmlFree(uqname);
 1497:             if (ns != NULL)
 1498: 	        xmlFree(ns);
 1499: 	    return(NULL);
 1500: 	}
 1501: 	if (ns != NULL) {
 1502: 	    xmlFree(ns);
 1503: 	    ns = NULL;
 1504: 	}
 1505:     } else {
 1506: 	ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
 1507: 	if (ret == NULL) {
 1508: 	    xmlVErrMemory(ctxt, "malloc failed");
 1509: 	    if (uqname != NULL)
 1510: 		xmlFree(uqname);
 1511:             if (ns != NULL)
 1512: 	        xmlFree(ns);
 1513: 	    return(NULL);
 1514: 	}
 1515: 	memset(ret, 0, sizeof(xmlElement));
 1516: 	ret->type = XML_ELEMENT_DECL;
 1517: 
 1518: 	/*
 1519: 	 * fill the structure.
 1520: 	 */
 1521: 	ret->name = xmlStrdup(name);
 1522: 	if (ret->name == NULL) {
 1523: 	    xmlVErrMemory(ctxt, "malloc failed");
 1524: 	    if (uqname != NULL)
 1525: 		xmlFree(uqname);
 1526:             if (ns != NULL)
 1527: 	        xmlFree(ns);
 1528: 	    xmlFree(ret);
 1529: 	    return(NULL);
 1530: 	}
 1531: 	ret->prefix = ns;
 1532: 
 1533: 	/*
 1534: 	 * Validity Check:
 1535: 	 * Insertion must not fail
 1536: 	 */
 1537: 	if (xmlHashAddEntry2(table, name, ns, ret)) {
 1538: #ifdef LIBXML_VALID_ENABLED
 1539: 	    /*
 1540: 	     * The element is already defined in this DTD.
 1541: 	     */
 1542: 	    xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
 1543: 	                    "Redefinition of element %s\n",
 1544: 			    name, NULL, NULL);
 1545: #endif /* LIBXML_VALID_ENABLED */
 1546: 	    xmlFreeElement(ret);
 1547: 	    if (uqname != NULL)
 1548: 		xmlFree(uqname);
 1549: 	    return(NULL);
 1550: 	}
 1551: 	/*
 1552: 	 * For new element, may have attributes from earlier
 1553: 	 * definition in internal subset
 1554: 	 */
 1555: 	ret->attributes = oldAttributes;
 1556:     }
 1557: 
 1558:     /*
 1559:      * Finish to fill the structure.
 1560:      */
 1561:     ret->etype = type;
 1562:     /*
 1563:      * Avoid a stupid copy when called by the parser
 1564:      * and flag it by setting a special parent value
 1565:      * so the parser doesn't unallocate it.
 1566:      */
 1567:     if ((ctxt != NULL) &&
 1568:         ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
 1569:          (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
 1570: 	ret->content = content;
 1571: 	if (content != NULL)
 1572: 	    content->parent = (xmlElementContentPtr) 1;
 1573:     } else {
 1574: 	ret->content = xmlCopyDocElementContent(dtd->doc, content);
 1575:     }
 1576: 
 1577:     /*
 1578:      * Link it to the DTD
 1579:      */
 1580:     ret->parent = dtd;
 1581:     ret->doc = dtd->doc;
 1582:     if (dtd->last == NULL) {
 1583: 	dtd->children = dtd->last = (xmlNodePtr) ret;
 1584:     } else {
 1585:         dtd->last->next = (xmlNodePtr) ret;
 1586: 	ret->prev = dtd->last;
 1587: 	dtd->last = (xmlNodePtr) ret;
 1588:     }
 1589:     if (uqname != NULL)
 1590: 	xmlFree(uqname);
 1591:     return(ret);
 1592: }
 1593: 
 1594: /**
 1595:  * xmlFreeElementTable:
 1596:  * @table:  An element table
 1597:  *
 1598:  * Deallocate the memory used by an element hash table.
 1599:  */
 1600: void
 1601: xmlFreeElementTable(xmlElementTablePtr table) {
 1602:     xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
 1603: }
 1604: 
 1605: #ifdef LIBXML_TREE_ENABLED
 1606: /**
 1607:  * xmlCopyElement:
 1608:  * @elem:  An element
 1609:  *
 1610:  * Build a copy of an element.
 1611:  *
 1612:  * Returns the new xmlElementPtr or NULL in case of error.
 1613:  */
 1614: static xmlElementPtr
 1615: xmlCopyElement(xmlElementPtr elem) {
 1616:     xmlElementPtr cur;
 1617: 
 1618:     cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
 1619:     if (cur == NULL) {
 1620: 	xmlVErrMemory(NULL, "malloc failed");
 1621: 	return(NULL);
 1622:     }
 1623:     memset(cur, 0, sizeof(xmlElement));
 1624:     cur->type = XML_ELEMENT_DECL;
 1625:     cur->etype = elem->etype;
 1626:     if (elem->name != NULL)
 1627: 	cur->name = xmlStrdup(elem->name);
 1628:     else
 1629: 	cur->name = NULL;
 1630:     if (elem->prefix != NULL)
 1631: 	cur->prefix = xmlStrdup(elem->prefix);
 1632:     else
 1633: 	cur->prefix = NULL;
 1634:     cur->content = xmlCopyElementContent(elem->content);
 1635:     /* TODO : rebuild the attribute list on the copy */
 1636:     cur->attributes = NULL;
 1637:     return(cur);
 1638: }
 1639: 
 1640: /**
 1641:  * xmlCopyElementTable:
 1642:  * @table:  An element table
 1643:  *
 1644:  * Build a copy of an element table.
 1645:  *
 1646:  * Returns the new xmlElementTablePtr or NULL in case of error.
 1647:  */
 1648: xmlElementTablePtr
 1649: xmlCopyElementTable(xmlElementTablePtr table) {
 1650:     return((xmlElementTablePtr) xmlHashCopy(table,
 1651: 		                            (xmlHashCopier) xmlCopyElement));
 1652: }
 1653: #endif /* LIBXML_TREE_ENABLED */
 1654: 
 1655: #ifdef LIBXML_OUTPUT_ENABLED
 1656: /**
 1657:  * xmlDumpElementDecl:
 1658:  * @buf:  the XML buffer output
 1659:  * @elem:  An element table
 1660:  *
 1661:  * This will dump the content of the element declaration as an XML
 1662:  * DTD definition
 1663:  */
 1664: void
 1665: xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
 1666:     if ((buf == NULL) || (elem == NULL))
 1667:         return;
 1668:     switch (elem->etype) {
 1669: 	case XML_ELEMENT_TYPE_EMPTY:
 1670: 	    xmlBufferWriteChar(buf, "<!ELEMENT ");
 1671: 	    if (elem->prefix != NULL) {
 1672: 		xmlBufferWriteCHAR(buf, elem->prefix);
 1673: 		xmlBufferWriteChar(buf, ":");
 1674: 	    }
 1675: 	    xmlBufferWriteCHAR(buf, elem->name);
 1676: 	    xmlBufferWriteChar(buf, " EMPTY>\n");
 1677: 	    break;
 1678: 	case XML_ELEMENT_TYPE_ANY:
 1679: 	    xmlBufferWriteChar(buf, "<!ELEMENT ");
 1680: 	    if (elem->prefix != NULL) {
 1681: 		xmlBufferWriteCHAR(buf, elem->prefix);
 1682: 		xmlBufferWriteChar(buf, ":");
 1683: 	    }
 1684: 	    xmlBufferWriteCHAR(buf, elem->name);
 1685: 	    xmlBufferWriteChar(buf, " ANY>\n");
 1686: 	    break;
 1687: 	case XML_ELEMENT_TYPE_MIXED:
 1688: 	    xmlBufferWriteChar(buf, "<!ELEMENT ");
 1689: 	    if (elem->prefix != NULL) {
 1690: 		xmlBufferWriteCHAR(buf, elem->prefix);
 1691: 		xmlBufferWriteChar(buf, ":");
 1692: 	    }
 1693: 	    xmlBufferWriteCHAR(buf, elem->name);
 1694: 	    xmlBufferWriteChar(buf, " ");
 1695: 	    xmlDumpElementContent(buf, elem->content, 1);
 1696: 	    xmlBufferWriteChar(buf, ">\n");
 1697: 	    break;
 1698: 	case XML_ELEMENT_TYPE_ELEMENT:
 1699: 	    xmlBufferWriteChar(buf, "<!ELEMENT ");
 1700: 	    if (elem->prefix != NULL) {
 1701: 		xmlBufferWriteCHAR(buf, elem->prefix);
 1702: 		xmlBufferWriteChar(buf, ":");
 1703: 	    }
 1704: 	    xmlBufferWriteCHAR(buf, elem->name);
 1705: 	    xmlBufferWriteChar(buf, " ");
 1706: 	    xmlDumpElementContent(buf, elem->content, 1);
 1707: 	    xmlBufferWriteChar(buf, ">\n");
 1708: 	    break;
 1709: 	default:
 1710: 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
 1711: 		    "Internal: ELEMENT struct corrupted invalid type\n",
 1712: 		    NULL);
 1713:     }
 1714: }
 1715: 
 1716: /**
 1717:  * xmlDumpElementDeclScan:
 1718:  * @elem:  An element table
 1719:  * @buf:  the XML buffer output
 1720:  *
 1721:  * This routine is used by the hash scan function.  It just reverses
 1722:  * the arguments.
 1723:  */
 1724: static void
 1725: xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
 1726:     xmlDumpElementDecl(buf, elem);
 1727: }
 1728: 
 1729: /**
 1730:  * xmlDumpElementTable:
 1731:  * @buf:  the XML buffer output
 1732:  * @table:  An element table
 1733:  *
 1734:  * This will dump the content of the element table as an XML DTD definition
 1735:  */
 1736: void
 1737: xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
 1738:     if ((buf == NULL) || (table == NULL))
 1739:         return;
 1740:     xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
 1741: }
 1742: #endif /* LIBXML_OUTPUT_ENABLED */
 1743: 
 1744: /**
 1745:  * xmlCreateEnumeration:
 1746:  * @name:  the enumeration name or NULL
 1747:  *
 1748:  * create and initialize an enumeration attribute node.
 1749:  *
 1750:  * Returns the xmlEnumerationPtr just created or NULL in case
 1751:  *                of error.
 1752:  */
 1753: xmlEnumerationPtr
 1754: xmlCreateEnumeration(const xmlChar *name) {
 1755:     xmlEnumerationPtr ret;
 1756: 
 1757:     ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
 1758:     if (ret == NULL) {
 1759: 	xmlVErrMemory(NULL, "malloc failed");
 1760:         return(NULL);
 1761:     }
 1762:     memset(ret, 0, sizeof(xmlEnumeration));
 1763: 
 1764:     if (name != NULL)
 1765:         ret->name = xmlStrdup(name);
 1766:     return(ret);
 1767: }
 1768: 
 1769: /**
 1770:  * xmlFreeEnumeration:
 1771:  * @cur:  the tree to free.
 1772:  *
 1773:  * free an enumeration attribute node (recursive).
 1774:  */
 1775: void
 1776: xmlFreeEnumeration(xmlEnumerationPtr cur) {
 1777:     if (cur == NULL) return;
 1778: 
 1779:     if (cur->next != NULL) xmlFreeEnumeration(cur->next);
 1780: 
 1781:     if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
 1782:     xmlFree(cur);
 1783: }
 1784: 
 1785: #ifdef LIBXML_TREE_ENABLED
 1786: /**
 1787:  * xmlCopyEnumeration:
 1788:  * @cur:  the tree to copy.
 1789:  *
 1790:  * Copy an enumeration attribute node (recursive).
 1791:  *
 1792:  * Returns the xmlEnumerationPtr just created or NULL in case
 1793:  *                of error.
 1794:  */
 1795: xmlEnumerationPtr
 1796: xmlCopyEnumeration(xmlEnumerationPtr cur) {
 1797:     xmlEnumerationPtr ret;
 1798: 
 1799:     if (cur == NULL) return(NULL);
 1800:     ret = xmlCreateEnumeration((xmlChar *) cur->name);
 1801: 
 1802:     if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
 1803:     else ret->next = NULL;
 1804: 
 1805:     return(ret);
 1806: }
 1807: #endif /* LIBXML_TREE_ENABLED */
 1808: 
 1809: #ifdef LIBXML_OUTPUT_ENABLED
 1810: /**
 1811:  * xmlDumpEnumeration:
 1812:  * @buf:  the XML buffer output
 1813:  * @enum:  An enumeration
 1814:  *
 1815:  * This will dump the content of the enumeration
 1816:  */
 1817: static void
 1818: xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
 1819:     if ((buf == NULL) || (cur == NULL))
 1820:         return;
 1821: 
 1822:     xmlBufferWriteCHAR(buf, cur->name);
 1823:     if (cur->next == NULL)
 1824: 	xmlBufferWriteChar(buf, ")");
 1825:     else {
 1826: 	xmlBufferWriteChar(buf, " | ");
 1827: 	xmlDumpEnumeration(buf, cur->next);
 1828:     }
 1829: }
 1830: #endif /* LIBXML_OUTPUT_ENABLED */
 1831: 
 1832: #ifdef LIBXML_VALID_ENABLED
 1833: /**
 1834:  * xmlScanIDAttributeDecl:
 1835:  * @ctxt:  the validation context
 1836:  * @elem:  the element name
 1837:  * @err: whether to raise errors here
 1838:  *
 1839:  * Verify that the element don't have too many ID attributes
 1840:  * declared.
 1841:  *
 1842:  * Returns the number of ID attributes found.
 1843:  */
 1844: static int
 1845: xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
 1846:     xmlAttributePtr cur;
 1847:     int ret = 0;
 1848: 
 1849:     if (elem == NULL) return(0);
 1850:     cur = elem->attributes;
 1851:     while (cur != NULL) {
 1852:         if (cur->atype == XML_ATTRIBUTE_ID) {
 1853: 	    ret ++;
 1854: 	    if ((ret > 1) && (err))
 1855: 		xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
 1856: 	       "Element %s has too many ID attributes defined : %s\n",
 1857: 		       elem->name, cur->name, NULL);
 1858: 	}
 1859: 	cur = cur->nexth;
 1860:     }
 1861:     return(ret);
 1862: }
 1863: #endif /* LIBXML_VALID_ENABLED */
 1864: 
 1865: /**
 1866:  * xmlFreeAttribute:
 1867:  * @elem:  An attribute
 1868:  *
 1869:  * Deallocate the memory used by an attribute definition
 1870:  */
 1871: static void
 1872: xmlFreeAttribute(xmlAttributePtr attr) {
 1873:     xmlDictPtr dict;
 1874: 
 1875:     if (attr == NULL) return;
 1876:     if (attr->doc != NULL)
 1877: 	dict = attr->doc->dict;
 1878:     else
 1879: 	dict = NULL;
 1880:     xmlUnlinkNode((xmlNodePtr) attr);
 1881:     if (attr->tree != NULL)
 1882:         xmlFreeEnumeration(attr->tree);
 1883:     if (dict) {
 1884:         if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
 1885: 	    xmlFree((xmlChar *) attr->elem);
 1886:         if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
 1887: 	    xmlFree((xmlChar *) attr->name);
 1888:         if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
 1889: 	    xmlFree((xmlChar *) attr->prefix);
 1890:         if ((attr->defaultValue != NULL) &&
 1891: 	    (!xmlDictOwns(dict, attr->defaultValue)))
 1892: 	    xmlFree((xmlChar *) attr->defaultValue);
 1893:     } else {
 1894: 	if (attr->elem != NULL)
 1895: 	    xmlFree((xmlChar *) attr->elem);
 1896: 	if (attr->name != NULL)
 1897: 	    xmlFree((xmlChar *) attr->name);
 1898: 	if (attr->defaultValue != NULL)
 1899: 	    xmlFree((xmlChar *) attr->defaultValue);
 1900: 	if (attr->prefix != NULL)
 1901: 	    xmlFree((xmlChar *) attr->prefix);
 1902:     }
 1903:     xmlFree(attr);
 1904: }
 1905: 
 1906: 
 1907: /**
 1908:  * xmlAddAttributeDecl:
 1909:  * @ctxt:  the validation context
 1910:  * @dtd:  pointer to the DTD
 1911:  * @elem:  the element name
 1912:  * @name:  the attribute name
 1913:  * @ns:  the attribute namespace prefix
 1914:  * @type:  the attribute type
 1915:  * @def:  the attribute default type
 1916:  * @defaultValue:  the attribute default value
 1917:  * @tree:  if it's an enumeration, the associated list
 1918:  *
 1919:  * Register a new attribute declaration
 1920:  * Note that @tree becomes the ownership of the DTD
 1921:  *
 1922:  * Returns NULL if not new, otherwise the attribute decl
 1923:  */
 1924: xmlAttributePtr
 1925: xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
 1926:                     xmlDtdPtr dtd, const xmlChar *elem,
 1927:                     const xmlChar *name, const xmlChar *ns,
 1928: 		    xmlAttributeType type, xmlAttributeDefault def,
 1929: 		    const xmlChar *defaultValue, xmlEnumerationPtr tree) {
 1930:     xmlAttributePtr ret;
 1931:     xmlAttributeTablePtr table;
 1932:     xmlElementPtr elemDef;
 1933:     xmlDictPtr dict = NULL;
 1934: 
 1935:     if (dtd == NULL) {
 1936: 	xmlFreeEnumeration(tree);
 1937: 	return(NULL);
 1938:     }
 1939:     if (name == NULL) {
 1940: 	xmlFreeEnumeration(tree);
 1941: 	return(NULL);
 1942:     }
 1943:     if (elem == NULL) {
 1944: 	xmlFreeEnumeration(tree);
 1945: 	return(NULL);
 1946:     }
 1947:     if (dtd->doc != NULL)
 1948: 	dict = dtd->doc->dict;
 1949: 
 1950: #ifdef LIBXML_VALID_ENABLED
 1951:     /*
 1952:      * Check the type and possibly the default value.
 1953:      */
 1954:     switch (type) {
 1955:         case XML_ATTRIBUTE_CDATA:
 1956: 	    break;
 1957:         case XML_ATTRIBUTE_ID:
 1958: 	    break;
 1959:         case XML_ATTRIBUTE_IDREF:
 1960: 	    break;
 1961:         case XML_ATTRIBUTE_IDREFS:
 1962: 	    break;
 1963:         case XML_ATTRIBUTE_ENTITY:
 1964: 	    break;
 1965:         case XML_ATTRIBUTE_ENTITIES:
 1966: 	    break;
 1967:         case XML_ATTRIBUTE_NMTOKEN:
 1968: 	    break;
 1969:         case XML_ATTRIBUTE_NMTOKENS:
 1970: 	    break;
 1971:         case XML_ATTRIBUTE_ENUMERATION:
 1972: 	    break;
 1973:         case XML_ATTRIBUTE_NOTATION:
 1974: 	    break;
 1975: 	default:
 1976: 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
 1977: 		    "Internal: ATTRIBUTE struct corrupted invalid type\n",
 1978: 		    NULL);
 1979: 	    xmlFreeEnumeration(tree);
 1980: 	    return(NULL);
 1981:     }
 1982:     if ((defaultValue != NULL) &&
 1983:         (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
 1984: 	xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
 1985: 	                "Attribute %s of %s: invalid default value\n",
 1986: 	                elem, name, defaultValue);
 1987: 	defaultValue = NULL;
 1988: 	if (ctxt != NULL)
 1989: 	    ctxt->valid = 0;
 1990:     }
 1991: #endif /* LIBXML_VALID_ENABLED */
 1992: 
 1993:     /*
 1994:      * Check first that an attribute defined in the external subset wasn't
 1995:      * already defined in the internal subset
 1996:      */
 1997:     if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
 1998: 	(dtd->doc->intSubset != NULL) &&
 1999: 	(dtd->doc->intSubset->attributes != NULL)) {
 2000:         ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
 2001: 	if (ret != NULL) {
 2002: 	    xmlFreeEnumeration(tree);
 2003: 	    return(NULL);
 2004: 	}
 2005:     }
 2006: 
 2007:     /*
 2008:      * Create the Attribute table if needed.
 2009:      */
 2010:     table = (xmlAttributeTablePtr) dtd->attributes;
 2011:     if (table == NULL) {
 2012:         table = xmlHashCreateDict(0, dict);
 2013: 	dtd->attributes = (void *) table;
 2014:     }
 2015:     if (table == NULL) {
 2016: 	xmlVErrMemory(ctxt,
 2017:             "xmlAddAttributeDecl: Table creation failed!\n");
 2018: 	xmlFreeEnumeration(tree);
 2019:         return(NULL);
 2020:     }
 2021: 
 2022: 
 2023:     ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
 2024:     if (ret == NULL) {
 2025: 	xmlVErrMemory(ctxt, "malloc failed");
 2026: 	xmlFreeEnumeration(tree);
 2027: 	return(NULL);
 2028:     }
 2029:     memset(ret, 0, sizeof(xmlAttribute));
 2030:     ret->type = XML_ATTRIBUTE_DECL;
 2031: 
 2032:     /*
 2033:      * fill the structure.
 2034:      */
 2035:     ret->atype = type;
 2036:     /*
 2037:      * doc must be set before possible error causes call
 2038:      * to xmlFreeAttribute (because it's used to check on
 2039:      * dict use)
 2040:      */
 2041:     ret->doc = dtd->doc;
 2042:     if (dict) {
 2043: 	ret->name = xmlDictLookup(dict, name, -1);
 2044: 	ret->prefix = xmlDictLookup(dict, ns, -1);
 2045: 	ret->elem = xmlDictLookup(dict, elem, -1);
 2046:     } else {
 2047: 	ret->name = xmlStrdup(name);
 2048: 	ret->prefix = xmlStrdup(ns);
 2049: 	ret->elem = xmlStrdup(elem);
 2050:     }
 2051:     ret->def = def;
 2052:     ret->tree = tree;
 2053:     if (defaultValue != NULL) {
 2054:         if (dict)
 2055: 	    ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
 2056: 	else
 2057: 	    ret->defaultValue = xmlStrdup(defaultValue);
 2058:     }
 2059: 
 2060:     /*
 2061:      * Validity Check:
 2062:      * Search the DTD for previous declarations of the ATTLIST
 2063:      */
 2064:     if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
 2065: #ifdef LIBXML_VALID_ENABLED
 2066: 	/*
 2067: 	 * The attribute is already defined in this DTD.
 2068: 	 */
 2069: 	xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
 2070: 		 "Attribute %s of element %s: already defined\n",
 2071: 		 name, elem, NULL);
 2072: #endif /* LIBXML_VALID_ENABLED */
 2073: 	xmlFreeAttribute(ret);
 2074: 	return(NULL);
 2075:     }
 2076: 
 2077:     /*
 2078:      * Validity Check:
 2079:      * Multiple ID per element
 2080:      */
 2081:     elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
 2082:     if (elemDef != NULL) {
 2083: 
 2084: #ifdef LIBXML_VALID_ENABLED
 2085:         if ((type == XML_ATTRIBUTE_ID) &&
 2086: 	    (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
 2087: 	    xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
 2088: 	   "Element %s has too may ID attributes defined : %s\n",
 2089: 		   elem, name, NULL);
 2090: 	    if (ctxt != NULL)
 2091: 		ctxt->valid = 0;
 2092: 	}
 2093: #endif /* LIBXML_VALID_ENABLED */
 2094: 
 2095: 	/*
 2096: 	 * Insert namespace default def first they need to be
 2097: 	 * processed first.
 2098: 	 */
 2099: 	if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
 2100: 	    ((ret->prefix != NULL &&
 2101: 	     (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
 2102: 	    ret->nexth = elemDef->attributes;
 2103: 	    elemDef->attributes = ret;
 2104: 	} else {
 2105: 	    xmlAttributePtr tmp = elemDef->attributes;
 2106: 
 2107: 	    while ((tmp != NULL) &&
 2108: 		   ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
 2109: 		    ((ret->prefix != NULL &&
 2110: 		     (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
 2111: 		if (tmp->nexth == NULL)
 2112: 		    break;
 2113: 		tmp = tmp->nexth;
 2114: 	    }
 2115: 	    if (tmp != NULL) {
 2116: 		ret->nexth = tmp->nexth;
 2117: 	        tmp->nexth = ret;
 2118: 	    } else {
 2119: 		ret->nexth = elemDef->attributes;
 2120: 		elemDef->attributes = ret;
 2121: 	    }
 2122: 	}
 2123:     }
 2124: 
 2125:     /*
 2126:      * Link it to the DTD
 2127:      */
 2128:     ret->parent = dtd;
 2129:     if (dtd->last == NULL) {
 2130: 	dtd->children = dtd->last = (xmlNodePtr) ret;
 2131:     } else {
 2132:         dtd->last->next = (xmlNodePtr) ret;
 2133: 	ret->prev = dtd->last;
 2134: 	dtd->last = (xmlNodePtr) ret;
 2135:     }
 2136:     return(ret);
 2137: }
 2138: 
 2139: /**
 2140:  * xmlFreeAttributeTable:
 2141:  * @table:  An attribute table
 2142:  *
 2143:  * Deallocate the memory used by an entities hash table.
 2144:  */
 2145: void
 2146: xmlFreeAttributeTable(xmlAttributeTablePtr table) {
 2147:     xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
 2148: }
 2149: 
 2150: #ifdef LIBXML_TREE_ENABLED
 2151: /**
 2152:  * xmlCopyAttribute:
 2153:  * @attr:  An attribute
 2154:  *
 2155:  * Build a copy of an attribute.
 2156:  *
 2157:  * Returns the new xmlAttributePtr or NULL in case of error.
 2158:  */
 2159: static xmlAttributePtr
 2160: xmlCopyAttribute(xmlAttributePtr attr) {
 2161:     xmlAttributePtr cur;
 2162: 
 2163:     cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
 2164:     if (cur == NULL) {
 2165: 	xmlVErrMemory(NULL, "malloc failed");
 2166: 	return(NULL);
 2167:     }
 2168:     memset(cur, 0, sizeof(xmlAttribute));
 2169:     cur->type = XML_ATTRIBUTE_DECL;
 2170:     cur->atype = attr->atype;
 2171:     cur->def = attr->def;
 2172:     cur->tree = xmlCopyEnumeration(attr->tree);
 2173:     if (attr->elem != NULL)
 2174: 	cur->elem = xmlStrdup(attr->elem);
 2175:     if (attr->name != NULL)
 2176: 	cur->name = xmlStrdup(attr->name);
 2177:     if (attr->prefix != NULL)
 2178: 	cur->prefix = xmlStrdup(attr->prefix);
 2179:     if (attr->defaultValue != NULL)
 2180: 	cur->defaultValue = xmlStrdup(attr->defaultValue);
 2181:     return(cur);
 2182: }
 2183: 
 2184: /**
 2185:  * xmlCopyAttributeTable:
 2186:  * @table:  An attribute table
 2187:  *
 2188:  * Build a copy of an attribute table.
 2189:  *
 2190:  * Returns the new xmlAttributeTablePtr or NULL in case of error.
 2191:  */
 2192: xmlAttributeTablePtr
 2193: xmlCopyAttributeTable(xmlAttributeTablePtr table) {
 2194:     return((xmlAttributeTablePtr) xmlHashCopy(table,
 2195: 				    (xmlHashCopier) xmlCopyAttribute));
 2196: }
 2197: #endif /* LIBXML_TREE_ENABLED */
 2198: 
 2199: #ifdef LIBXML_OUTPUT_ENABLED
 2200: /**
 2201:  * xmlDumpAttributeDecl:
 2202:  * @buf:  the XML buffer output
 2203:  * @attr:  An attribute declaration
 2204:  *
 2205:  * This will dump the content of the attribute declaration as an XML
 2206:  * DTD definition
 2207:  */
 2208: void
 2209: xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
 2210:     if ((buf == NULL) || (attr == NULL))
 2211:         return;
 2212:     xmlBufferWriteChar(buf, "<!ATTLIST ");
 2213:     xmlBufferWriteCHAR(buf, attr->elem);
 2214:     xmlBufferWriteChar(buf, " ");
 2215:     if (attr->prefix != NULL) {
 2216: 	xmlBufferWriteCHAR(buf, attr->prefix);
 2217: 	xmlBufferWriteChar(buf, ":");
 2218:     }
 2219:     xmlBufferWriteCHAR(buf, attr->name);
 2220:     switch (attr->atype) {
 2221: 	case XML_ATTRIBUTE_CDATA:
 2222: 	    xmlBufferWriteChar(buf, " CDATA");
 2223: 	    break;
 2224: 	case XML_ATTRIBUTE_ID:
 2225: 	    xmlBufferWriteChar(buf, " ID");
 2226: 	    break;
 2227: 	case XML_ATTRIBUTE_IDREF:
 2228: 	    xmlBufferWriteChar(buf, " IDREF");
 2229: 	    break;
 2230: 	case XML_ATTRIBUTE_IDREFS:
 2231: 	    xmlBufferWriteChar(buf, " IDREFS");
 2232: 	    break;
 2233: 	case XML_ATTRIBUTE_ENTITY:
 2234: 	    xmlBufferWriteChar(buf, " ENTITY");
 2235: 	    break;
 2236: 	case XML_ATTRIBUTE_ENTITIES:
 2237: 	    xmlBufferWriteChar(buf, " ENTITIES");
 2238: 	    break;
 2239: 	case XML_ATTRIBUTE_NMTOKEN:
 2240: 	    xmlBufferWriteChar(buf, " NMTOKEN");
 2241: 	    break;
 2242: 	case XML_ATTRIBUTE_NMTOKENS:
 2243: 	    xmlBufferWriteChar(buf, " NMTOKENS");
 2244: 	    break;
 2245: 	case XML_ATTRIBUTE_ENUMERATION:
 2246: 	    xmlBufferWriteChar(buf, " (");
 2247: 	    xmlDumpEnumeration(buf, attr->tree);
 2248: 	    break;
 2249: 	case XML_ATTRIBUTE_NOTATION:
 2250: 	    xmlBufferWriteChar(buf, " NOTATION (");
 2251: 	    xmlDumpEnumeration(buf, attr->tree);
 2252: 	    break;
 2253: 	default:
 2254: 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
 2255: 		    "Internal: ATTRIBUTE struct corrupted invalid type\n",
 2256: 		    NULL);
 2257:     }
 2258:     switch (attr->def) {
 2259: 	case XML_ATTRIBUTE_NONE:
 2260: 	    break;
 2261: 	case XML_ATTRIBUTE_REQUIRED:
 2262: 	    xmlBufferWriteChar(buf, " #REQUIRED");
 2263: 	    break;
 2264: 	case XML_ATTRIBUTE_IMPLIED:
 2265: 	    xmlBufferWriteChar(buf, " #IMPLIED");
 2266: 	    break;
 2267: 	case XML_ATTRIBUTE_FIXED:
 2268: 	    xmlBufferWriteChar(buf, " #FIXED");
 2269: 	    break;
 2270: 	default:
 2271: 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
 2272: 		    "Internal: ATTRIBUTE struct corrupted invalid def\n",
 2273: 		    NULL);
 2274:     }
 2275:     if (attr->defaultValue != NULL) {
 2276: 	xmlBufferWriteChar(buf, " ");
 2277: 	xmlBufferWriteQuotedString(buf, attr->defaultValue);
 2278:     }
 2279:     xmlBufferWriteChar(buf, ">\n");
 2280: }
 2281: 
 2282: /**
 2283:  * xmlDumpAttributeDeclScan:
 2284:  * @attr:  An attribute declaration
 2285:  * @buf:  the XML buffer output
 2286:  *
 2287:  * This is used with the hash scan function - just reverses arguments
 2288:  */
 2289: static void
 2290: xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
 2291:     xmlDumpAttributeDecl(buf, attr);
 2292: }
 2293: 
 2294: /**
 2295:  * xmlDumpAttributeTable:
 2296:  * @buf:  the XML buffer output
 2297:  * @table:  An attribute table
 2298:  *
 2299:  * This will dump the content of the attribute table as an XML DTD definition
 2300:  */
 2301: void
 2302: xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
 2303:     if ((buf == NULL) || (table == NULL))
 2304:         return;
 2305:     xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
 2306: }
 2307: #endif /* LIBXML_OUTPUT_ENABLED */
 2308: 
 2309: /************************************************************************
 2310:  *									*
 2311:  *				NOTATIONs				*
 2312:  *									*
 2313:  ************************************************************************/
 2314: /**
 2315:  * xmlFreeNotation:
 2316:  * @not:  A notation
 2317:  *
 2318:  * Deallocate the memory used by an notation definition
 2319:  */
 2320: static void
 2321: xmlFreeNotation(xmlNotationPtr nota) {
 2322:     if (nota == NULL) return;
 2323:     if (nota->name != NULL)
 2324: 	xmlFree((xmlChar *) nota->name);
 2325:     if (nota->PublicID != NULL)
 2326: 	xmlFree((xmlChar *) nota->PublicID);
 2327:     if (nota->SystemID != NULL)
 2328: 	xmlFree((xmlChar *) nota->SystemID);
 2329:     xmlFree(nota);
 2330: }
 2331: 
 2332: 
 2333: /**
 2334:  * xmlAddNotationDecl:
 2335:  * @dtd:  pointer to the DTD
 2336:  * @ctxt:  the validation context
 2337:  * @name:  the entity name
 2338:  * @PublicID:  the public identifier or NULL
 2339:  * @SystemID:  the system identifier or NULL
 2340:  *
 2341:  * Register a new notation declaration
 2342:  *
 2343:  * Returns NULL if not, otherwise the entity
 2344:  */
 2345: xmlNotationPtr
 2346: xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
 2347: 	           const xmlChar *name,
 2348:                    const xmlChar *PublicID, const xmlChar *SystemID) {
 2349:     xmlNotationPtr ret;
 2350:     xmlNotationTablePtr table;
 2351: 
 2352:     if (dtd == NULL) {
 2353: 	return(NULL);
 2354:     }
 2355:     if (name == NULL) {
 2356: 	return(NULL);
 2357:     }
 2358:     if ((PublicID == NULL) && (SystemID == NULL)) {
 2359: 	return(NULL);
 2360:     }
 2361: 
 2362:     /*
 2363:      * Create the Notation table if needed.
 2364:      */
 2365:     table = (xmlNotationTablePtr) dtd->notations;
 2366:     if (table == NULL) {
 2367: 	xmlDictPtr dict = NULL;
 2368: 	if (dtd->doc != NULL)
 2369: 	    dict = dtd->doc->dict;
 2370: 
 2371:         dtd->notations = table = xmlHashCreateDict(0, dict);
 2372:     }
 2373:     if (table == NULL) {
 2374: 	xmlVErrMemory(ctxt,
 2375: 		"xmlAddNotationDecl: Table creation failed!\n");
 2376:         return(NULL);
 2377:     }
 2378: 
 2379:     ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
 2380:     if (ret == NULL) {
 2381: 	xmlVErrMemory(ctxt, "malloc failed");
 2382: 	return(NULL);
 2383:     }
 2384:     memset(ret, 0, sizeof(xmlNotation));
 2385: 
 2386:     /*
 2387:      * fill the structure.
 2388:      */
 2389:     ret->name = xmlStrdup(name);
 2390:     if (SystemID != NULL)
 2391:         ret->SystemID = xmlStrdup(SystemID);
 2392:     if (PublicID != NULL)
 2393:         ret->PublicID = xmlStrdup(PublicID);
 2394: 
 2395:     /*
 2396:      * Validity Check:
 2397:      * Check the DTD for previous declarations of the ATTLIST
 2398:      */
 2399:     if (xmlHashAddEntry(table, name, ret)) {
 2400: #ifdef LIBXML_VALID_ENABLED
 2401: 	xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
 2402: 		    "xmlAddNotationDecl: %s already defined\n",
 2403: 		    (const char *) name);
 2404: #endif /* LIBXML_VALID_ENABLED */
 2405: 	xmlFreeNotation(ret);
 2406: 	return(NULL);
 2407:     }
 2408:     return(ret);
 2409: }
 2410: 
 2411: /**
 2412:  * xmlFreeNotationTable:
 2413:  * @table:  An notation table
 2414:  *
 2415:  * Deallocate the memory used by an entities hash table.
 2416:  */
 2417: void
 2418: xmlFreeNotationTable(xmlNotationTablePtr table) {
 2419:     xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
 2420: }
 2421: 
 2422: #ifdef LIBXML_TREE_ENABLED
 2423: /**
 2424:  * xmlCopyNotation:
 2425:  * @nota:  A notation
 2426:  *
 2427:  * Build a copy of a notation.
 2428:  *
 2429:  * Returns the new xmlNotationPtr or NULL in case of error.
 2430:  */
 2431: static xmlNotationPtr
 2432: xmlCopyNotation(xmlNotationPtr nota) {
 2433:     xmlNotationPtr cur;
 2434: 
 2435:     cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
 2436:     if (cur == NULL) {
 2437: 	xmlVErrMemory(NULL, "malloc failed");
 2438: 	return(NULL);
 2439:     }
 2440:     if (nota->name != NULL)
 2441: 	cur->name = xmlStrdup(nota->name);
 2442:     else
 2443: 	cur->name = NULL;
 2444:     if (nota->PublicID != NULL)
 2445: 	cur->PublicID = xmlStrdup(nota->PublicID);
 2446:     else
 2447: 	cur->PublicID = NULL;
 2448:     if (nota->SystemID != NULL)
 2449: 	cur->SystemID = xmlStrdup(nota->SystemID);
 2450:     else
 2451: 	cur->SystemID = NULL;
 2452:     return(cur);
 2453: }
 2454: 
 2455: /**
 2456:  * xmlCopyNotationTable:
 2457:  * @table:  A notation table
 2458:  *
 2459:  * Build a copy of a notation table.
 2460:  *
 2461:  * Returns the new xmlNotationTablePtr or NULL in case of error.
 2462:  */
 2463: xmlNotationTablePtr
 2464: xmlCopyNotationTable(xmlNotationTablePtr table) {
 2465:     return((xmlNotationTablePtr) xmlHashCopy(table,
 2466: 				    (xmlHashCopier) xmlCopyNotation));
 2467: }
 2468: #endif /* LIBXML_TREE_ENABLED */
 2469: 
 2470: #ifdef LIBXML_OUTPUT_ENABLED
 2471: /**
 2472:  * xmlDumpNotationDecl:
 2473:  * @buf:  the XML buffer output
 2474:  * @nota:  A notation declaration
 2475:  *
 2476:  * This will dump the content the notation declaration as an XML DTD definition
 2477:  */
 2478: void
 2479: xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
 2480:     if ((buf == NULL) || (nota == NULL))
 2481:         return;
 2482:     xmlBufferWriteChar(buf, "<!NOTATION ");
 2483:     xmlBufferWriteCHAR(buf, nota->name);
 2484:     if (nota->PublicID != NULL) {
 2485: 	xmlBufferWriteChar(buf, " PUBLIC ");
 2486: 	xmlBufferWriteQuotedString(buf, nota->PublicID);
 2487: 	if (nota->SystemID != NULL) {
 2488: 	    xmlBufferWriteChar(buf, " ");
 2489: 	    xmlBufferWriteQuotedString(buf, nota->SystemID);
 2490: 	}
 2491:     } else {
 2492: 	xmlBufferWriteChar(buf, " SYSTEM ");
 2493: 	xmlBufferWriteQuotedString(buf, nota->SystemID);
 2494:     }
 2495:     xmlBufferWriteChar(buf, " >\n");
 2496: }
 2497: 
 2498: /**
 2499:  * xmlDumpNotationDeclScan:
 2500:  * @nota:  A notation declaration
 2501:  * @buf:  the XML buffer output
 2502:  *
 2503:  * This is called with the hash scan function, and just reverses args
 2504:  */
 2505: static void
 2506: xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
 2507:     xmlDumpNotationDecl(buf, nota);
 2508: }
 2509: 
 2510: /**
 2511:  * xmlDumpNotationTable:
 2512:  * @buf:  the XML buffer output
 2513:  * @table:  A notation table
 2514:  *
 2515:  * This will dump the content of the notation table as an XML DTD definition
 2516:  */
 2517: void
 2518: xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
 2519:     if ((buf == NULL) || (table == NULL))
 2520:         return;
 2521:     xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
 2522: }
 2523: #endif /* LIBXML_OUTPUT_ENABLED */
 2524: 
 2525: /************************************************************************
 2526:  *									*
 2527:  *				IDs					*
 2528:  *									*
 2529:  ************************************************************************/
 2530: /**
 2531:  * DICT_FREE:
 2532:  * @str:  a string
 2533:  *
 2534:  * Free a string if it is not owned by the "dict" dictionnary in the
 2535:  * current scope
 2536:  */
 2537: #define DICT_FREE(str)						\
 2538: 	if ((str) && ((!dict) ||				\
 2539: 	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
 2540: 	    xmlFree((char *)(str));
 2541: 
 2542: /**
 2543:  * xmlFreeID:
 2544:  * @not:  A id
 2545:  *
 2546:  * Deallocate the memory used by an id definition
 2547:  */
 2548: static void
 2549: xmlFreeID(xmlIDPtr id) {
 2550:     xmlDictPtr dict = NULL;
 2551: 
 2552:     if (id == NULL) return;
 2553: 
 2554:     if (id->doc != NULL)
 2555:         dict = id->doc->dict;
 2556: 
 2557:     if (id->value != NULL)
 2558: 	DICT_FREE(id->value)
 2559:     if (id->name != NULL)
 2560: 	DICT_FREE(id->name)
 2561:     xmlFree(id);
 2562: }
 2563: 
 2564: 
 2565: /**
 2566:  * xmlAddID:
 2567:  * @ctxt:  the validation context
 2568:  * @doc:  pointer to the document
 2569:  * @value:  the value name
 2570:  * @attr:  the attribute holding the ID
 2571:  *
 2572:  * Register a new id declaration
 2573:  *
 2574:  * Returns NULL if not, otherwise the new xmlIDPtr
 2575:  */
 2576: xmlIDPtr
 2577: xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
 2578:          xmlAttrPtr attr) {
 2579:     xmlIDPtr ret;
 2580:     xmlIDTablePtr table;
 2581: 
 2582:     if (doc == NULL) {
 2583: 	return(NULL);
 2584:     }
 2585:     if (value == NULL) {
 2586: 	return(NULL);
 2587:     }
 2588:     if (attr == NULL) {
 2589: 	return(NULL);
 2590:     }
 2591: 
 2592:     /*
 2593:      * Create the ID table if needed.
 2594:      */
 2595:     table = (xmlIDTablePtr) doc->ids;
 2596:     if (table == NULL)  {
 2597:         doc->ids = table = xmlHashCreateDict(0, doc->dict);
 2598:     }
 2599:     if (table == NULL) {
 2600: 	xmlVErrMemory(ctxt,
 2601: 		"xmlAddID: Table creation failed!\n");
 2602:         return(NULL);
 2603:     }
 2604: 
 2605:     ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
 2606:     if (ret == NULL) {
 2607: 	xmlVErrMemory(ctxt, "malloc failed");
 2608: 	return(NULL);
 2609:     }
 2610: 
 2611:     /*
 2612:      * fill the structure.
 2613:      */
 2614:     ret->value = xmlStrdup(value);
 2615:     ret->doc = doc;
 2616:     if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
 2617: 	/*
 2618: 	 * Operating in streaming mode, attr is gonna disapear
 2619: 	 */
 2620: 	if (doc->dict != NULL)
 2621: 	    ret->name = xmlDictLookup(doc->dict, attr->name, -1);
 2622: 	else
 2623: 	    ret->name = xmlStrdup(attr->name);
 2624: 	ret->attr = NULL;
 2625:     } else {
 2626: 	ret->attr = attr;
 2627: 	ret->name = NULL;
 2628:     }
 2629:     ret->lineno = xmlGetLineNo(attr->parent);
 2630: 
 2631:     if (xmlHashAddEntry(table, value, ret) < 0) {
 2632: #ifdef LIBXML_VALID_ENABLED
 2633: 	/*
 2634: 	 * The id is already defined in this DTD.
 2635: 	 */
 2636: 	if ((ctxt != NULL) && (ctxt->error != NULL)) {
 2637: 	    xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
 2638: 	                    "ID %s already defined\n",
 2639: 			    value, NULL, NULL);
 2640: 	}
 2641: #endif /* LIBXML_VALID_ENABLED */
 2642: 	xmlFreeID(ret);
 2643: 	return(NULL);
 2644:     }
 2645:     if (attr != NULL)
 2646: 	attr->atype = XML_ATTRIBUTE_ID;
 2647:     return(ret);
 2648: }
 2649: 
 2650: /**
 2651:  * xmlFreeIDTable:
 2652:  * @table:  An id table
 2653:  *
 2654:  * Deallocate the memory used by an ID hash table.
 2655:  */
 2656: void
 2657: xmlFreeIDTable(xmlIDTablePtr table) {
 2658:     xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
 2659: }
 2660: 
 2661: /**
 2662:  * xmlIsID:
 2663:  * @doc:  the document
 2664:  * @elem:  the element carrying the attribute
 2665:  * @attr:  the attribute
 2666:  *
 2667:  * Determine whether an attribute is of type ID. In case we have DTD(s)
 2668:  * then this is done if DTD loading has been requested. In the case
 2669:  * of HTML documents parsed with the HTML parser, then ID detection is
 2670:  * done systematically.
 2671:  *
 2672:  * Returns 0 or 1 depending on the lookup result
 2673:  */
 2674: int
 2675: xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
 2676:     if ((attr == NULL) || (attr->name == NULL)) return(0);
 2677:     if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
 2678:         (!strcmp((char *) attr->name, "id")) &&
 2679:         (!strcmp((char *) attr->ns->prefix, "xml")))
 2680: 	return(1);
 2681:     if (doc == NULL) return(0);
 2682:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
 2683:         (doc->type != XML_HTML_DOCUMENT_NODE)) {
 2684: 	return(0);
 2685:     } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
 2686:         if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
 2687: 	    ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
 2688: 	    ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
 2689: 	    return(1);
 2690: 	return(0);
 2691:     } else if (elem == NULL) {
 2692: 	return(0);
 2693:     } else {
 2694: 	xmlAttributePtr attrDecl = NULL;
 2695: 
 2696: 	xmlChar felem[50], fattr[50];
 2697: 	xmlChar *fullelemname, *fullattrname;
 2698: 
 2699: 	fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
 2700: 	    xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
 2701: 	    (xmlChar *)elem->name;
 2702: 
 2703: 	fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
 2704: 	    xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
 2705: 	    (xmlChar *)attr->name;
 2706: 
 2707: 	if (fullelemname != NULL && fullattrname != NULL) {
 2708: 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
 2709: 		                         fullattrname);
 2710: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 2711: 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
 2712: 					     fullattrname);
 2713: 	}
 2714: 
 2715: 	if ((fullattrname != fattr) && (fullattrname != attr->name))
 2716: 	    xmlFree(fullattrname);
 2717: 	if ((fullelemname != felem) && (fullelemname != elem->name))
 2718: 	    xmlFree(fullelemname);
 2719: 
 2720:         if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
 2721: 	    return(1);
 2722:     }
 2723:     return(0);
 2724: }
 2725: 
 2726: /**
 2727:  * xmlRemoveID:
 2728:  * @doc:  the document
 2729:  * @attr:  the attribute
 2730:  *
 2731:  * Remove the given attribute from the ID table maintained internally.
 2732:  *
 2733:  * Returns -1 if the lookup failed and 0 otherwise
 2734:  */
 2735: int
 2736: xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
 2737:     xmlIDTablePtr table;
 2738:     xmlIDPtr id;
 2739:     xmlChar *ID;
 2740: 
 2741:     if (doc == NULL) return(-1);
 2742:     if (attr == NULL) return(-1);
 2743:     table = (xmlIDTablePtr) doc->ids;
 2744:     if (table == NULL)
 2745:         return(-1);
 2746: 
 2747:     if (attr == NULL)
 2748: 	return(-1);
 2749:     ID = xmlNodeListGetString(doc, attr->children, 1);
 2750:     if (ID == NULL)
 2751: 	return(-1);
 2752:     id = xmlHashLookup(table, ID);
 2753:     if (id == NULL || id->attr != attr) {
 2754: 	xmlFree(ID);
 2755: 	return(-1);
 2756:     }
 2757:     xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
 2758:     xmlFree(ID);
 2759: 	attr->atype = 0;
 2760:     return(0);
 2761: }
 2762: 
 2763: /**
 2764:  * xmlGetID:
 2765:  * @doc:  pointer to the document
 2766:  * @ID:  the ID value
 2767:  *
 2768:  * Search the attribute declaring the given ID
 2769:  *
 2770:  * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
 2771:  */
 2772: xmlAttrPtr
 2773: xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
 2774:     xmlIDTablePtr table;
 2775:     xmlIDPtr id;
 2776: 
 2777:     if (doc == NULL) {
 2778: 	return(NULL);
 2779:     }
 2780: 
 2781:     if (ID == NULL) {
 2782: 	return(NULL);
 2783:     }
 2784: 
 2785:     table = (xmlIDTablePtr) doc->ids;
 2786:     if (table == NULL)
 2787:         return(NULL);
 2788: 
 2789:     id = xmlHashLookup(table, ID);
 2790:     if (id == NULL)
 2791: 	return(NULL);
 2792:     if (id->attr == NULL) {
 2793: 	/*
 2794: 	 * We are operating on a stream, return a well known reference
 2795: 	 * since the attribute node doesn't exist anymore
 2796: 	 */
 2797: 	return((xmlAttrPtr) doc);
 2798:     }
 2799:     return(id->attr);
 2800: }
 2801: 
 2802: /************************************************************************
 2803:  *									*
 2804:  *				Refs					*
 2805:  *									*
 2806:  ************************************************************************/
 2807: typedef struct xmlRemoveMemo_t
 2808: {
 2809: 	xmlListPtr l;
 2810: 	xmlAttrPtr ap;
 2811: } xmlRemoveMemo;
 2812: 
 2813: typedef xmlRemoveMemo *xmlRemoveMemoPtr;
 2814: 
 2815: typedef struct xmlValidateMemo_t
 2816: {
 2817:     xmlValidCtxtPtr ctxt;
 2818:     const xmlChar *name;
 2819: } xmlValidateMemo;
 2820: 
 2821: typedef xmlValidateMemo *xmlValidateMemoPtr;
 2822: 
 2823: /**
 2824:  * xmlFreeRef:
 2825:  * @lk:  A list link
 2826:  *
 2827:  * Deallocate the memory used by a ref definition
 2828:  */
 2829: static void
 2830: xmlFreeRef(xmlLinkPtr lk) {
 2831:     xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
 2832:     if (ref == NULL) return;
 2833:     if (ref->value != NULL)
 2834:         xmlFree((xmlChar *)ref->value);
 2835:     if (ref->name != NULL)
 2836:         xmlFree((xmlChar *)ref->name);
 2837:     xmlFree(ref);
 2838: }
 2839: 
 2840: /**
 2841:  * xmlFreeRefList:
 2842:  * @list_ref:  A list of references.
 2843:  *
 2844:  * Deallocate the memory used by a list of references
 2845:  */
 2846: static void
 2847: xmlFreeRefList(xmlListPtr list_ref) {
 2848:     if (list_ref == NULL) return;
 2849:     xmlListDelete(list_ref);
 2850: }
 2851: 
 2852: /**
 2853:  * xmlWalkRemoveRef:
 2854:  * @data:  Contents of current link
 2855:  * @user:  Value supplied by the user
 2856:  *
 2857:  * Returns 0 to abort the walk or 1 to continue
 2858:  */
 2859: static int
 2860: xmlWalkRemoveRef(const void *data, const void *user)
 2861: {
 2862:     xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
 2863:     xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
 2864:     xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
 2865: 
 2866:     if (attr0 == attr1) { /* Matched: remove and terminate walk */
 2867:         xmlListRemoveFirst(ref_list, (void *)data);
 2868:         return 0;
 2869:     }
 2870:     return 1;
 2871: }
 2872: 
 2873: /**
 2874:  * xmlDummyCompare
 2875:  * @data0:  Value supplied by the user
 2876:  * @data1:  Value supplied by the user
 2877:  *
 2878:  * Do nothing, return 0. Used to create unordered lists.
 2879:  */
 2880: static int
 2881: xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
 2882:                 const void *data1 ATTRIBUTE_UNUSED)
 2883: {
 2884:     return (0);
 2885: }
 2886: 
 2887: /**
 2888:  * xmlAddRef:
 2889:  * @ctxt:  the validation context
 2890:  * @doc:  pointer to the document
 2891:  * @value:  the value name
 2892:  * @attr:  the attribute holding the Ref
 2893:  *
 2894:  * Register a new ref declaration
 2895:  *
 2896:  * Returns NULL if not, otherwise the new xmlRefPtr
 2897:  */
 2898: xmlRefPtr
 2899: xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
 2900:     xmlAttrPtr attr) {
 2901:     xmlRefPtr ret;
 2902:     xmlRefTablePtr table;
 2903:     xmlListPtr ref_list;
 2904: 
 2905:     if (doc == NULL) {
 2906:         return(NULL);
 2907:     }
 2908:     if (value == NULL) {
 2909:         return(NULL);
 2910:     }
 2911:     if (attr == NULL) {
 2912:         return(NULL);
 2913:     }
 2914: 
 2915:     /*
 2916:      * Create the Ref table if needed.
 2917:      */
 2918:     table = (xmlRefTablePtr) doc->refs;
 2919:     if (table == NULL) {
 2920:         doc->refs = table = xmlHashCreateDict(0, doc->dict);
 2921:     }
 2922:     if (table == NULL) {
 2923: 	xmlVErrMemory(ctxt,
 2924:             "xmlAddRef: Table creation failed!\n");
 2925:         return(NULL);
 2926:     }
 2927: 
 2928:     ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
 2929:     if (ret == NULL) {
 2930: 	xmlVErrMemory(ctxt, "malloc failed");
 2931:         return(NULL);
 2932:     }
 2933: 
 2934:     /*
 2935:      * fill the structure.
 2936:      */
 2937:     ret->value = xmlStrdup(value);
 2938:     if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
 2939: 	/*
 2940: 	 * Operating in streaming mode, attr is gonna disapear
 2941: 	 */
 2942: 	ret->name = xmlStrdup(attr->name);
 2943: 	ret->attr = NULL;
 2944:     } else {
 2945: 	ret->name = NULL;
 2946: 	ret->attr = attr;
 2947:     }
 2948:     ret->lineno = xmlGetLineNo(attr->parent);
 2949: 
 2950:     /* To add a reference :-
 2951:      * References are maintained as a list of references,
 2952:      * Lookup the entry, if no entry create new nodelist
 2953:      * Add the owning node to the NodeList
 2954:      * Return the ref
 2955:      */
 2956: 
 2957:     if (NULL == (ref_list = xmlHashLookup(table, value))) {
 2958:         if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
 2959: 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
 2960: 		    "xmlAddRef: Reference list creation failed!\n",
 2961: 		    NULL);
 2962: 	    goto failed;
 2963:         }
 2964:         if (xmlHashAddEntry(table, value, ref_list) < 0) {
 2965:             xmlListDelete(ref_list);
 2966: 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
 2967: 		    "xmlAddRef: Reference list insertion failed!\n",
 2968: 		    NULL);
 2969: 	    goto failed;
 2970:         }
 2971:     }
 2972:     if (xmlListAppend(ref_list, ret) != 0) {
 2973: 	xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
 2974: 		    "xmlAddRef: Reference list insertion failed!\n",
 2975: 		    NULL);
 2976:         goto failed;
 2977:     }
 2978:     return(ret);
 2979: failed:
 2980:     if (ret != NULL) {
 2981:         if (ret->value != NULL)
 2982: 	    xmlFree((char *)ret->value);
 2983:         if (ret->name != NULL)
 2984: 	    xmlFree((char *)ret->name);
 2985:         xmlFree(ret);
 2986:     }
 2987:     return(NULL);
 2988: }
 2989: 
 2990: /**
 2991:  * xmlFreeRefTable:
 2992:  * @table:  An ref table
 2993:  *
 2994:  * Deallocate the memory used by an Ref hash table.
 2995:  */
 2996: void
 2997: xmlFreeRefTable(xmlRefTablePtr table) {
 2998:     xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
 2999: }
 3000: 
 3001: /**
 3002:  * xmlIsRef:
 3003:  * @doc:  the document
 3004:  * @elem:  the element carrying the attribute
 3005:  * @attr:  the attribute
 3006:  *
 3007:  * Determine whether an attribute is of type Ref. In case we have DTD(s)
 3008:  * then this is simple, otherwise we use an heuristic: name Ref (upper
 3009:  * or lowercase).
 3010:  *
 3011:  * Returns 0 or 1 depending on the lookup result
 3012:  */
 3013: int
 3014: xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
 3015:     if (attr == NULL)
 3016:         return(0);
 3017:     if (doc == NULL) {
 3018:         doc = attr->doc;
 3019: 	if (doc == NULL) return(0);
 3020:     }
 3021: 
 3022:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
 3023:         return(0);
 3024:     } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
 3025:         /* TODO @@@ */
 3026:         return(0);
 3027:     } else {
 3028:         xmlAttributePtr attrDecl;
 3029: 
 3030:         if (elem == NULL) return(0);
 3031:         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
 3032:         if ((attrDecl == NULL) && (doc->extSubset != NULL))
 3033:             attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
 3034: 		                         elem->name, attr->name);
 3035: 
 3036: 	if ((attrDecl != NULL) &&
 3037: 	    (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
 3038: 	     attrDecl->atype == XML_ATTRIBUTE_IDREFS))
 3039: 	return(1);
 3040:     }
 3041:     return(0);
 3042: }
 3043: 
 3044: /**
 3045:  * xmlRemoveRef:
 3046:  * @doc:  the document
 3047:  * @attr:  the attribute
 3048:  *
 3049:  * Remove the given attribute from the Ref table maintained internally.
 3050:  *
 3051:  * Returns -1 if the lookup failed and 0 otherwise
 3052:  */
 3053: int
 3054: xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
 3055:     xmlListPtr ref_list;
 3056:     xmlRefTablePtr table;
 3057:     xmlChar *ID;
 3058:     xmlRemoveMemo target;
 3059: 
 3060:     if (doc == NULL) return(-1);
 3061:     if (attr == NULL) return(-1);
 3062:     table = (xmlRefTablePtr) doc->refs;
 3063:     if (table == NULL)
 3064:         return(-1);
 3065: 
 3066:     if (attr == NULL)
 3067:         return(-1);
 3068:     ID = xmlNodeListGetString(doc, attr->children, 1);
 3069:     if (ID == NULL)
 3070:         return(-1);
 3071:     ref_list = xmlHashLookup(table, ID);
 3072: 
 3073:     if(ref_list == NULL) {
 3074:         xmlFree(ID);
 3075:         return (-1);
 3076:     }
 3077:     /* At this point, ref_list refers to a list of references which
 3078:      * have the same key as the supplied attr. Our list of references
 3079:      * is ordered by reference address and we don't have that information
 3080:      * here to use when removing. We'll have to walk the list and
 3081:      * check for a matching attribute, when we find one stop the walk
 3082:      * and remove the entry.
 3083:      * The list is ordered by reference, so that means we don't have the
 3084:      * key. Passing the list and the reference to the walker means we
 3085:      * will have enough data to be able to remove the entry.
 3086:      */
 3087:     target.l = ref_list;
 3088:     target.ap = attr;
 3089: 
 3090:     /* Remove the supplied attr from our list */
 3091:     xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
 3092: 
 3093:     /*If the list is empty then remove the list entry in the hash */
 3094:     if (xmlListEmpty(ref_list))
 3095:         xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
 3096:         xmlFreeRefList);
 3097:     xmlFree(ID);
 3098:     return(0);
 3099: }
 3100: 
 3101: /**
 3102:  * xmlGetRefs:
 3103:  * @doc:  pointer to the document
 3104:  * @ID:  the ID value
 3105:  *
 3106:  * Find the set of references for the supplied ID.
 3107:  *
 3108:  * Returns NULL if not found, otherwise node set for the ID.
 3109:  */
 3110: xmlListPtr
 3111: xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
 3112:     xmlRefTablePtr table;
 3113: 
 3114:     if (doc == NULL) {
 3115:         return(NULL);
 3116:     }
 3117: 
 3118:     if (ID == NULL) {
 3119:         return(NULL);
 3120:     }
 3121: 
 3122:     table = (xmlRefTablePtr) doc->refs;
 3123:     if (table == NULL)
 3124:         return(NULL);
 3125: 
 3126:     return (xmlHashLookup(table, ID));
 3127: }
 3128: 
 3129: /************************************************************************
 3130:  *									*
 3131:  *		Routines for validity checking				*
 3132:  *									*
 3133:  ************************************************************************/
 3134: 
 3135: /**
 3136:  * xmlGetDtdElementDesc:
 3137:  * @dtd:  a pointer to the DtD to search
 3138:  * @name:  the element name
 3139:  *
 3140:  * Search the DTD for the description of this element
 3141:  *
 3142:  * returns the xmlElementPtr if found or NULL
 3143:  */
 3144: 
 3145: xmlElementPtr
 3146: xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
 3147:     xmlElementTablePtr table;
 3148:     xmlElementPtr cur;
 3149:     xmlChar *uqname = NULL, *prefix = NULL;
 3150: 
 3151:     if ((dtd == NULL) || (name == NULL)) return(NULL);
 3152:     if (dtd->elements == NULL)
 3153: 	return(NULL);
 3154:     table = (xmlElementTablePtr) dtd->elements;
 3155: 
 3156:     uqname = xmlSplitQName2(name, &prefix);
 3157:     if (uqname != NULL)
 3158:         name = uqname;
 3159:     cur = xmlHashLookup2(table, name, prefix);
 3160:     if (prefix != NULL) xmlFree(prefix);
 3161:     if (uqname != NULL) xmlFree(uqname);
 3162:     return(cur);
 3163: }
 3164: /**
 3165:  * xmlGetDtdElementDesc2:
 3166:  * @dtd:  a pointer to the DtD to search
 3167:  * @name:  the element name
 3168:  * @create:  create an empty description if not found
 3169:  *
 3170:  * Search the DTD for the description of this element
 3171:  *
 3172:  * returns the xmlElementPtr if found or NULL
 3173:  */
 3174: 
 3175: static xmlElementPtr
 3176: xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
 3177:     xmlElementTablePtr table;
 3178:     xmlElementPtr cur;
 3179:     xmlChar *uqname = NULL, *prefix = NULL;
 3180: 
 3181:     if (dtd == NULL) return(NULL);
 3182:     if (dtd->elements == NULL) {
 3183: 	xmlDictPtr dict = NULL;
 3184: 
 3185: 	if (dtd->doc != NULL)
 3186: 	    dict = dtd->doc->dict;
 3187: 
 3188: 	if (!create)
 3189: 	    return(NULL);
 3190: 	/*
 3191: 	 * Create the Element table if needed.
 3192: 	 */
 3193: 	table = (xmlElementTablePtr) dtd->elements;
 3194: 	if (table == NULL) {
 3195: 	    table = xmlHashCreateDict(0, dict);
 3196: 	    dtd->elements = (void *) table;
 3197: 	}
 3198: 	if (table == NULL) {
 3199: 	    xmlVErrMemory(NULL, "element table allocation failed");
 3200: 	    return(NULL);
 3201: 	}
 3202:     }
 3203:     table = (xmlElementTablePtr) dtd->elements;
 3204: 
 3205:     uqname = xmlSplitQName2(name, &prefix);
 3206:     if (uqname != NULL)
 3207:         name = uqname;
 3208:     cur = xmlHashLookup2(table, name, prefix);
 3209:     if ((cur == NULL) && (create)) {
 3210: 	cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
 3211: 	if (cur == NULL) {
 3212: 	    xmlVErrMemory(NULL, "malloc failed");
 3213: 	    return(NULL);
 3214: 	}
 3215: 	memset(cur, 0, sizeof(xmlElement));
 3216: 	cur->type = XML_ELEMENT_DECL;
 3217: 
 3218: 	/*
 3219: 	 * fill the structure.
 3220: 	 */
 3221: 	cur->name = xmlStrdup(name);
 3222: 	cur->prefix = xmlStrdup(prefix);
 3223: 	cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
 3224: 
 3225: 	xmlHashAddEntry2(table, name, prefix, cur);
 3226:     }
 3227:     if (prefix != NULL) xmlFree(prefix);
 3228:     if (uqname != NULL) xmlFree(uqname);
 3229:     return(cur);
 3230: }
 3231: 
 3232: /**
 3233:  * xmlGetDtdQElementDesc:
 3234:  * @dtd:  a pointer to the DtD to search
 3235:  * @name:  the element name
 3236:  * @prefix:  the element namespace prefix
 3237:  *
 3238:  * Search the DTD for the description of this element
 3239:  *
 3240:  * returns the xmlElementPtr if found or NULL
 3241:  */
 3242: 
 3243: xmlElementPtr
 3244: xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
 3245: 	              const xmlChar *prefix) {
 3246:     xmlElementTablePtr table;
 3247: 
 3248:     if (dtd == NULL) return(NULL);
 3249:     if (dtd->elements == NULL) return(NULL);
 3250:     table = (xmlElementTablePtr) dtd->elements;
 3251: 
 3252:     return(xmlHashLookup2(table, name, prefix));
 3253: }
 3254: 
 3255: /**
 3256:  * xmlGetDtdAttrDesc:
 3257:  * @dtd:  a pointer to the DtD to search
 3258:  * @elem:  the element name
 3259:  * @name:  the attribute name
 3260:  *
 3261:  * Search the DTD for the description of this attribute on
 3262:  * this element.
 3263:  *
 3264:  * returns the xmlAttributePtr if found or NULL
 3265:  */
 3266: 
 3267: xmlAttributePtr
 3268: xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
 3269:     xmlAttributeTablePtr table;
 3270:     xmlAttributePtr cur;
 3271:     xmlChar *uqname = NULL, *prefix = NULL;
 3272: 
 3273:     if (dtd == NULL) return(NULL);
 3274:     if (dtd->attributes == NULL) return(NULL);
 3275: 
 3276:     table = (xmlAttributeTablePtr) dtd->attributes;
 3277:     if (table == NULL)
 3278: 	return(NULL);
 3279: 
 3280:     uqname = xmlSplitQName2(name, &prefix);
 3281: 
 3282:     if (uqname != NULL) {
 3283: 	cur = xmlHashLookup3(table, uqname, prefix, elem);
 3284: 	if (prefix != NULL) xmlFree(prefix);
 3285: 	if (uqname != NULL) xmlFree(uqname);
 3286:     } else
 3287: 	cur = xmlHashLookup3(table, name, NULL, elem);
 3288:     return(cur);
 3289: }
 3290: 
 3291: /**
 3292:  * xmlGetDtdQAttrDesc:
 3293:  * @dtd:  a pointer to the DtD to search
 3294:  * @elem:  the element name
 3295:  * @name:  the attribute name
 3296:  * @prefix:  the attribute namespace prefix
 3297:  *
 3298:  * Search the DTD for the description of this qualified attribute on
 3299:  * this element.
 3300:  *
 3301:  * returns the xmlAttributePtr if found or NULL
 3302:  */
 3303: 
 3304: xmlAttributePtr
 3305: xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
 3306: 	          const xmlChar *prefix) {
 3307:     xmlAttributeTablePtr table;
 3308: 
 3309:     if (dtd == NULL) return(NULL);
 3310:     if (dtd->attributes == NULL) return(NULL);
 3311:     table = (xmlAttributeTablePtr) dtd->attributes;
 3312: 
 3313:     return(xmlHashLookup3(table, name, prefix, elem));
 3314: }
 3315: 
 3316: /**
 3317:  * xmlGetDtdNotationDesc:
 3318:  * @dtd:  a pointer to the DtD to search
 3319:  * @name:  the notation name
 3320:  *
 3321:  * Search the DTD for the description of this notation
 3322:  *
 3323:  * returns the xmlNotationPtr if found or NULL
 3324:  */
 3325: 
 3326: xmlNotationPtr
 3327: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
 3328:     xmlNotationTablePtr table;
 3329: 
 3330:     if (dtd == NULL) return(NULL);
 3331:     if (dtd->notations == NULL) return(NULL);
 3332:     table = (xmlNotationTablePtr) dtd->notations;
 3333: 
 3334:     return(xmlHashLookup(table, name));
 3335: }
 3336: 
 3337: #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
 3338: /**
 3339:  * xmlValidateNotationUse:
 3340:  * @ctxt:  the validation context
 3341:  * @doc:  the document
 3342:  * @notationName:  the notation name to check
 3343:  *
 3344:  * Validate that the given name match a notation declaration.
 3345:  * - [ VC: Notation Declared ]
 3346:  *
 3347:  * returns 1 if valid or 0 otherwise
 3348:  */
 3349: 
 3350: int
 3351: xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 3352:                        const xmlChar *notationName) {
 3353:     xmlNotationPtr notaDecl;
 3354:     if ((doc == NULL) || (doc->intSubset == NULL) ||
 3355:         (notationName == NULL)) return(-1);
 3356: 
 3357:     notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
 3358:     if ((notaDecl == NULL) && (doc->extSubset != NULL))
 3359: 	notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
 3360: 
 3361:     if ((notaDecl == NULL) && (ctxt != NULL)) {
 3362: 	xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
 3363: 	                "NOTATION %s is not declared\n",
 3364: 		        notationName, NULL, NULL);
 3365: 	return(0);
 3366:     }
 3367:     return(1);
 3368: }
 3369: #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
 3370: 
 3371: /**
 3372:  * xmlIsMixedElement:
 3373:  * @doc:  the document
 3374:  * @name:  the element name
 3375:  *
 3376:  * Search in the DtDs whether an element accept Mixed content (or ANY)
 3377:  * basically if it is supposed to accept text childs
 3378:  *
 3379:  * returns 0 if no, 1 if yes, and -1 if no element description is available
 3380:  */
 3381: 
 3382: int
 3383: xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
 3384:     xmlElementPtr elemDecl;
 3385: 
 3386:     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
 3387: 
 3388:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
 3389:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
 3390: 	elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
 3391:     if (elemDecl == NULL) return(-1);
 3392:     switch (elemDecl->etype) {
 3393: 	case XML_ELEMENT_TYPE_UNDEFINED:
 3394: 	    return(-1);
 3395: 	case XML_ELEMENT_TYPE_ELEMENT:
 3396: 	    return(0);
 3397:         case XML_ELEMENT_TYPE_EMPTY:
 3398: 	    /*
 3399: 	     * return 1 for EMPTY since we want VC error to pop up
 3400: 	     * on <empty>     </empty> for example
 3401: 	     */
 3402: 	case XML_ELEMENT_TYPE_ANY:
 3403: 	case XML_ELEMENT_TYPE_MIXED:
 3404: 	    return(1);
 3405:     }
 3406:     return(1);
 3407: }
 3408: 
 3409: #ifdef LIBXML_VALID_ENABLED
 3410: 
 3411: static int
 3412: xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
 3413:     if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
 3414:         /*
 3415: 	 * Use the new checks of production [4] [4a] amd [5] of the
 3416: 	 * Update 5 of XML-1.0
 3417: 	 */
 3418: 	if (((c >= 'a') && (c <= 'z')) ||
 3419: 	    ((c >= 'A') && (c <= 'Z')) ||
 3420: 	    (c == '_') || (c == ':') ||
 3421: 	    ((c >= 0xC0) && (c <= 0xD6)) ||
 3422: 	    ((c >= 0xD8) && (c <= 0xF6)) ||
 3423: 	    ((c >= 0xF8) && (c <= 0x2FF)) ||
 3424: 	    ((c >= 0x370) && (c <= 0x37D)) ||
 3425: 	    ((c >= 0x37F) && (c <= 0x1FFF)) ||
 3426: 	    ((c >= 0x200C) && (c <= 0x200D)) ||
 3427: 	    ((c >= 0x2070) && (c <= 0x218F)) ||
 3428: 	    ((c >= 0x2C00) && (c <= 0x2FEF)) ||
 3429: 	    ((c >= 0x3001) && (c <= 0xD7FF)) ||
 3430: 	    ((c >= 0xF900) && (c <= 0xFDCF)) ||
 3431: 	    ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
 3432: 	    ((c >= 0x10000) && (c <= 0xEFFFF)))
 3433: 	    return(1);
 3434:     } else {
 3435:         if (IS_LETTER(c) || (c == '_') || (c == ':'))
 3436: 	    return(1);
 3437:     }
 3438:     return(0);
 3439: }
 3440: 
 3441: static int
 3442: xmlIsDocNameChar(xmlDocPtr doc, int c) {
 3443:     if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
 3444:         /*
 3445: 	 * Use the new checks of production [4] [4a] amd [5] of the
 3446: 	 * Update 5 of XML-1.0
 3447: 	 */
 3448: 	if (((c >= 'a') && (c <= 'z')) ||
 3449: 	    ((c >= 'A') && (c <= 'Z')) ||
 3450: 	    ((c >= '0') && (c <= '9')) || /* !start */
 3451: 	    (c == '_') || (c == ':') ||
 3452: 	    (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
 3453: 	    ((c >= 0xC0) && (c <= 0xD6)) ||
 3454: 	    ((c >= 0xD8) && (c <= 0xF6)) ||
 3455: 	    ((c >= 0xF8) && (c <= 0x2FF)) ||
 3456: 	    ((c >= 0x300) && (c <= 0x36F)) || /* !start */
 3457: 	    ((c >= 0x370) && (c <= 0x37D)) ||
 3458: 	    ((c >= 0x37F) && (c <= 0x1FFF)) ||
 3459: 	    ((c >= 0x200C) && (c <= 0x200D)) ||
 3460: 	    ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
 3461: 	    ((c >= 0x2070) && (c <= 0x218F)) ||
 3462: 	    ((c >= 0x2C00) && (c <= 0x2FEF)) ||
 3463: 	    ((c >= 0x3001) && (c <= 0xD7FF)) ||
 3464: 	    ((c >= 0xF900) && (c <= 0xFDCF)) ||
 3465: 	    ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
 3466: 	    ((c >= 0x10000) && (c <= 0xEFFFF)))
 3467: 	     return(1);
 3468:     } else {
 3469:         if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
 3470:             (c == '.') || (c == '-') ||
 3471: 	    (c == '_') || (c == ':') ||
 3472: 	    (IS_COMBINING(c)) ||
 3473: 	    (IS_EXTENDER(c)))
 3474: 	    return(1);
 3475:     }
 3476:     return(0);
 3477: }
 3478: 
 3479: /**
 3480:  * xmlValidateNameValue:
 3481:  * @doc:  pointer to the document or NULL
 3482:  * @value:  an Name value
 3483:  *
 3484:  * Validate that the given value match Name production
 3485:  *
 3486:  * returns 1 if valid or 0 otherwise
 3487:  */
 3488: 
 3489: static int
 3490: xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
 3491:     const xmlChar *cur;
 3492:     int val, len;
 3493: 
 3494:     if (value == NULL) return(0);
 3495:     cur = value;
 3496:     val = xmlStringCurrentChar(NULL, cur, &len);
 3497:     cur += len;
 3498:     if (!xmlIsDocNameStartChar(doc, val))
 3499: 	return(0);
 3500: 
 3501:     val = xmlStringCurrentChar(NULL, cur, &len);
 3502:     cur += len;
 3503:     while (xmlIsDocNameChar(doc, val)) {
 3504: 	val = xmlStringCurrentChar(NULL, cur, &len);
 3505: 	cur += len;
 3506:     }
 3507: 
 3508:     if (val != 0) return(0);
 3509: 
 3510:     return(1);
 3511: }
 3512: 
 3513: /**
 3514:  * xmlValidateNameValue:
 3515:  * @value:  an Name value
 3516:  *
 3517:  * Validate that the given value match Name production
 3518:  *
 3519:  * returns 1 if valid or 0 otherwise
 3520:  */
 3521: 
 3522: int
 3523: xmlValidateNameValue(const xmlChar *value) {
 3524:     return(xmlValidateNameValueInternal(NULL, value));
 3525: }
 3526: 
 3527: /**
 3528:  * xmlValidateNamesValueInternal:
 3529:  * @doc:  pointer to the document or NULL
 3530:  * @value:  an Names value
 3531:  *
 3532:  * Validate that the given value match Names production
 3533:  *
 3534:  * returns 1 if valid or 0 otherwise
 3535:  */
 3536: 
 3537: static int
 3538: xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
 3539:     const xmlChar *cur;
 3540:     int val, len;
 3541: 
 3542:     if (value == NULL) return(0);
 3543:     cur = value;
 3544:     val = xmlStringCurrentChar(NULL, cur, &len);
 3545:     cur += len;
 3546: 
 3547:     if (!xmlIsDocNameStartChar(doc, val))
 3548: 	return(0);
 3549: 
 3550:     val = xmlStringCurrentChar(NULL, cur, &len);
 3551:     cur += len;
 3552:     while (xmlIsDocNameChar(doc, val)) {
 3553: 	val = xmlStringCurrentChar(NULL, cur, &len);
 3554: 	cur += len;
 3555:     }
 3556: 
 3557:     /* Should not test IS_BLANK(val) here -- see erratum E20*/
 3558:     while (val == 0x20) {
 3559: 	while (val == 0x20) {
 3560: 	    val = xmlStringCurrentChar(NULL, cur, &len);
 3561: 	    cur += len;
 3562: 	}
 3563: 
 3564: 	if (!xmlIsDocNameStartChar(doc, val))
 3565: 	    return(0);
 3566: 
 3567: 	val = xmlStringCurrentChar(NULL, cur, &len);
 3568: 	cur += len;
 3569: 
 3570: 	while (xmlIsDocNameChar(doc, val)) {
 3571: 	    val = xmlStringCurrentChar(NULL, cur, &len);
 3572: 	    cur += len;
 3573: 	}
 3574:     }
 3575: 
 3576:     if (val != 0) return(0);
 3577: 
 3578:     return(1);
 3579: }
 3580: 
 3581: /**
 3582:  * xmlValidateNamesValue:
 3583:  * @value:  an Names value
 3584:  *
 3585:  * Validate that the given value match Names production
 3586:  *
 3587:  * returns 1 if valid or 0 otherwise
 3588:  */
 3589: 
 3590: int
 3591: xmlValidateNamesValue(const xmlChar *value) {
 3592:     return(xmlValidateNamesValueInternal(NULL, value));
 3593: }
 3594: 
 3595: /**
 3596:  * xmlValidateNmtokenValueInternal:
 3597:  * @doc:  pointer to the document or NULL
 3598:  * @value:  an Nmtoken value
 3599:  *
 3600:  * Validate that the given value match Nmtoken production
 3601:  *
 3602:  * [ VC: Name Token ]
 3603:  *
 3604:  * returns 1 if valid or 0 otherwise
 3605:  */
 3606: 
 3607: static int
 3608: xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
 3609:     const xmlChar *cur;
 3610:     int val, len;
 3611: 
 3612:     if (value == NULL) return(0);
 3613:     cur = value;
 3614:     val = xmlStringCurrentChar(NULL, cur, &len);
 3615:     cur += len;
 3616: 
 3617:     if (!xmlIsDocNameChar(doc, val))
 3618: 	return(0);
 3619: 
 3620:     val = xmlStringCurrentChar(NULL, cur, &len);
 3621:     cur += len;
 3622:     while (xmlIsDocNameChar(doc, val)) {
 3623: 	val = xmlStringCurrentChar(NULL, cur, &len);
 3624: 	cur += len;
 3625:     }
 3626: 
 3627:     if (val != 0) return(0);
 3628: 
 3629:     return(1);
 3630: }
 3631: 
 3632: /**
 3633:  * xmlValidateNmtokenValue:
 3634:  * @value:  an Nmtoken value
 3635:  *
 3636:  * Validate that the given value match Nmtoken production
 3637:  *
 3638:  * [ VC: Name Token ]
 3639:  *
 3640:  * returns 1 if valid or 0 otherwise
 3641:  */
 3642: 
 3643: int
 3644: xmlValidateNmtokenValue(const xmlChar *value) {
 3645:     return(xmlValidateNmtokenValueInternal(NULL, value));
 3646: }
 3647: 
 3648: /**
 3649:  * xmlValidateNmtokensValueInternal:
 3650:  * @doc:  pointer to the document or NULL
 3651:  * @value:  an Nmtokens value
 3652:  *
 3653:  * Validate that the given value match Nmtokens production
 3654:  *
 3655:  * [ VC: Name Token ]
 3656:  *
 3657:  * returns 1 if valid or 0 otherwise
 3658:  */
 3659: 
 3660: static int
 3661: xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
 3662:     const xmlChar *cur;
 3663:     int val, len;
 3664: 
 3665:     if (value == NULL) return(0);
 3666:     cur = value;
 3667:     val = xmlStringCurrentChar(NULL, cur, &len);
 3668:     cur += len;
 3669: 
 3670:     while (IS_BLANK(val)) {
 3671: 	val = xmlStringCurrentChar(NULL, cur, &len);
 3672: 	cur += len;
 3673:     }
 3674: 
 3675:     if (!xmlIsDocNameChar(doc, val))
 3676: 	return(0);
 3677: 
 3678:     while (xmlIsDocNameChar(doc, val)) {
 3679: 	val = xmlStringCurrentChar(NULL, cur, &len);
 3680: 	cur += len;
 3681:     }
 3682: 
 3683:     /* Should not test IS_BLANK(val) here -- see erratum E20*/
 3684:     while (val == 0x20) {
 3685: 	while (val == 0x20) {
 3686: 	    val = xmlStringCurrentChar(NULL, cur, &len);
 3687: 	    cur += len;
 3688: 	}
 3689: 	if (val == 0) return(1);
 3690: 
 3691: 	if (!xmlIsDocNameChar(doc, val))
 3692: 	    return(0);
 3693: 
 3694: 	val = xmlStringCurrentChar(NULL, cur, &len);
 3695: 	cur += len;
 3696: 
 3697: 	while (xmlIsDocNameChar(doc, val)) {
 3698: 	    val = xmlStringCurrentChar(NULL, cur, &len);
 3699: 	    cur += len;
 3700: 	}
 3701:     }
 3702: 
 3703:     if (val != 0) return(0);
 3704: 
 3705:     return(1);
 3706: }
 3707: 
 3708: /**
 3709:  * xmlValidateNmtokensValue:
 3710:  * @value:  an Nmtokens value
 3711:  *
 3712:  * Validate that the given value match Nmtokens production
 3713:  *
 3714:  * [ VC: Name Token ]
 3715:  *
 3716:  * returns 1 if valid or 0 otherwise
 3717:  */
 3718: 
 3719: int
 3720: xmlValidateNmtokensValue(const xmlChar *value) {
 3721:     return(xmlValidateNmtokensValueInternal(NULL, value));
 3722: }
 3723: 
 3724: /**
 3725:  * xmlValidateNotationDecl:
 3726:  * @ctxt:  the validation context
 3727:  * @doc:  a document instance
 3728:  * @nota:  a notation definition
 3729:  *
 3730:  * Try to validate a single notation definition
 3731:  * basically it does the following checks as described by the
 3732:  * XML-1.0 recommendation:
 3733:  *  - it seems that no validity constraint exists on notation declarations
 3734:  * But this function get called anyway ...
 3735:  *
 3736:  * returns 1 if valid or 0 otherwise
 3737:  */
 3738: 
 3739: int
 3740: xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
 3741:                          xmlNotationPtr nota ATTRIBUTE_UNUSED) {
 3742:     int ret = 1;
 3743: 
 3744:     return(ret);
 3745: }
 3746: 
 3747: /**
 3748:  * xmlValidateAttributeValueInternal:
 3749:  * @doc: the document
 3750:  * @type:  an attribute type
 3751:  * @value:  an attribute value
 3752:  *
 3753:  * Validate that the given attribute value match  the proper production
 3754:  *
 3755:  * returns 1 if valid or 0 otherwise
 3756:  */
 3757: 
 3758: static int
 3759: xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
 3760:                                   const xmlChar *value) {
 3761:     switch (type) {
 3762: 	case XML_ATTRIBUTE_ENTITIES:
 3763: 	case XML_ATTRIBUTE_IDREFS:
 3764: 	    return(xmlValidateNamesValueInternal(doc, value));
 3765: 	case XML_ATTRIBUTE_ENTITY:
 3766: 	case XML_ATTRIBUTE_IDREF:
 3767: 	case XML_ATTRIBUTE_ID:
 3768: 	case XML_ATTRIBUTE_NOTATION:
 3769: 	    return(xmlValidateNameValueInternal(doc, value));
 3770: 	case XML_ATTRIBUTE_NMTOKENS:
 3771: 	case XML_ATTRIBUTE_ENUMERATION:
 3772: 	    return(xmlValidateNmtokensValueInternal(doc, value));
 3773: 	case XML_ATTRIBUTE_NMTOKEN:
 3774: 	    return(xmlValidateNmtokenValueInternal(doc, value));
 3775:         case XML_ATTRIBUTE_CDATA:
 3776: 	    break;
 3777:     }
 3778:     return(1);
 3779: }
 3780: 
 3781: /**
 3782:  * xmlValidateAttributeValue:
 3783:  * @type:  an attribute type
 3784:  * @value:  an attribute value
 3785:  *
 3786:  * Validate that the given attribute value match  the proper production
 3787:  *
 3788:  * [ VC: ID ]
 3789:  * Values of type ID must match the Name production....
 3790:  *
 3791:  * [ VC: IDREF ]
 3792:  * Values of type IDREF must match the Name production, and values
 3793:  * of type IDREFS must match Names ...
 3794:  *
 3795:  * [ VC: Entity Name ]
 3796:  * Values of type ENTITY must match the Name production, values
 3797:  * of type ENTITIES must match Names ...
 3798:  *
 3799:  * [ VC: Name Token ]
 3800:  * Values of type NMTOKEN must match the Nmtoken production; values
 3801:  * of type NMTOKENS must match Nmtokens.
 3802:  *
 3803:  * returns 1 if valid or 0 otherwise
 3804:  */
 3805: int
 3806: xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
 3807:     return(xmlValidateAttributeValueInternal(NULL, type, value));
 3808: }
 3809: 
 3810: /**
 3811:  * xmlValidateAttributeValue2:
 3812:  * @ctxt:  the validation context
 3813:  * @doc:  the document
 3814:  * @name:  the attribute name (used for error reporting only)
 3815:  * @type:  the attribute type
 3816:  * @value:  the attribute value
 3817:  *
 3818:  * Validate that the given attribute value match a given type.
 3819:  * This typically cannot be done before having finished parsing
 3820:  * the subsets.
 3821:  *
 3822:  * [ VC: IDREF ]
 3823:  * Values of type IDREF must match one of the declared IDs
 3824:  * Values of type IDREFS must match a sequence of the declared IDs
 3825:  * each Name must match the value of an ID attribute on some element
 3826:  * in the XML document; i.e. IDREF values must match the value of
 3827:  * some ID attribute
 3828:  *
 3829:  * [ VC: Entity Name ]
 3830:  * Values of type ENTITY must match one declared entity
 3831:  * Values of type ENTITIES must match a sequence of declared entities
 3832:  *
 3833:  * [ VC: Notation Attributes ]
 3834:  * all notation names in the declaration must be declared.
 3835:  *
 3836:  * returns 1 if valid or 0 otherwise
 3837:  */
 3838: 
 3839: static int
 3840: xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 3841:       const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
 3842:     int ret = 1;
 3843:     switch (type) {
 3844: 	case XML_ATTRIBUTE_IDREFS:
 3845: 	case XML_ATTRIBUTE_IDREF:
 3846: 	case XML_ATTRIBUTE_ID:
 3847: 	case XML_ATTRIBUTE_NMTOKENS:
 3848: 	case XML_ATTRIBUTE_ENUMERATION:
 3849: 	case XML_ATTRIBUTE_NMTOKEN:
 3850:         case XML_ATTRIBUTE_CDATA:
 3851: 	    break;
 3852: 	case XML_ATTRIBUTE_ENTITY: {
 3853: 	    xmlEntityPtr ent;
 3854: 
 3855: 	    ent = xmlGetDocEntity(doc, value);
 3856: 	    /* yeah it's a bit messy... */
 3857: 	    if ((ent == NULL) && (doc->standalone == 1)) {
 3858: 		doc->standalone = 0;
 3859: 		ent = xmlGetDocEntity(doc, value);
 3860: 	    }
 3861: 	    if (ent == NULL) {
 3862: 		xmlErrValidNode(ctxt, (xmlNodePtr) doc,
 3863: 				XML_DTD_UNKNOWN_ENTITY,
 3864:    "ENTITY attribute %s reference an unknown entity \"%s\"\n",
 3865: 		       name, value, NULL);
 3866: 		ret = 0;
 3867: 	    } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
 3868: 		xmlErrValidNode(ctxt, (xmlNodePtr) doc,
 3869: 				XML_DTD_ENTITY_TYPE,
 3870:    "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
 3871: 		       name, value, NULL);
 3872: 		ret = 0;
 3873: 	    }
 3874: 	    break;
 3875:         }
 3876: 	case XML_ATTRIBUTE_ENTITIES: {
 3877: 	    xmlChar *dup, *nam = NULL, *cur, save;
 3878: 	    xmlEntityPtr ent;
 3879: 
 3880: 	    dup = xmlStrdup(value);
 3881: 	    if (dup == NULL)
 3882: 		return(0);
 3883: 	    cur = dup;
 3884: 	    while (*cur != 0) {
 3885: 		nam = cur;
 3886: 		while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
 3887: 		save = *cur;
 3888: 		*cur = 0;
 3889: 		ent = xmlGetDocEntity(doc, nam);
 3890: 		if (ent == NULL) {
 3891: 		    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
 3892: 				    XML_DTD_UNKNOWN_ENTITY,
 3893:        "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
 3894: 			   name, nam, NULL);
 3895: 		    ret = 0;
 3896: 		} else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
 3897: 		    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
 3898: 				    XML_DTD_ENTITY_TYPE,
 3899:        "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
 3900: 			   name, nam, NULL);
 3901: 		    ret = 0;
 3902: 		}
 3903: 		if (save == 0)
 3904: 		    break;
 3905: 		*cur = save;
 3906: 		while (IS_BLANK_CH(*cur)) cur++;
 3907: 	    }
 3908: 	    xmlFree(dup);
 3909: 	    break;
 3910: 	}
 3911: 	case XML_ATTRIBUTE_NOTATION: {
 3912: 	    xmlNotationPtr nota;
 3913: 
 3914: 	    nota = xmlGetDtdNotationDesc(doc->intSubset, value);
 3915: 	    if ((nota == NULL) && (doc->extSubset != NULL))
 3916: 		nota = xmlGetDtdNotationDesc(doc->extSubset, value);
 3917: 
 3918: 	    if (nota == NULL) {
 3919: 		xmlErrValidNode(ctxt, (xmlNodePtr) doc,
 3920: 		                XML_DTD_UNKNOWN_NOTATION,
 3921:        "NOTATION attribute %s reference an unknown notation \"%s\"\n",
 3922: 		       name, value, NULL);
 3923: 		ret = 0;
 3924: 	    }
 3925: 	    break;
 3926:         }
 3927:     }
 3928:     return(ret);
 3929: }
 3930: 
 3931: /**
 3932:  * xmlValidCtxtNormalizeAttributeValue:
 3933:  * @ctxt: the validation context
 3934:  * @doc:  the document
 3935:  * @elem:  the parent
 3936:  * @name:  the attribute name
 3937:  * @value:  the attribute value
 3938:  * @ctxt:  the validation context or NULL
 3939:  *
 3940:  * Does the validation related extra step of the normalization of attribute
 3941:  * values:
 3942:  *
 3943:  * If the declared value is not CDATA, then the XML processor must further
 3944:  * process the normalized attribute value by discarding any leading and
 3945:  * trailing space (#x20) characters, and by replacing sequences of space
 3946:  * (#x20) characters by single space (#x20) character.
 3947:  *
 3948:  * Also  check VC: Standalone Document Declaration in P32, and update
 3949:  *  ctxt->valid accordingly
 3950:  *
 3951:  * returns a new normalized string if normalization is needed, NULL otherwise
 3952:  *      the caller must free the returned value.
 3953:  */
 3954: 
 3955: xmlChar *
 3956: xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 3957: 	     xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
 3958:     xmlChar *ret, *dst;
 3959:     const xmlChar *src;
 3960:     xmlAttributePtr attrDecl = NULL;
 3961:     int extsubset = 0;
 3962: 
 3963:     if (doc == NULL) return(NULL);
 3964:     if (elem == NULL) return(NULL);
 3965:     if (name == NULL) return(NULL);
 3966:     if (value == NULL) return(NULL);
 3967: 
 3968:     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
 3969: 	xmlChar fn[50];
 3970: 	xmlChar *fullname;
 3971: 
 3972: 	fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
 3973: 	if (fullname == NULL)
 3974: 	    return(NULL);
 3975: 	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
 3976: 	if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
 3977: 	    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
 3978: 	    if (attrDecl != NULL)
 3979: 		extsubset = 1;
 3980: 	}
 3981: 	if ((fullname != fn) && (fullname != elem->name))
 3982: 	    xmlFree(fullname);
 3983:     }
 3984:     if ((attrDecl == NULL) && (doc->intSubset != NULL))
 3985: 	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
 3986:     if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
 3987: 	attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
 3988: 	if (attrDecl != NULL)
 3989: 	    extsubset = 1;
 3990:     }
 3991: 
 3992:     if (attrDecl == NULL)
 3993: 	return(NULL);
 3994:     if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
 3995: 	return(NULL);
 3996: 
 3997:     ret = xmlStrdup(value);
 3998:     if (ret == NULL)
 3999: 	return(NULL);
 4000:     src = value;
 4001:     dst = ret;
 4002:     while (*src == 0x20) src++;
 4003:     while (*src != 0) {
 4004: 	if (*src == 0x20) {
 4005: 	    while (*src == 0x20) src++;
 4006: 	    if (*src != 0)
 4007: 		*dst++ = 0x20;
 4008: 	} else {
 4009: 	    *dst++ = *src++;
 4010: 	}
 4011:     }
 4012:     *dst = 0;
 4013:     if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
 4014: 	xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
 4015: "standalone: %s on %s value had to be normalized based on external subset declaration\n",
 4016: 	       name, elem->name, NULL);
 4017: 	ctxt->valid = 0;
 4018:     }
 4019:     return(ret);
 4020: }
 4021: 
 4022: /**
 4023:  * xmlValidNormalizeAttributeValue:
 4024:  * @doc:  the document
 4025:  * @elem:  the parent
 4026:  * @name:  the attribute name
 4027:  * @value:  the attribute value
 4028:  *
 4029:  * Does the validation related extra step of the normalization of attribute
 4030:  * values:
 4031:  *
 4032:  * If the declared value is not CDATA, then the XML processor must further
 4033:  * process the normalized attribute value by discarding any leading and
 4034:  * trailing space (#x20) characters, and by replacing sequences of space
 4035:  * (#x20) characters by single space (#x20) character.
 4036:  *
 4037:  * Returns a new normalized string if normalization is needed, NULL otherwise
 4038:  *      the caller must free the returned value.
 4039:  */
 4040: 
 4041: xmlChar *
 4042: xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
 4043: 			        const xmlChar *name, const xmlChar *value) {
 4044:     xmlChar *ret, *dst;
 4045:     const xmlChar *src;
 4046:     xmlAttributePtr attrDecl = NULL;
 4047: 
 4048:     if (doc == NULL) return(NULL);
 4049:     if (elem == NULL) return(NULL);
 4050:     if (name == NULL) return(NULL);
 4051:     if (value == NULL) return(NULL);
 4052: 
 4053:     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
 4054: 	xmlChar fn[50];
 4055: 	xmlChar *fullname;
 4056: 
 4057: 	fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
 4058: 	if (fullname == NULL)
 4059: 	    return(NULL);
 4060: 	if ((fullname != fn) && (fullname != elem->name))
 4061: 	    xmlFree(fullname);
 4062:     }
 4063:     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
 4064:     if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4065: 	attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
 4066: 
 4067:     if (attrDecl == NULL)
 4068: 	return(NULL);
 4069:     if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
 4070: 	return(NULL);
 4071: 
 4072:     ret = xmlStrdup(value);
 4073:     if (ret == NULL)
 4074: 	return(NULL);
 4075:     src = value;
 4076:     dst = ret;
 4077:     while (*src == 0x20) src++;
 4078:     while (*src != 0) {
 4079: 	if (*src == 0x20) {
 4080: 	    while (*src == 0x20) src++;
 4081: 	    if (*src != 0)
 4082: 		*dst++ = 0x20;
 4083: 	} else {
 4084: 	    *dst++ = *src++;
 4085: 	}
 4086:     }
 4087:     *dst = 0;
 4088:     return(ret);
 4089: }
 4090: 
 4091: static void
 4092: xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
 4093: 	                       const xmlChar* name ATTRIBUTE_UNUSED) {
 4094:     if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
 4095: }
 4096: 
 4097: /**
 4098:  * xmlValidateAttributeDecl:
 4099:  * @ctxt:  the validation context
 4100:  * @doc:  a document instance
 4101:  * @attr:  an attribute definition
 4102:  *
 4103:  * Try to validate a single attribute definition
 4104:  * basically it does the following checks as described by the
 4105:  * XML-1.0 recommendation:
 4106:  *  - [ VC: Attribute Default Legal ]
 4107:  *  - [ VC: Enumeration ]
 4108:  *  - [ VC: ID Attribute Default ]
 4109:  *
 4110:  * The ID/IDREF uniqueness and matching are done separately
 4111:  *
 4112:  * returns 1 if valid or 0 otherwise
 4113:  */
 4114: 
 4115: int
 4116: xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 4117:                          xmlAttributePtr attr) {
 4118:     int ret = 1;
 4119:     int val;
 4120:     CHECK_DTD;
 4121:     if(attr == NULL) return(1);
 4122: 
 4123:     /* Attribute Default Legal */
 4124:     /* Enumeration */
 4125:     if (attr->defaultValue != NULL) {
 4126: 	val = xmlValidateAttributeValueInternal(doc, attr->atype,
 4127: 	                                        attr->defaultValue);
 4128: 	if (val == 0) {
 4129: 	    xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
 4130: 	       "Syntax of default value for attribute %s of %s is not valid\n",
 4131: 	           attr->name, attr->elem, NULL);
 4132: 	}
 4133:         ret &= val;
 4134:     }
 4135: 
 4136:     /* ID Attribute Default */
 4137:     if ((attr->atype == XML_ATTRIBUTE_ID)&&
 4138:         (attr->def != XML_ATTRIBUTE_IMPLIED) &&
 4139: 	(attr->def != XML_ATTRIBUTE_REQUIRED)) {
 4140: 	xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
 4141:           "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
 4142: 	       attr->name, attr->elem, NULL);
 4143: 	ret = 0;
 4144:     }
 4145: 
 4146:     /* One ID per Element Type */
 4147:     if (attr->atype == XML_ATTRIBUTE_ID) {
 4148:         int nbId;
 4149: 
 4150: 	/* the trick is that we parse DtD as their own internal subset */
 4151:         xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
 4152: 	                                          attr->elem);
 4153: 	if (elem != NULL) {
 4154: 	    nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
 4155: 	} else {
 4156: 	    xmlAttributeTablePtr table;
 4157: 
 4158: 	    /*
 4159: 	     * The attribute may be declared in the internal subset and the
 4160: 	     * element in the external subset.
 4161: 	     */
 4162: 	    nbId = 0;
 4163: 	    if (doc->intSubset != NULL) {
 4164: 		table = (xmlAttributeTablePtr) doc->intSubset->attributes;
 4165: 		xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
 4166: 			     xmlValidateAttributeIdCallback, &nbId);
 4167: 	    }
 4168: 	}
 4169: 	if (nbId > 1) {
 4170: 
 4171: 	    xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
 4172:        "Element %s has %d ID attribute defined in the internal subset : %s\n",
 4173: 		   attr->elem, nbId, attr->name);
 4174: 	} else if (doc->extSubset != NULL) {
 4175: 	    int extId = 0;
 4176: 	    elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
 4177: 	    if (elem != NULL) {
 4178: 		extId = xmlScanIDAttributeDecl(NULL, elem, 0);
 4179: 	    }
 4180: 	    if (extId > 1) {
 4181: 		xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
 4182:        "Element %s has %d ID attribute defined in the external subset : %s\n",
 4183: 		       attr->elem, extId, attr->name);
 4184: 	    } else if (extId + nbId > 1) {
 4185: 		xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
 4186: "Element %s has ID attributes defined in the internal and external subset : %s\n",
 4187: 		       attr->elem, attr->name, NULL);
 4188: 	    }
 4189: 	}
 4190:     }
 4191: 
 4192:     /* Validity Constraint: Enumeration */
 4193:     if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
 4194:         xmlEnumerationPtr tree = attr->tree;
 4195: 	while (tree != NULL) {
 4196: 	    if (xmlStrEqual(tree->name, attr->defaultValue)) break;
 4197: 	    tree = tree->next;
 4198: 	}
 4199: 	if (tree == NULL) {
 4200: 	    xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
 4201: "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
 4202: 		   attr->defaultValue, attr->name, attr->elem);
 4203: 	    ret = 0;
 4204: 	}
 4205:     }
 4206: 
 4207:     return(ret);
 4208: }
 4209: 
 4210: /**
 4211:  * xmlValidateElementDecl:
 4212:  * @ctxt:  the validation context
 4213:  * @doc:  a document instance
 4214:  * @elem:  an element definition
 4215:  *
 4216:  * Try to validate a single element definition
 4217:  * basically it does the following checks as described by the
 4218:  * XML-1.0 recommendation:
 4219:  *  - [ VC: One ID per Element Type ]
 4220:  *  - [ VC: No Duplicate Types ]
 4221:  *  - [ VC: Unique Element Type Declaration ]
 4222:  *
 4223:  * returns 1 if valid or 0 otherwise
 4224:  */
 4225: 
 4226: int
 4227: xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 4228:                        xmlElementPtr elem) {
 4229:     int ret = 1;
 4230:     xmlElementPtr tst;
 4231: 
 4232:     CHECK_DTD;
 4233: 
 4234:     if (elem == NULL) return(1);
 4235: 
 4236: #if 0
 4237: #ifdef LIBXML_REGEXP_ENABLED
 4238:     /* Build the regexp associated to the content model */
 4239:     ret = xmlValidBuildContentModel(ctxt, elem);
 4240: #endif
 4241: #endif
 4242: 
 4243:     /* No Duplicate Types */
 4244:     if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
 4245: 	xmlElementContentPtr cur, next;
 4246:         const xmlChar *name;
 4247: 
 4248: 	cur = elem->content;
 4249: 	while (cur != NULL) {
 4250: 	    if (cur->type != XML_ELEMENT_CONTENT_OR) break;
 4251: 	    if (cur->c1 == NULL) break;
 4252: 	    if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
 4253: 		name = cur->c1->name;
 4254: 		next = cur->c2;
 4255: 		while (next != NULL) {
 4256: 		    if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
 4257: 		        if ((xmlStrEqual(next->name, name)) &&
 4258: 			    (xmlStrEqual(next->prefix, cur->c1->prefix))) {
 4259: 			    if (cur->c1->prefix == NULL) {
 4260: 				xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
 4261: 		   "Definition of %s has duplicate references of %s\n",
 4262: 				       elem->name, name, NULL);
 4263: 			    } else {
 4264: 				xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
 4265: 		   "Definition of %s has duplicate references of %s:%s\n",
 4266: 				       elem->name, cur->c1->prefix, name);
 4267: 			    }
 4268: 			    ret = 0;
 4269: 			}
 4270: 			break;
 4271: 		    }
 4272: 		    if (next->c1 == NULL) break;
 4273: 		    if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
 4274: 		    if ((xmlStrEqual(next->c1->name, name)) &&
 4275: 		        (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
 4276: 			if (cur->c1->prefix == NULL) {
 4277: 			    xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
 4278: 	       "Definition of %s has duplicate references to %s\n",
 4279: 				   elem->name, name, NULL);
 4280: 			} else {
 4281: 			    xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
 4282: 	       "Definition of %s has duplicate references to %s:%s\n",
 4283: 				   elem->name, cur->c1->prefix, name);
 4284: 			}
 4285: 			ret = 0;
 4286: 		    }
 4287: 		    next = next->c2;
 4288: 		}
 4289: 	    }
 4290: 	    cur = cur->c2;
 4291: 	}
 4292:     }
 4293: 
 4294:     /* VC: Unique Element Type Declaration */
 4295:     tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
 4296:     if ((tst != NULL ) && (tst != elem) &&
 4297: 	((tst->prefix == elem->prefix) ||
 4298: 	 (xmlStrEqual(tst->prefix, elem->prefix))) &&
 4299: 	(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
 4300: 	xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
 4301: 	                "Redefinition of element %s\n",
 4302: 		       elem->name, NULL, NULL);
 4303: 	ret = 0;
 4304:     }
 4305:     tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
 4306:     if ((tst != NULL ) && (tst != elem) &&
 4307: 	((tst->prefix == elem->prefix) ||
 4308: 	 (xmlStrEqual(tst->prefix, elem->prefix))) &&
 4309: 	(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
 4310: 	xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
 4311: 	                "Redefinition of element %s\n",
 4312: 		       elem->name, NULL, NULL);
 4313: 	ret = 0;
 4314:     }
 4315:     /* One ID per Element Type
 4316:      * already done when registering the attribute
 4317:     if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
 4318: 	ret = 0;
 4319:     } */
 4320:     return(ret);
 4321: }
 4322: 
 4323: /**
 4324:  * xmlValidateOneAttribute:
 4325:  * @ctxt:  the validation context
 4326:  * @doc:  a document instance
 4327:  * @elem:  an element instance
 4328:  * @attr:  an attribute instance
 4329:  * @value:  the attribute value (without entities processing)
 4330:  *
 4331:  * Try to validate a single attribute for an element
 4332:  * basically it does the following checks as described by the
 4333:  * XML-1.0 recommendation:
 4334:  *  - [ VC: Attribute Value Type ]
 4335:  *  - [ VC: Fixed Attribute Default ]
 4336:  *  - [ VC: Entity Name ]
 4337:  *  - [ VC: Name Token ]
 4338:  *  - [ VC: ID ]
 4339:  *  - [ VC: IDREF ]
 4340:  *  - [ VC: Entity Name ]
 4341:  *  - [ VC: Notation Attributes ]
 4342:  *
 4343:  * The ID/IDREF uniqueness and matching are done separately
 4344:  *
 4345:  * returns 1 if valid or 0 otherwise
 4346:  */
 4347: 
 4348: int
 4349: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 4350:                         xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
 4351: {
 4352:     xmlAttributePtr attrDecl =  NULL;
 4353:     int val;
 4354:     int ret = 1;
 4355: 
 4356:     CHECK_DTD;
 4357:     if ((elem == NULL) || (elem->name == NULL)) return(0);
 4358:     if ((attr == NULL) || (attr->name == NULL)) return(0);
 4359: 
 4360:     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
 4361: 	xmlChar fn[50];
 4362: 	xmlChar *fullname;
 4363: 
 4364: 	fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
 4365: 	if (fullname == NULL)
 4366: 	    return(0);
 4367: 	if (attr->ns != NULL) {
 4368: 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
 4369: 		                          attr->name, attr->ns->prefix);
 4370: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4371: 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
 4372: 					      attr->name, attr->ns->prefix);
 4373: 	} else {
 4374: 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
 4375: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4376: 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
 4377: 					     fullname, attr->name);
 4378: 	}
 4379: 	if ((fullname != fn) && (fullname != elem->name))
 4380: 	    xmlFree(fullname);
 4381:     }
 4382:     if (attrDecl == NULL) {
 4383: 	if (attr->ns != NULL) {
 4384: 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
 4385: 		                          attr->name, attr->ns->prefix);
 4386: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4387: 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
 4388: 					      attr->name, attr->ns->prefix);
 4389: 	} else {
 4390: 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
 4391: 		                         elem->name, attr->name);
 4392: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4393: 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
 4394: 					     elem->name, attr->name);
 4395: 	}
 4396:     }
 4397: 
 4398: 
 4399:     /* Validity Constraint: Attribute Value Type */
 4400:     if (attrDecl == NULL) {
 4401: 	xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
 4402: 	       "No declaration for attribute %s of element %s\n",
 4403: 	       attr->name, elem->name, NULL);
 4404: 	return(0);
 4405:     }
 4406:     attr->atype = attrDecl->atype;
 4407: 
 4408:     val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
 4409:     if (val == 0) {
 4410: 	    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
 4411: 	   "Syntax of value for attribute %s of %s is not valid\n",
 4412: 	       attr->name, elem->name, NULL);
 4413:         ret = 0;
 4414:     }
 4415: 
 4416:     /* Validity constraint: Fixed Attribute Default */
 4417:     if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
 4418: 	if (!xmlStrEqual(value, attrDecl->defaultValue)) {
 4419: 	    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
 4420: 	   "Value for attribute %s of %s is different from default \"%s\"\n",
 4421: 		   attr->name, elem->name, attrDecl->defaultValue);
 4422: 	    ret = 0;
 4423: 	}
 4424:     }
 4425: 
 4426:     /* Validity Constraint: ID uniqueness */
 4427:     if (attrDecl->atype == XML_ATTRIBUTE_ID) {
 4428:         if (xmlAddID(ctxt, doc, value, attr) == NULL)
 4429: 	    ret = 0;
 4430:     }
 4431: 
 4432:     if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
 4433: 	(attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
 4434:         if (xmlAddRef(ctxt, doc, value, attr) == NULL)
 4435: 	    ret = 0;
 4436:     }
 4437: 
 4438:     /* Validity Constraint: Notation Attributes */
 4439:     if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
 4440:         xmlEnumerationPtr tree = attrDecl->tree;
 4441:         xmlNotationPtr nota;
 4442: 
 4443:         /* First check that the given NOTATION was declared */
 4444: 	nota = xmlGetDtdNotationDesc(doc->intSubset, value);
 4445: 	if (nota == NULL)
 4446: 	    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
 4447: 
 4448: 	if (nota == NULL) {
 4449: 	    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
 4450:        "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
 4451: 		   value, attr->name, elem->name);
 4452: 	    ret = 0;
 4453:         }
 4454: 
 4455: 	/* Second, verify that it's among the list */
 4456: 	while (tree != NULL) {
 4457: 	    if (xmlStrEqual(tree->name, value)) break;
 4458: 	    tree = tree->next;
 4459: 	}
 4460: 	if (tree == NULL) {
 4461: 	    xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
 4462: "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
 4463: 		   value, attr->name, elem->name);
 4464: 	    ret = 0;
 4465: 	}
 4466:     }
 4467: 
 4468:     /* Validity Constraint: Enumeration */
 4469:     if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
 4470:         xmlEnumerationPtr tree = attrDecl->tree;
 4471: 	while (tree != NULL) {
 4472: 	    if (xmlStrEqual(tree->name, value)) break;
 4473: 	    tree = tree->next;
 4474: 	}
 4475: 	if (tree == NULL) {
 4476: 	    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
 4477:        "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
 4478: 		   value, attr->name, elem->name);
 4479: 	    ret = 0;
 4480: 	}
 4481:     }
 4482: 
 4483:     /* Fixed Attribute Default */
 4484:     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
 4485:         (!xmlStrEqual(attrDecl->defaultValue, value))) {
 4486: 	xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
 4487: 	   "Value for attribute %s of %s must be \"%s\"\n",
 4488: 	       attr->name, elem->name, attrDecl->defaultValue);
 4489:         ret = 0;
 4490:     }
 4491: 
 4492:     /* Extra check for the attribute value */
 4493:     ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
 4494: 				      attrDecl->atype, value);
 4495: 
 4496:     return(ret);
 4497: }
 4498: 
 4499: /**
 4500:  * xmlValidateOneNamespace:
 4501:  * @ctxt:  the validation context
 4502:  * @doc:  a document instance
 4503:  * @elem:  an element instance
 4504:  * @prefix:  the namespace prefix
 4505:  * @ns:  an namespace declaration instance
 4506:  * @value:  the attribute value (without entities processing)
 4507:  *
 4508:  * Try to validate a single namespace declaration for an element
 4509:  * basically it does the following checks as described by the
 4510:  * XML-1.0 recommendation:
 4511:  *  - [ VC: Attribute Value Type ]
 4512:  *  - [ VC: Fixed Attribute Default ]
 4513:  *  - [ VC: Entity Name ]
 4514:  *  - [ VC: Name Token ]
 4515:  *  - [ VC: ID ]
 4516:  *  - [ VC: IDREF ]
 4517:  *  - [ VC: Entity Name ]
 4518:  *  - [ VC: Notation Attributes ]
 4519:  *
 4520:  * The ID/IDREF uniqueness and matching are done separately
 4521:  *
 4522:  * returns 1 if valid or 0 otherwise
 4523:  */
 4524: 
 4525: int
 4526: xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 4527: xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
 4528:     /* xmlElementPtr elemDecl; */
 4529:     xmlAttributePtr attrDecl =  NULL;
 4530:     int val;
 4531:     int ret = 1;
 4532: 
 4533:     CHECK_DTD;
 4534:     if ((elem == NULL) || (elem->name == NULL)) return(0);
 4535:     if ((ns == NULL) || (ns->href == NULL)) return(0);
 4536: 
 4537:     if (prefix != NULL) {
 4538: 	xmlChar fn[50];
 4539: 	xmlChar *fullname;
 4540: 
 4541: 	fullname = xmlBuildQName(elem->name, prefix, fn, 50);
 4542: 	if (fullname == NULL) {
 4543: 	    xmlVErrMemory(ctxt, "Validating namespace");
 4544: 	    return(0);
 4545: 	}
 4546: 	if (ns->prefix != NULL) {
 4547: 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
 4548: 		                          ns->prefix, BAD_CAST "xmlns");
 4549: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4550: 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
 4551: 					  ns->prefix, BAD_CAST "xmlns");
 4552: 	} else {
 4553: 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
 4554: 		                         BAD_CAST "xmlns");
 4555: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4556: 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
 4557: 			                 BAD_CAST "xmlns");
 4558: 	}
 4559: 	if ((fullname != fn) && (fullname != elem->name))
 4560: 	    xmlFree(fullname);
 4561:     }
 4562:     if (attrDecl == NULL) {
 4563: 	if (ns->prefix != NULL) {
 4564: 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
 4565: 		                          ns->prefix, BAD_CAST "xmlns");
 4566: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4567: 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
 4568: 					      ns->prefix, BAD_CAST "xmlns");
 4569: 	} else {
 4570: 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
 4571: 		                         elem->name, BAD_CAST "xmlns");
 4572: 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
 4573: 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
 4574: 					     elem->name, BAD_CAST "xmlns");
 4575: 	}
 4576:     }
 4577: 
 4578: 
 4579:     /* Validity Constraint: Attribute Value Type */
 4580:     if (attrDecl == NULL) {
 4581: 	if (ns->prefix != NULL) {
 4582: 	    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
 4583: 		   "No declaration for attribute xmlns:%s of element %s\n",
 4584: 		   ns->prefix, elem->name, NULL);
 4585: 	} else {
 4586: 	    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
 4587: 		   "No declaration for attribute xmlns of element %s\n",
 4588: 		   elem->name, NULL, NULL);
 4589: 	}
 4590: 	return(0);
 4591:     }
 4592: 
 4593:     val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
 4594:     if (val == 0) {
 4595: 	if (ns->prefix != NULL) {
 4596: 	    xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
 4597: 	       "Syntax of value for attribute xmlns:%s of %s is not valid\n",
 4598: 		   ns->prefix, elem->name, NULL);
 4599: 	} else {
 4600: 	    xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
 4601: 	       "Syntax of value for attribute xmlns of %s is not valid\n",
 4602: 		   elem->name, NULL, NULL);
 4603: 	}
 4604:         ret = 0;
 4605:     }
 4606: 
 4607:     /* Validity constraint: Fixed Attribute Default */
 4608:     if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
 4609: 	if (!xmlStrEqual(value, attrDecl->defaultValue)) {
 4610: 	    if (ns->prefix != NULL) {
 4611: 		xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
 4612:        "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
 4613: 		       ns->prefix, elem->name, attrDecl->defaultValue);
 4614: 	    } else {
 4615: 		xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
 4616:        "Value for attribute xmlns of %s is different from default \"%s\"\n",
 4617: 		       elem->name, attrDecl->defaultValue, NULL);
 4618: 	    }
 4619: 	    ret = 0;
 4620: 	}
 4621:     }
 4622: 
 4623:     /* Validity Constraint: ID uniqueness */
 4624:     if (attrDecl->atype == XML_ATTRIBUTE_ID) {
 4625:         if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
 4626: 	    ret = 0;
 4627:     }
 4628: 
 4629:     if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
 4630: 	(attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
 4631:         if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
 4632: 	    ret = 0;
 4633:     }
 4634: 
 4635:     /* Validity Constraint: Notation Attributes */
 4636:     if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
 4637:         xmlEnumerationPtr tree = attrDecl->tree;
 4638:         xmlNotationPtr nota;
 4639: 
 4640:         /* First check that the given NOTATION was declared */
 4641: 	nota = xmlGetDtdNotationDesc(doc->intSubset, value);
 4642: 	if (nota == NULL)
 4643: 	    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
 4644: 
 4645: 	if (nota == NULL) {
 4646: 	    if (ns->prefix != NULL) {
 4647: 		xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
 4648:        "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
 4649: 		       value, ns->prefix, elem->name);
 4650: 	    } else {
 4651: 		xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
 4652:        "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
 4653: 		       value, elem->name, NULL);
 4654: 	    }
 4655: 	    ret = 0;
 4656:         }
 4657: 
 4658: 	/* Second, verify that it's among the list */
 4659: 	while (tree != NULL) {
 4660: 	    if (xmlStrEqual(tree->name, value)) break;
 4661: 	    tree = tree->next;
 4662: 	}
 4663: 	if (tree == NULL) {
 4664: 	    if (ns->prefix != NULL) {
 4665: 		xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
 4666: "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
 4667: 		       value, ns->prefix, elem->name);
 4668: 	    } else {
 4669: 		xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
 4670: "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
 4671: 		       value, elem->name, NULL);
 4672: 	    }
 4673: 	    ret = 0;
 4674: 	}
 4675:     }
 4676: 
 4677:     /* Validity Constraint: Enumeration */
 4678:     if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
 4679:         xmlEnumerationPtr tree = attrDecl->tree;
 4680: 	while (tree != NULL) {
 4681: 	    if (xmlStrEqual(tree->name, value)) break;
 4682: 	    tree = tree->next;
 4683: 	}
 4684: 	if (tree == NULL) {
 4685: 	    if (ns->prefix != NULL) {
 4686: 		xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
 4687: "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
 4688: 		       value, ns->prefix, elem->name);
 4689: 	    } else {
 4690: 		xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
 4691: "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
 4692: 		       value, elem->name, NULL);
 4693: 	    }
 4694: 	    ret = 0;
 4695: 	}
 4696:     }
 4697: 
 4698:     /* Fixed Attribute Default */
 4699:     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
 4700:         (!xmlStrEqual(attrDecl->defaultValue, value))) {
 4701: 	if (ns->prefix != NULL) {
 4702: 	    xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
 4703: 		   "Value for attribute xmlns:%s of %s must be \"%s\"\n",
 4704: 		   ns->prefix, elem->name, attrDecl->defaultValue);
 4705: 	} else {
 4706: 	    xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
 4707: 		   "Value for attribute xmlns of %s must be \"%s\"\n",
 4708: 		   elem->name, attrDecl->defaultValue, NULL);
 4709: 	}
 4710:         ret = 0;
 4711:     }
 4712: 
 4713:     /* Extra check for the attribute value */
 4714:     if (ns->prefix != NULL) {
 4715: 	ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
 4716: 					  attrDecl->atype, value);
 4717:     } else {
 4718: 	ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
 4719: 					  attrDecl->atype, value);
 4720:     }
 4721: 
 4722:     return(ret);
 4723: }
 4724: 
 4725: #ifndef  LIBXML_REGEXP_ENABLED
 4726: /**
 4727:  * xmlValidateSkipIgnorable:
 4728:  * @ctxt:  the validation context
 4729:  * @child:  the child list
 4730:  *
 4731:  * Skip ignorable elements w.r.t. the validation process
 4732:  *
 4733:  * returns the first element to consider for validation of the content model
 4734:  */
 4735: 
 4736: static xmlNodePtr
 4737: xmlValidateSkipIgnorable(xmlNodePtr child) {
 4738:     while (child != NULL) {
 4739: 	switch (child->type) {
 4740: 	    /* These things are ignored (skipped) during validation.  */
 4741: 	    case XML_PI_NODE:
 4742: 	    case XML_COMMENT_NODE:
 4743: 	    case XML_XINCLUDE_START:
 4744: 	    case XML_XINCLUDE_END:
 4745: 		child = child->next;
 4746: 		break;
 4747: 	    case XML_TEXT_NODE:
 4748: 		if (xmlIsBlankNode(child))
 4749: 		    child = child->next;
 4750: 		else
 4751: 		    return(child);
 4752: 		break;
 4753: 	    /* keep current node */
 4754: 	    default:
 4755: 		return(child);
 4756: 	}
 4757:     }
 4758:     return(child);
 4759: }
 4760: 
 4761: /**
 4762:  * xmlValidateElementType:
 4763:  * @ctxt:  the validation context
 4764:  *
 4765:  * Try to validate the content model of an element internal function
 4766:  *
 4767:  * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
 4768:  *           reference is found and -3 if the validation succeeded but
 4769:  *           the content model is not determinist.
 4770:  */
 4771: 
 4772: static int
 4773: xmlValidateElementType(xmlValidCtxtPtr ctxt) {
 4774:     int ret = -1;
 4775:     int determinist = 1;
 4776: 
 4777:     NODE = xmlValidateSkipIgnorable(NODE);
 4778:     if ((NODE == NULL) && (CONT == NULL))
 4779: 	return(1);
 4780:     if ((NODE == NULL) &&
 4781: 	((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
 4782: 	 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
 4783: 	return(1);
 4784:     }
 4785:     if (CONT == NULL) return(-1);
 4786:     if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
 4787: 	return(-2);
 4788: 
 4789:     /*
 4790:      * We arrive here when more states need to be examined
 4791:      */
 4792: cont:
 4793: 
 4794:     /*
 4795:      * We just recovered from a rollback generated by a possible
 4796:      * epsilon transition, go directly to the analysis phase
 4797:      */
 4798:     if (STATE == ROLLBACK_PARENT) {
 4799: 	DEBUG_VALID_MSG("restored parent branch");
 4800: 	DEBUG_VALID_STATE(NODE, CONT)
 4801: 	ret = 1;
 4802: 	goto analyze;
 4803:     }
 4804: 
 4805:     DEBUG_VALID_STATE(NODE, CONT)
 4806:     /*
 4807:      * we may have to save a backup state here. This is the equivalent
 4808:      * of handling epsilon transition in NFAs.
 4809:      */
 4810:     if ((CONT != NULL) &&
 4811: 	((CONT->parent == NULL) ||
 4812: 	 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
 4813: 	((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
 4814: 	 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
 4815: 	 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
 4816: 	DEBUG_VALID_MSG("saving parent branch");
 4817: 	if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
 4818: 	    return(0);
 4819:     }
 4820: 
 4821: 
 4822:     /*
 4823:      * Check first if the content matches
 4824:      */
 4825:     switch (CONT->type) {
 4826: 	case XML_ELEMENT_CONTENT_PCDATA:
 4827: 	    if (NODE == NULL) {
 4828: 		DEBUG_VALID_MSG("pcdata failed no node");
 4829: 		ret = 0;
 4830: 		break;
 4831: 	    }
 4832: 	    if (NODE->type == XML_TEXT_NODE) {
 4833: 		DEBUG_VALID_MSG("pcdata found, skip to next");
 4834: 		/*
 4835: 		 * go to next element in the content model
 4836: 		 * skipping ignorable elems
 4837: 		 */
 4838: 		do {
 4839: 		    NODE = NODE->next;
 4840: 		    NODE = xmlValidateSkipIgnorable(NODE);
 4841: 		    if ((NODE != NULL) &&
 4842: 			(NODE->type == XML_ENTITY_REF_NODE))
 4843: 			return(-2);
 4844: 		} while ((NODE != NULL) &&
 4845: 			 ((NODE->type != XML_ELEMENT_NODE) &&
 4846: 			  (NODE->type != XML_TEXT_NODE) &&
 4847: 			  (NODE->type != XML_CDATA_SECTION_NODE)));
 4848:                 ret = 1;
 4849: 		break;
 4850: 	    } else {
 4851: 		DEBUG_VALID_MSG("pcdata failed");
 4852: 		ret = 0;
 4853: 		break;
 4854: 	    }
 4855: 	    break;
 4856: 	case XML_ELEMENT_CONTENT_ELEMENT:
 4857: 	    if (NODE == NULL) {
 4858: 		DEBUG_VALID_MSG("element failed no node");
 4859: 		ret = 0;
 4860: 		break;
 4861: 	    }
 4862: 	    ret = ((NODE->type == XML_ELEMENT_NODE) &&
 4863: 		   (xmlStrEqual(NODE->name, CONT->name)));
 4864: 	    if (ret == 1) {
 4865: 		if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
 4866: 		    ret = (CONT->prefix == NULL);
 4867: 		} else if (CONT->prefix == NULL) {
 4868: 		    ret = 0;
 4869: 		} else {
 4870: 		    ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
 4871: 		}
 4872: 	    }
 4873: 	    if (ret == 1) {
 4874: 		DEBUG_VALID_MSG("element found, skip to next");
 4875: 		/*
 4876: 		 * go to next element in the content model
 4877: 		 * skipping ignorable elems
 4878: 		 */
 4879: 		do {
 4880: 		    NODE = NODE->next;
 4881: 		    NODE = xmlValidateSkipIgnorable(NODE);
 4882: 		    if ((NODE != NULL) &&
 4883: 			(NODE->type == XML_ENTITY_REF_NODE))
 4884: 			return(-2);
 4885: 		} while ((NODE != NULL) &&
 4886: 			 ((NODE->type != XML_ELEMENT_NODE) &&
 4887: 			  (NODE->type != XML_TEXT_NODE) &&
 4888: 			  (NODE->type != XML_CDATA_SECTION_NODE)));
 4889: 	    } else {
 4890: 		DEBUG_VALID_MSG("element failed");
 4891: 		ret = 0;
 4892: 		break;
 4893: 	    }
 4894: 	    break;
 4895: 	case XML_ELEMENT_CONTENT_OR:
 4896: 	    /*
 4897: 	     * Small optimization.
 4898: 	     */
 4899: 	    if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
 4900: 		if ((NODE == NULL) ||
 4901: 		    (!xmlStrEqual(NODE->name, CONT->c1->name))) {
 4902: 		    DEPTH++;
 4903: 		    CONT = CONT->c2;
 4904: 		    goto cont;
 4905: 		}
 4906: 		if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
 4907: 		    ret = (CONT->c1->prefix == NULL);
 4908: 		} else if (CONT->c1->prefix == NULL) {
 4909: 		    ret = 0;
 4910: 		} else {
 4911: 		    ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
 4912: 		}
 4913: 		if (ret == 0) {
 4914: 		    DEPTH++;
 4915: 		    CONT = CONT->c2;
 4916: 		    goto cont;
 4917: 		}
 4918: 	    }
 4919: 
 4920: 	    /*
 4921: 	     * save the second branch 'or' branch
 4922: 	     */
 4923: 	    DEBUG_VALID_MSG("saving 'or' branch");
 4924: 	    if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
 4925: 			    OCCURS, ROLLBACK_OR) < 0)
 4926: 		return(-1);
 4927: 	    DEPTH++;
 4928: 	    CONT = CONT->c1;
 4929: 	    goto cont;
 4930: 	case XML_ELEMENT_CONTENT_SEQ:
 4931: 	    /*
 4932: 	     * Small optimization.
 4933: 	     */
 4934: 	    if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
 4935: 		((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
 4936: 		 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
 4937: 		if ((NODE == NULL) ||
 4938: 		    (!xmlStrEqual(NODE->name, CONT->c1->name))) {
 4939: 		    DEPTH++;
 4940: 		    CONT = CONT->c2;
 4941: 		    goto cont;
 4942: 		}
 4943: 		if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
 4944: 		    ret = (CONT->c1->prefix == NULL);
 4945: 		} else if (CONT->c1->prefix == NULL) {
 4946: 		    ret = 0;
 4947: 		} else {
 4948: 		    ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
 4949: 		}
 4950: 		if (ret == 0) {
 4951: 		    DEPTH++;
 4952: 		    CONT = CONT->c2;
 4953: 		    goto cont;
 4954: 		}
 4955: 	    }
 4956: 	    DEPTH++;
 4957: 	    CONT = CONT->c1;
 4958: 	    goto cont;
 4959:     }
 4960: 
 4961:     /*
 4962:      * At this point handle going up in the tree
 4963:      */
 4964:     if (ret == -1) {
 4965: 	DEBUG_VALID_MSG("error found returning");
 4966: 	return(ret);
 4967:     }
 4968: analyze:
 4969:     while (CONT != NULL) {
 4970: 	/*
 4971: 	 * First do the analysis depending on the occurrence model at
 4972: 	 * this level.
 4973: 	 */
 4974: 	if (ret == 0) {
 4975: 	    switch (CONT->ocur) {
 4976: 		xmlNodePtr cur;
 4977: 
 4978: 		case XML_ELEMENT_CONTENT_ONCE:
 4979: 		    cur = ctxt->vstate->node;
 4980: 		    DEBUG_VALID_MSG("Once branch failed, rollback");
 4981: 		    if (vstateVPop(ctxt) < 0 ) {
 4982: 			DEBUG_VALID_MSG("exhaustion, failed");
 4983: 			return(0);
 4984: 		    }
 4985: 		    if (cur != ctxt->vstate->node)
 4986: 			determinist = -3;
 4987: 		    goto cont;
 4988: 		case XML_ELEMENT_CONTENT_PLUS:
 4989: 		    if (OCCURRENCE == 0) {
 4990: 			cur = ctxt->vstate->node;
 4991: 			DEBUG_VALID_MSG("Plus branch failed, rollback");
 4992: 			if (vstateVPop(ctxt) < 0 ) {
 4993: 			    DEBUG_VALID_MSG("exhaustion, failed");
 4994: 			    return(0);
 4995: 			}
 4996: 			if (cur != ctxt->vstate->node)
 4997: 			    determinist = -3;
 4998: 			goto cont;
 4999: 		    }
 5000: 		    DEBUG_VALID_MSG("Plus branch found");
 5001: 		    ret = 1;
 5002: 		    break;
 5003: 		case XML_ELEMENT_CONTENT_MULT:
 5004: #ifdef DEBUG_VALID_ALGO
 5005: 		    if (OCCURRENCE == 0) {
 5006: 			DEBUG_VALID_MSG("Mult branch failed");
 5007: 		    } else {
 5008: 			DEBUG_VALID_MSG("Mult branch found");
 5009: 		    }
 5010: #endif
 5011: 		    ret = 1;
 5012: 		    break;
 5013: 		case XML_ELEMENT_CONTENT_OPT:
 5014: 		    DEBUG_VALID_MSG("Option branch failed");
 5015: 		    ret = 1;
 5016: 		    break;
 5017: 	    }
 5018: 	} else {
 5019: 	    switch (CONT->ocur) {
 5020: 		case XML_ELEMENT_CONTENT_OPT:
 5021: 		    DEBUG_VALID_MSG("Option branch succeeded");
 5022: 		    ret = 1;
 5023: 		    break;
 5024: 		case XML_ELEMENT_CONTENT_ONCE:
 5025: 		    DEBUG_VALID_MSG("Once branch succeeded");
 5026: 		    ret = 1;
 5027: 		    break;
 5028: 		case XML_ELEMENT_CONTENT_PLUS:
 5029: 		    if (STATE == ROLLBACK_PARENT) {
 5030: 			DEBUG_VALID_MSG("Plus branch rollback");
 5031: 			ret = 1;
 5032: 			break;
 5033: 		    }
 5034: 		    if (NODE == NULL) {
 5035: 			DEBUG_VALID_MSG("Plus branch exhausted");
 5036: 			ret = 1;
 5037: 			break;
 5038: 		    }
 5039: 		    DEBUG_VALID_MSG("Plus branch succeeded, continuing");
 5040: 		    SET_OCCURRENCE;
 5041: 		    goto cont;
 5042: 		case XML_ELEMENT_CONTENT_MULT:
 5043: 		    if (STATE == ROLLBACK_PARENT) {
 5044: 			DEBUG_VALID_MSG("Mult branch rollback");
 5045: 			ret = 1;
 5046: 			break;
 5047: 		    }
 5048: 		    if (NODE == NULL) {
 5049: 			DEBUG_VALID_MSG("Mult branch exhausted");
 5050: 			ret = 1;
 5051: 			break;
 5052: 		    }
 5053: 		    DEBUG_VALID_MSG("Mult branch succeeded, continuing");
 5054: 		    /* SET_OCCURRENCE; */
 5055: 		    goto cont;
 5056: 	    }
 5057: 	}
 5058: 	STATE = 0;
 5059: 
 5060: 	/*
 5061: 	 * Then act accordingly at the parent level
 5062: 	 */
 5063: 	RESET_OCCURRENCE;
 5064: 	if (CONT->parent == NULL)
 5065: 	    break;
 5066: 
 5067: 	switch (CONT->parent->type) {
 5068: 	    case XML_ELEMENT_CONTENT_PCDATA:
 5069: 		DEBUG_VALID_MSG("Error: parent pcdata");
 5070: 		return(-1);
 5071: 	    case XML_ELEMENT_CONTENT_ELEMENT:
 5072: 		DEBUG_VALID_MSG("Error: parent element");
 5073: 		return(-1);
 5074: 	    case XML_ELEMENT_CONTENT_OR:
 5075: 		if (ret == 1) {
 5076: 		    DEBUG_VALID_MSG("Or succeeded");
 5077: 		    CONT = CONT->parent;
 5078: 		    DEPTH--;
 5079: 		} else {
 5080: 		    DEBUG_VALID_MSG("Or failed");
 5081: 		    CONT = CONT->parent;
 5082: 		    DEPTH--;
 5083: 		}
 5084: 		break;
 5085: 	    case XML_ELEMENT_CONTENT_SEQ:
 5086: 		if (ret == 0) {
 5087: 		    DEBUG_VALID_MSG("Sequence failed");
 5088: 		    CONT = CONT->parent;
 5089: 		    DEPTH--;
 5090: 		} else if (CONT == CONT->parent->c1) {
 5091: 		    DEBUG_VALID_MSG("Sequence testing 2nd branch");
 5092: 		    CONT = CONT->parent->c2;
 5093: 		    goto cont;
 5094: 		} else {
 5095: 		    DEBUG_VALID_MSG("Sequence succeeded");
 5096: 		    CONT = CONT->parent;
 5097: 		    DEPTH--;
 5098: 		}
 5099: 	}
 5100:     }
 5101:     if (NODE != NULL) {
 5102: 	xmlNodePtr cur;
 5103: 
 5104: 	cur = ctxt->vstate->node;
 5105: 	DEBUG_VALID_MSG("Failed, remaining input, rollback");
 5106: 	if (vstateVPop(ctxt) < 0 ) {
 5107: 	    DEBUG_VALID_MSG("exhaustion, failed");
 5108: 	    return(0);
 5109: 	}
 5110: 	if (cur != ctxt->vstate->node)
 5111: 	    determinist = -3;
 5112: 	goto cont;
 5113:     }
 5114:     if (ret == 0) {
 5115: 	xmlNodePtr cur;
 5116: 
 5117: 	cur = ctxt->vstate->node;
 5118: 	DEBUG_VALID_MSG("Failure, rollback");
 5119: 	if (vstateVPop(ctxt) < 0 ) {
 5120: 	    DEBUG_VALID_MSG("exhaustion, failed");
 5121: 	    return(0);
 5122: 	}
 5123: 	if (cur != ctxt->vstate->node)
 5124: 	    determinist = -3;
 5125: 	goto cont;
 5126:     }
 5127:     return(determinist);
 5128: }
 5129: #endif
 5130: 
 5131: /**
 5132:  * xmlSnprintfElements:
 5133:  * @buf:  an output buffer
 5134:  * @size:  the size of the buffer
 5135:  * @content:  An element
 5136:  * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
 5137:  *
 5138:  * This will dump the list of elements to the buffer
 5139:  * Intended just for the debug routine
 5140:  */
 5141: static void
 5142: xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
 5143:     xmlNodePtr cur;
 5144:     int len;
 5145: 
 5146:     if (node == NULL) return;
 5147:     if (glob) strcat(buf, "(");
 5148:     cur = node;
 5149:     while (cur != NULL) {
 5150: 	len = strlen(buf);
 5151: 	if (size - len < 50) {
 5152: 	    if ((size - len > 4) && (buf[len - 1] != '.'))
 5153: 		strcat(buf, " ...");
 5154: 	    return;
 5155: 	}
 5156:         switch (cur->type) {
 5157:             case XML_ELEMENT_NODE:
 5158: 		if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
 5159: 		    if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
 5160: 			if ((size - len > 4) && (buf[len - 1] != '.'))
 5161: 			    strcat(buf, " ...");
 5162: 			return;
 5163: 		    }
 5164: 		    strcat(buf, (char *) cur->ns->prefix);
 5165: 		    strcat(buf, ":");
 5166: 		}
 5167:                 if (size - len < xmlStrlen(cur->name) + 10) {
 5168: 		    if ((size - len > 4) && (buf[len - 1] != '.'))
 5169: 			strcat(buf, " ...");
 5170: 		    return;
 5171: 		}
 5172: 	        strcat(buf, (char *) cur->name);
 5173: 		if (cur->next != NULL)
 5174: 		    strcat(buf, " ");
 5175: 		break;
 5176:             case XML_TEXT_NODE:
 5177: 		if (xmlIsBlankNode(cur))
 5178: 		    break;
 5179:             case XML_CDATA_SECTION_NODE:
 5180:             case XML_ENTITY_REF_NODE:
 5181: 	        strcat(buf, "CDATA");
 5182: 		if (cur->next != NULL)
 5183: 		    strcat(buf, " ");
 5184: 		break;
 5185:             case XML_ATTRIBUTE_NODE:
 5186:             case XML_DOCUMENT_NODE:
 5187: #ifdef LIBXML_DOCB_ENABLED
 5188: 	    case XML_DOCB_DOCUMENT_NODE:
 5189: #endif
 5190: 	    case XML_HTML_DOCUMENT_NODE:
 5191:             case XML_DOCUMENT_TYPE_NODE:
 5192:             case XML_DOCUMENT_FRAG_NODE:
 5193:             case XML_NOTATION_NODE:
 5194: 	    case XML_NAMESPACE_DECL:
 5195: 	        strcat(buf, "???");
 5196: 		if (cur->next != NULL)
 5197: 		    strcat(buf, " ");
 5198: 		break;
 5199:             case XML_ENTITY_NODE:
 5200:             case XML_PI_NODE:
 5201:             case XML_DTD_NODE:
 5202:             case XML_COMMENT_NODE:
 5203: 	    case XML_ELEMENT_DECL:
 5204: 	    case XML_ATTRIBUTE_DECL:
 5205: 	    case XML_ENTITY_DECL:
 5206: 	    case XML_XINCLUDE_START:
 5207: 	    case XML_XINCLUDE_END:
 5208: 		break;
 5209: 	}
 5210: 	cur = cur->next;
 5211:     }
 5212:     if (glob) strcat(buf, ")");
 5213: }
 5214: 
 5215: /**
 5216:  * xmlValidateElementContent:
 5217:  * @ctxt:  the validation context
 5218:  * @child:  the child list
 5219:  * @elemDecl:  pointer to the element declaration
 5220:  * @warn:  emit the error message
 5221:  * @parent: the parent element (for error reporting)
 5222:  *
 5223:  * Try to validate the content model of an element
 5224:  *
 5225:  * returns 1 if valid or 0 if not and -1 in case of error
 5226:  */
 5227: 
 5228: static int
 5229: xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
 5230:        xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
 5231:     int ret = 1;
 5232: #ifndef  LIBXML_REGEXP_ENABLED
 5233:     xmlNodePtr repl = NULL, last = NULL, tmp;
 5234: #endif
 5235:     xmlNodePtr cur;
 5236:     xmlElementContentPtr cont;
 5237:     const xmlChar *name;
 5238: 
 5239:     if ((elemDecl == NULL) || (parent == NULL))
 5240: 	return(-1);
 5241:     cont = elemDecl->content;
 5242:     name = elemDecl->name;
 5243: 
 5244: #ifdef LIBXML_REGEXP_ENABLED
 5245:     /* Build the regexp associated to the content model */
 5246:     if (elemDecl->contModel == NULL)
 5247: 	ret = xmlValidBuildContentModel(ctxt, elemDecl);
 5248:     if (elemDecl->contModel == NULL) {
 5249: 	return(-1);
 5250:     } else {
 5251: 	xmlRegExecCtxtPtr exec;
 5252: 
 5253: 	if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
 5254: 	    return(-1);
 5255: 	}
 5256: 	ctxt->nodeMax = 0;
 5257: 	ctxt->nodeNr = 0;
 5258: 	ctxt->nodeTab = NULL;
 5259: 	exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
 5260: 	if (exec != NULL) {
 5261: 	    cur = child;
 5262: 	    while (cur != NULL) {
 5263: 		switch (cur->type) {
 5264: 		    case XML_ENTITY_REF_NODE:
 5265: 			/*
 5266: 			 * Push the current node to be able to roll back
 5267: 			 * and process within the entity
 5268: 			 */
 5269: 			if ((cur->children != NULL) &&
 5270: 			    (cur->children->children != NULL)) {
 5271: 			    nodeVPush(ctxt, cur);
 5272: 			    cur = cur->children->children;
 5273: 			    continue;
 5274: 			}
 5275: 			break;
 5276: 		    case XML_TEXT_NODE:
 5277: 			if (xmlIsBlankNode(cur))
 5278: 			    break;
 5279: 			ret = 0;
 5280: 			goto fail;
 5281: 		    case XML_CDATA_SECTION_NODE:
 5282: 			/* TODO */
 5283: 			ret = 0;
 5284: 			goto fail;
 5285: 		    case XML_ELEMENT_NODE:
 5286: 			if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
 5287: 			    xmlChar fn[50];
 5288: 			    xmlChar *fullname;
 5289: 
 5290: 			    fullname = xmlBuildQName(cur->name,
 5291: 				                     cur->ns->prefix, fn, 50);
 5292: 			    if (fullname == NULL) {
 5293: 				ret = -1;
 5294: 				goto fail;
 5295: 			    }
 5296:                             ret = xmlRegExecPushString(exec, fullname, NULL);
 5297: 			    if ((fullname != fn) && (fullname != cur->name))
 5298: 				xmlFree(fullname);
 5299: 			} else {
 5300: 			    ret = xmlRegExecPushString(exec, cur->name, NULL);
 5301: 			}
 5302: 			break;
 5303: 		    default:
 5304: 			break;
 5305: 		}
 5306: 		/*
 5307: 		 * Switch to next element
 5308: 		 */
 5309: 		cur = cur->next;
 5310: 		while (cur == NULL) {
 5311: 		    cur = nodeVPop(ctxt);
 5312: 		    if (cur == NULL)
 5313: 			break;
 5314: 		    cur = cur->next;
 5315: 		}
 5316: 	    }
 5317: 	    ret = xmlRegExecPushString(exec, NULL, NULL);
 5318: fail:
 5319: 	    xmlRegFreeExecCtxt(exec);
 5320: 	}
 5321:     }
 5322: #else  /* LIBXML_REGEXP_ENABLED */
 5323:     /*
 5324:      * Allocate the stack
 5325:      */
 5326:     ctxt->vstateMax = 8;
 5327:     ctxt->vstateTab = (xmlValidState *) xmlMalloc(
 5328: 		 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
 5329:     if (ctxt->vstateTab == NULL) {
 5330: 	xmlVErrMemory(ctxt, "malloc failed");
 5331: 	return(-1);
 5332:     }
 5333:     /*
 5334:      * The first entry in the stack is reserved to the current state
 5335:      */
 5336:     ctxt->nodeMax = 0;
 5337:     ctxt->nodeNr = 0;
 5338:     ctxt->nodeTab = NULL;
 5339:     ctxt->vstate = &ctxt->vstateTab[0];
 5340:     ctxt->vstateNr = 1;
 5341:     CONT = cont;
 5342:     NODE = child;
 5343:     DEPTH = 0;
 5344:     OCCURS = 0;
 5345:     STATE = 0;
 5346:     ret = xmlValidateElementType(ctxt);
 5347:     if ((ret == -3) && (warn)) {
 5348: 	xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
 5349: 	       "Content model for Element %s is ambiguous\n",
 5350: 	                   name, NULL, NULL);
 5351:     } else if (ret == -2) {
 5352: 	/*
 5353: 	 * An entities reference appeared at this level.
 5354: 	 * Buid a minimal representation of this node content
 5355: 	 * sufficient to run the validation process on it
 5356: 	 */
 5357: 	DEBUG_VALID_MSG("Found an entity reference, linearizing");
 5358: 	cur = child;
 5359: 	while (cur != NULL) {
 5360: 	    switch (cur->type) {
 5361: 		case XML_ENTITY_REF_NODE:
 5362: 		    /*
 5363: 		     * Push the current node to be able to roll back
 5364: 		     * and process within the entity
 5365: 		     */
 5366: 		    if ((cur->children != NULL) &&
 5367: 			(cur->children->children != NULL)) {
 5368: 			nodeVPush(ctxt, cur);
 5369: 			cur = cur->children->children;
 5370: 			continue;
 5371: 		    }
 5372: 		    break;
 5373: 		case XML_TEXT_NODE:
 5374: 		    if (xmlIsBlankNode(cur))
 5375: 			break;
 5376: 		    /* no break on purpose */
 5377: 		case XML_CDATA_SECTION_NODE:
 5378: 		    /* no break on purpose */
 5379: 		case XML_ELEMENT_NODE:
 5380: 		    /*
 5381: 		     * Allocate a new node and minimally fills in
 5382: 		     * what's required
 5383: 		     */
 5384: 		    tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
 5385: 		    if (tmp == NULL) {
 5386: 			xmlVErrMemory(ctxt, "malloc failed");
 5387: 			xmlFreeNodeList(repl);
 5388: 			ret = -1;
 5389: 			goto done;
 5390: 		    }
 5391: 		    tmp->type = cur->type;
 5392: 		    tmp->name = cur->name;
 5393: 		    tmp->ns = cur->ns;
 5394: 		    tmp->next = NULL;
 5395: 		    tmp->content = NULL;
 5396: 		    if (repl == NULL)
 5397: 			repl = last = tmp;
 5398: 		    else {
 5399: 			last->next = tmp;
 5400: 			last = tmp;
 5401: 		    }
 5402: 		    if (cur->type == XML_CDATA_SECTION_NODE) {
 5403: 			/*
 5404: 			 * E59 spaces in CDATA does not match the
 5405: 			 * nonterminal S
 5406: 			 */
 5407: 			tmp->content = xmlStrdup(BAD_CAST "CDATA");
 5408: 		    }
 5409: 		    break;
 5410: 		default:
 5411: 		    break;
 5412: 	    }
 5413: 	    /*
 5414: 	     * Switch to next element
 5415: 	     */
 5416: 	    cur = cur->next;
 5417: 	    while (cur == NULL) {
 5418: 		cur = nodeVPop(ctxt);
 5419: 		if (cur == NULL)
 5420: 		    break;
 5421: 		cur = cur->next;
 5422: 	    }
 5423: 	}
 5424: 
 5425: 	/*
 5426: 	 * Relaunch the validation
 5427: 	 */
 5428: 	ctxt->vstate = &ctxt->vstateTab[0];
 5429: 	ctxt->vstateNr = 1;
 5430: 	CONT = cont;
 5431: 	NODE = repl;
 5432: 	DEPTH = 0;
 5433: 	OCCURS = 0;
 5434: 	STATE = 0;
 5435: 	ret = xmlValidateElementType(ctxt);
 5436:     }
 5437: #endif /* LIBXML_REGEXP_ENABLED */
 5438:     if ((warn) && ((ret != 1) && (ret != -3))) {
 5439: 	if (ctxt != NULL) {
 5440: 	    char expr[5000];
 5441: 	    char list[5000];
 5442: 
 5443: 	    expr[0] = 0;
 5444: 	    xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
 5445: 	    list[0] = 0;
 5446: #ifndef LIBXML_REGEXP_ENABLED
 5447: 	    if (repl != NULL)
 5448: 		xmlSnprintfElements(&list[0], 5000, repl, 1);
 5449: 	    else
 5450: #endif /* LIBXML_REGEXP_ENABLED */
 5451: 		xmlSnprintfElements(&list[0], 5000, child, 1);
 5452: 
 5453: 	    if (name != NULL) {
 5454: 		xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
 5455: 	   "Element %s content does not follow the DTD, expecting %s, got %s\n",
 5456: 		       name, BAD_CAST expr, BAD_CAST list);
 5457: 	    } else {
 5458: 		xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
 5459: 	   "Element content does not follow the DTD, expecting %s, got %s\n",
 5460: 		       BAD_CAST expr, BAD_CAST list, NULL);
 5461: 	    }
 5462: 	} else {
 5463: 	    if (name != NULL) {
 5464: 		xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
 5465: 		       "Element %s content does not follow the DTD\n",
 5466: 		       name, NULL, NULL);
 5467: 	    } else {
 5468: 		xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
 5469: 		       "Element content does not follow the DTD\n",
 5470: 		                NULL, NULL, NULL);
 5471: 	    }
 5472: 	}
 5473: 	ret = 0;
 5474:     }
 5475:     if (ret == -3)
 5476: 	ret = 1;
 5477: 
 5478: #ifndef  LIBXML_REGEXP_ENABLED
 5479: done:
 5480:     /*
 5481:      * Deallocate the copy if done, and free up the validation stack
 5482:      */
 5483:     while (repl != NULL) {
 5484: 	tmp = repl->next;
 5485: 	xmlFree(repl);
 5486: 	repl = tmp;
 5487:     }
 5488:     ctxt->vstateMax = 0;
 5489:     if (ctxt->vstateTab != NULL) {
 5490: 	xmlFree(ctxt->vstateTab);
 5491: 	ctxt->vstateTab = NULL;
 5492:     }
 5493: #endif
 5494:     ctxt->nodeMax = 0;
 5495:     ctxt->nodeNr = 0;
 5496:     if (ctxt->nodeTab != NULL) {
 5497: 	xmlFree(ctxt->nodeTab);
 5498: 	ctxt->nodeTab = NULL;
 5499:     }
 5500:     return(ret);
 5501: 
 5502: }
 5503: 
 5504: /**
 5505:  * xmlValidateCdataElement:
 5506:  * @ctxt:  the validation context
 5507:  * @doc:  a document instance
 5508:  * @elem:  an element instance
 5509:  *
 5510:  * Check that an element follows #CDATA
 5511:  *
 5512:  * returns 1 if valid or 0 otherwise
 5513:  */
 5514: static int
 5515: xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 5516:                            xmlNodePtr elem) {
 5517:     int ret = 1;
 5518:     xmlNodePtr cur, child;
 5519: 
 5520:     if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
 5521:         (elem->type != XML_ELEMENT_NODE))
 5522: 	return(0);
 5523: 
 5524:     child = elem->children;
 5525: 
 5526:     cur = child;
 5527:     while (cur != NULL) {
 5528: 	switch (cur->type) {
 5529: 	    case XML_ENTITY_REF_NODE:
 5530: 		/*
 5531: 		 * Push the current node to be able to roll back
 5532: 		 * and process within the entity
 5533: 		 */
 5534: 		if ((cur->children != NULL) &&
 5535: 		    (cur->children->children != NULL)) {
 5536: 		    nodeVPush(ctxt, cur);
 5537: 		    cur = cur->children->children;
 5538: 		    continue;
 5539: 		}
 5540: 		break;
 5541: 	    case XML_COMMENT_NODE:
 5542: 	    case XML_PI_NODE:
 5543: 	    case XML_TEXT_NODE:
 5544: 	    case XML_CDATA_SECTION_NODE:
 5545: 		break;
 5546: 	    default:
 5547: 		ret = 0;
 5548: 		goto done;
 5549: 	}
 5550: 	/*
 5551: 	 * Switch to next element
 5552: 	 */
 5553: 	cur = cur->next;
 5554: 	while (cur == NULL) {
 5555: 	    cur = nodeVPop(ctxt);
 5556: 	    if (cur == NULL)
 5557: 		break;
 5558: 	    cur = cur->next;
 5559: 	}
 5560:     }
 5561: done:
 5562:     ctxt->nodeMax = 0;
 5563:     ctxt->nodeNr = 0;
 5564:     if (ctxt->nodeTab != NULL) {
 5565: 	xmlFree(ctxt->nodeTab);
 5566: 	ctxt->nodeTab = NULL;
 5567:     }
 5568:     return(ret);
 5569: }
 5570: 
 5571: /**
 5572:  * xmlValidateCheckMixed:
 5573:  * @ctxt:  the validation context
 5574:  * @cont:  the mixed content model
 5575:  * @qname:  the qualified name as appearing in the serialization
 5576:  *
 5577:  * Check if the given node is part of the content model.
 5578:  *
 5579:  * Returns 1 if yes, 0 if no, -1 in case of error
 5580:  */
 5581: static int
 5582: xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
 5583: 	              xmlElementContentPtr cont, const xmlChar *qname) {
 5584:     const xmlChar *name;
 5585:     int plen;
 5586:     name = xmlSplitQName3(qname, &plen);
 5587: 
 5588:     if (name == NULL) {
 5589: 	while (cont != NULL) {
 5590: 	    if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
 5591: 		if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
 5592: 		    return(1);
 5593: 	    } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
 5594: 	       (cont->c1 != NULL) &&
 5595: 	       (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
 5596: 		if ((cont->c1->prefix == NULL) &&
 5597: 		    (xmlStrEqual(cont->c1->name, qname)))
 5598: 		    return(1);
 5599: 	    } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
 5600: 		(cont->c1 == NULL) ||
 5601: 		(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
 5602: 		xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
 5603: 			"Internal: MIXED struct corrupted\n",
 5604: 			NULL);
 5605: 		break;
 5606: 	    }
 5607: 	    cont = cont->c2;
 5608: 	}
 5609:     } else {
 5610: 	while (cont != NULL) {
 5611: 	    if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
 5612: 		if ((cont->prefix != NULL) &&
 5613: 		    (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
 5614: 		    (xmlStrEqual(cont->name, name)))
 5615: 		    return(1);
 5616: 	    } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
 5617: 	       (cont->c1 != NULL) &&
 5618: 	       (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
 5619: 		if ((cont->c1->prefix != NULL) &&
 5620: 		    (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
 5621: 		    (xmlStrEqual(cont->c1->name, name)))
 5622: 		    return(1);
 5623: 	    } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
 5624: 		(cont->c1 == NULL) ||
 5625: 		(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
 5626: 		xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
 5627: 			"Internal: MIXED struct corrupted\n",
 5628: 			NULL);
 5629: 		break;
 5630: 	    }
 5631: 	    cont = cont->c2;
 5632: 	}
 5633:     }
 5634:     return(0);
 5635: }
 5636: 
 5637: /**
 5638:  * xmlValidGetElemDecl:
 5639:  * @ctxt:  the validation context
 5640:  * @doc:  a document instance
 5641:  * @elem:  an element instance
 5642:  * @extsubset:  pointer, (out) indicate if the declaration was found
 5643:  *              in the external subset.
 5644:  *
 5645:  * Finds a declaration associated to an element in the document.
 5646:  *
 5647:  * returns the pointer to the declaration or NULL if not found.
 5648:  */
 5649: static xmlElementPtr
 5650: xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 5651: 	            xmlNodePtr elem, int *extsubset) {
 5652:     xmlElementPtr elemDecl = NULL;
 5653:     const xmlChar *prefix = NULL;
 5654: 
 5655:     if ((ctxt == NULL) || (doc == NULL) ||
 5656:         (elem == NULL) || (elem->name == NULL))
 5657:         return(NULL);
 5658:     if (extsubset != NULL)
 5659: 	*extsubset = 0;
 5660: 
 5661:     /*
 5662:      * Fetch the declaration for the qualified name
 5663:      */
 5664:     if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
 5665: 	prefix = elem->ns->prefix;
 5666: 
 5667:     if (prefix != NULL) {
 5668: 	elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
 5669: 		                         elem->name, prefix);
 5670: 	if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
 5671: 	    elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
 5672: 		                             elem->name, prefix);
 5673: 	    if ((elemDecl != NULL) && (extsubset != NULL))
 5674: 		*extsubset = 1;
 5675: 	}
 5676:     }
 5677: 
 5678:     /*
 5679:      * Fetch the declaration for the non qualified name
 5680:      * This is "non-strict" validation should be done on the
 5681:      * full QName but in that case being flexible makes sense.
 5682:      */
 5683:     if (elemDecl == NULL) {
 5684: 	elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
 5685: 	if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
 5686: 	    elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
 5687: 	    if ((elemDecl != NULL) && (extsubset != NULL))
 5688: 		*extsubset = 1;
 5689: 	}
 5690:     }
 5691:     if (elemDecl == NULL) {
 5692: 	xmlErrValidNode(ctxt, elem,
 5693: 			XML_DTD_UNKNOWN_ELEM,
 5694: 	       "No declaration for element %s\n",
 5695: 	       elem->name, NULL, NULL);
 5696:     }
 5697:     return(elemDecl);
 5698: }
 5699: 
 5700: #ifdef LIBXML_REGEXP_ENABLED
 5701: /**
 5702:  * xmlValidatePushElement:
 5703:  * @ctxt:  the validation context
 5704:  * @doc:  a document instance
 5705:  * @elem:  an element instance
 5706:  * @qname:  the qualified name as appearing in the serialization
 5707:  *
 5708:  * Push a new element start on the validation stack.
 5709:  *
 5710:  * returns 1 if no validation problem was found or 0 otherwise
 5711:  */
 5712: int
 5713: xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 5714:                        xmlNodePtr elem, const xmlChar *qname) {
 5715:     int ret = 1;
 5716:     xmlElementPtr eDecl;
 5717:     int extsubset = 0;
 5718: 
 5719:     if (ctxt == NULL)
 5720:         return(0);
 5721: /* printf("PushElem %s\n", qname); */
 5722:     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
 5723: 	xmlValidStatePtr state = ctxt->vstate;
 5724: 	xmlElementPtr elemDecl;
 5725: 
 5726: 	/*
 5727: 	 * Check the new element agaisnt the content model of the new elem.
 5728: 	 */
 5729: 	if (state->elemDecl != NULL) {
 5730: 	    elemDecl = state->elemDecl;
 5731: 
 5732: 	    switch(elemDecl->etype) {
 5733: 		case XML_ELEMENT_TYPE_UNDEFINED:
 5734: 		    ret = 0;
 5735: 		    break;
 5736: 		case XML_ELEMENT_TYPE_EMPTY:
 5737: 		    xmlErrValidNode(ctxt, state->node,
 5738: 				    XML_DTD_NOT_EMPTY,
 5739: 	       "Element %s was declared EMPTY this one has content\n",
 5740: 			   state->node->name, NULL, NULL);
 5741: 		    ret = 0;
 5742: 		    break;
 5743: 		case XML_ELEMENT_TYPE_ANY:
 5744: 		    /* I don't think anything is required then */
 5745: 		    break;
 5746: 		case XML_ELEMENT_TYPE_MIXED:
 5747: 		    /* simple case of declared as #PCDATA */
 5748: 		    if ((elemDecl->content != NULL) &&
 5749: 			(elemDecl->content->type ==
 5750: 			 XML_ELEMENT_CONTENT_PCDATA)) {
 5751: 			xmlErrValidNode(ctxt, state->node,
 5752: 					XML_DTD_NOT_PCDATA,
 5753: 	       "Element %s was declared #PCDATA but contains non text nodes\n",
 5754: 				state->node->name, NULL, NULL);
 5755: 			ret = 0;
 5756: 		    } else {
 5757: 			ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
 5758: 				                    qname);
 5759: 			if (ret != 1) {
 5760: 			    xmlErrValidNode(ctxt, state->node,
 5761: 					    XML_DTD_INVALID_CHILD,
 5762: 	       "Element %s is not declared in %s list of possible children\n",
 5763: 				    qname, state->node->name, NULL);
 5764: 			}
 5765: 		    }
 5766: 		    break;
 5767: 		case XML_ELEMENT_TYPE_ELEMENT:
 5768: 		    /*
 5769: 		     * TODO:
 5770: 		     * VC: Standalone Document Declaration
 5771: 		     *     - element types with element content, if white space
 5772: 		     *       occurs directly within any instance of those types.
 5773: 		     */
 5774: 		    if (state->exec != NULL) {
 5775: 			ret = xmlRegExecPushString(state->exec, qname, NULL);
 5776: 			if (ret < 0) {
 5777: 			    xmlErrValidNode(ctxt, state->node,
 5778: 					    XML_DTD_CONTENT_MODEL,
 5779: 	       "Element %s content does not follow the DTD, Misplaced %s\n",
 5780: 				   state->node->name, qname, NULL);
 5781: 			    ret = 0;
 5782: 			} else {
 5783: 			    ret = 1;
 5784: 			}
 5785: 		    }
 5786: 		    break;
 5787: 	    }
 5788: 	}
 5789:     }
 5790:     eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
 5791:     vstateVPush(ctxt, eDecl, elem);
 5792:     return(ret);
 5793: }
 5794: 
 5795: /**
 5796:  * xmlValidatePushCData:
 5797:  * @ctxt:  the validation context
 5798:  * @data:  some character data read
 5799:  * @len:  the length of the data
 5800:  *
 5801:  * check the CData parsed for validation in the current stack
 5802:  *
 5803:  * returns 1 if no validation problem was found or 0 otherwise
 5804:  */
 5805: int
 5806: xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
 5807:     int ret = 1;
 5808: 
 5809: /* printf("CDATA %s %d\n", data, len); */
 5810:     if (ctxt == NULL)
 5811:         return(0);
 5812:     if (len <= 0)
 5813: 	return(ret);
 5814:     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
 5815: 	xmlValidStatePtr state = ctxt->vstate;
 5816: 	xmlElementPtr elemDecl;
 5817: 
 5818: 	/*
 5819: 	 * Check the new element agaisnt the content model of the new elem.
 5820: 	 */
 5821: 	if (state->elemDecl != NULL) {
 5822: 	    elemDecl = state->elemDecl;
 5823: 
 5824: 	    switch(elemDecl->etype) {
 5825: 		case XML_ELEMENT_TYPE_UNDEFINED:
 5826: 		    ret = 0;
 5827: 		    break;
 5828: 		case XML_ELEMENT_TYPE_EMPTY:
 5829: 		    xmlErrValidNode(ctxt, state->node,
 5830: 				    XML_DTD_NOT_EMPTY,
 5831: 	       "Element %s was declared EMPTY this one has content\n",
 5832: 			   state->node->name, NULL, NULL);
 5833: 		    ret = 0;
 5834: 		    break;
 5835: 		case XML_ELEMENT_TYPE_ANY:
 5836: 		    break;
 5837: 		case XML_ELEMENT_TYPE_MIXED:
 5838: 		    break;
 5839: 		case XML_ELEMENT_TYPE_ELEMENT:
 5840: 		    if (len > 0) {
 5841: 			int i;
 5842: 
 5843: 			for (i = 0;i < len;i++) {
 5844: 			    if (!IS_BLANK_CH(data[i])) {
 5845: 				xmlErrValidNode(ctxt, state->node,
 5846: 						XML_DTD_CONTENT_MODEL,
 5847: 	   "Element %s content does not follow the DTD, Text not allowed\n",
 5848: 				       state->node->name, NULL, NULL);
 5849: 				ret = 0;
 5850: 				goto done;
 5851: 			    }
 5852: 			}
 5853: 			/*
 5854: 			 * TODO:
 5855: 			 * VC: Standalone Document Declaration
 5856: 			 *  element types with element content, if white space
 5857: 			 *  occurs directly within any instance of those types.
 5858: 			 */
 5859: 		    }
 5860: 		    break;
 5861: 	    }
 5862: 	}
 5863:     }
 5864: done:
 5865:     return(ret);
 5866: }
 5867: 
 5868: /**
 5869:  * xmlValidatePopElement:
 5870:  * @ctxt:  the validation context
 5871:  * @doc:  a document instance
 5872:  * @elem:  an element instance
 5873:  * @qname:  the qualified name as appearing in the serialization
 5874:  *
 5875:  * Pop the element end from the validation stack.
 5876:  *
 5877:  * returns 1 if no validation problem was found or 0 otherwise
 5878:  */
 5879: int
 5880: xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
 5881:                       xmlNodePtr elem ATTRIBUTE_UNUSED,
 5882: 		      const xmlChar *qname ATTRIBUTE_UNUSED) {
 5883:     int ret = 1;
 5884: 
 5885:     if (ctxt == NULL)
 5886:         return(0);
 5887: /* printf("PopElem %s\n", qname); */
 5888:     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
 5889: 	xmlValidStatePtr state = ctxt->vstate;
 5890: 	xmlElementPtr elemDecl;
 5891: 
 5892: 	/*
 5893: 	 * Check the new element agaisnt the content model of the new elem.
 5894: 	 */
 5895: 	if (state->elemDecl != NULL) {
 5896: 	    elemDecl = state->elemDecl;
 5897: 
 5898: 	    if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
 5899: 		if (state->exec != NULL) {
 5900: 		    ret = xmlRegExecPushString(state->exec, NULL, NULL);
 5901: 		    if (ret == 0) {
 5902: 			xmlErrValidNode(ctxt, state->node,
 5903: 			                XML_DTD_CONTENT_MODEL,
 5904: 	   "Element %s content does not follow the DTD, Expecting more child\n",
 5905: 			       state->node->name, NULL,NULL);
 5906: 		    } else {
 5907: 			/*
 5908: 			 * previous validation errors should not generate
 5909: 			 * a new one here
 5910: 			 */
 5911: 			ret = 1;
 5912: 		    }
 5913: 		}
 5914: 	    }
 5915: 	}
 5916: 	vstateVPop(ctxt);
 5917:     }
 5918:     return(ret);
 5919: }
 5920: #endif /* LIBXML_REGEXP_ENABLED */
 5921: 
 5922: /**
 5923:  * xmlValidateOneElement:
 5924:  * @ctxt:  the validation context
 5925:  * @doc:  a document instance
 5926:  * @elem:  an element instance
 5927:  *
 5928:  * Try to validate a single element and it's attributes,
 5929:  * basically it does the following checks as described by the
 5930:  * XML-1.0 recommendation:
 5931:  *  - [ VC: Element Valid ]
 5932:  *  - [ VC: Required Attribute ]
 5933:  * Then call xmlValidateOneAttribute() for each attribute present.
 5934:  *
 5935:  * The ID/IDREF checkings are done separately
 5936:  *
 5937:  * returns 1 if valid or 0 otherwise
 5938:  */
 5939: 
 5940: int
 5941: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
 5942:                       xmlNodePtr elem) {
 5943:     xmlElementPtr elemDecl = NULL;
 5944:     xmlElementContentPtr cont;
 5945:     xmlAttributePtr attr;
 5946:     xmlNodePtr child;
 5947:     int ret = 1, tmp;
 5948:     const xmlChar *name;
 5949:     int extsubset = 0;
 5950: 
 5951:     CHECK_DTD;
 5952: 
 5953:     if (elem == NULL) return(0);
 5954:     switch (elem->type) {
 5955:         case XML_ATTRIBUTE_NODE:
 5956: 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 5957: 		   "Attribute element not expected\n", NULL, NULL ,NULL);
 5958: 	    return(0);
 5959:         case XML_TEXT_NODE:
 5960: 	    if (elem->children != NULL) {
 5961: 		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 5962: 		                "Text element has children !\n",
 5963: 				NULL,NULL,NULL);
 5964: 		return(0);
 5965: 	    }
 5966: 	    if (elem->ns != NULL) {
 5967: 		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 5968: 		                "Text element has namespace !\n",
 5969: 				NULL,NULL,NULL);
 5970: 		return(0);
 5971: 	    }
 5972: 	    if (elem->content == NULL) {
 5973: 		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 5974: 		                "Text element has no content !\n",
 5975: 				NULL,NULL,NULL);
 5976: 		return(0);
 5977: 	    }
 5978: 	    return(1);
 5979:         case XML_XINCLUDE_START:
 5980:         case XML_XINCLUDE_END:
 5981:             return(1);
 5982:         case XML_CDATA_SECTION_NODE:
 5983:         case XML_ENTITY_REF_NODE:
 5984:         case XML_PI_NODE:
 5985:         case XML_COMMENT_NODE:
 5986: 	    return(1);
 5987:         case XML_ENTITY_NODE:
 5988: 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 5989: 		   "Entity element not expected\n", NULL, NULL ,NULL);
 5990: 	    return(0);
 5991:         case XML_NOTATION_NODE:
 5992: 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 5993: 		   "Notation element not expected\n", NULL, NULL ,NULL);
 5994: 	    return(0);
 5995:         case XML_DOCUMENT_NODE:
 5996:         case XML_DOCUMENT_TYPE_NODE:
 5997:         case XML_DOCUMENT_FRAG_NODE:
 5998: 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 5999: 		   "Document element not expected\n", NULL, NULL ,NULL);
 6000: 	    return(0);
 6001:         case XML_HTML_DOCUMENT_NODE:
 6002: 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 6003: 		   "HTML Document not expected\n", NULL, NULL ,NULL);
 6004: 	    return(0);
 6005:         case XML_ELEMENT_NODE:
 6006: 	    break;
 6007: 	default:
 6008: 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
 6009: 		   "unknown element type\n", NULL, NULL ,NULL);
 6010: 	    return(0);
 6011:     }
 6012: 
 6013:     /*
 6014:      * Fetch the declaration
 6015:      */
 6016:     elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
 6017:     if (elemDecl == NULL)
 6018: 	return(0);
 6019: 
 6020:     /*
 6021:      * If vstateNr is not zero that means continuous validation is
 6022:      * activated, do not try to check the content model at that level.
 6023:      */
 6024:     if (ctxt->vstateNr == 0) {
 6025:     /* Check that the element content matches the definition */
 6026:     switch (elemDecl->etype) {
 6027:         case XML_ELEMENT_TYPE_UNDEFINED:
 6028: 	    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
 6029: 	                    "No declaration for element %s\n",
 6030: 		   elem->name, NULL, NULL);
 6031: 	    return(0);
 6032:         case XML_ELEMENT_TYPE_EMPTY:
 6033: 	    if (elem->children != NULL) {
 6034: 		xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
 6035: 	       "Element %s was declared EMPTY this one has content\n",
 6036: 	               elem->name, NULL, NULL);
 6037: 		ret = 0;
 6038: 	    }
 6039: 	    break;
 6040:         case XML_ELEMENT_TYPE_ANY:
 6041: 	    /* I don't think anything is required then */
 6042: 	    break;
 6043:         case XML_ELEMENT_TYPE_MIXED:
 6044: 
 6045: 	    /* simple case of declared as #PCDATA */
 6046: 	    if ((elemDecl->content != NULL) &&
 6047: 		(elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
 6048: 		ret = xmlValidateOneCdataElement(ctxt, doc, elem);
 6049: 		if (!ret) {
 6050: 		    xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
 6051: 	       "Element %s was declared #PCDATA but contains non text nodes\n",
 6052: 			   elem->name, NULL, NULL);
 6053: 		}
 6054: 		break;
 6055: 	    }
 6056: 	    child = elem->children;
 6057: 	    /* Hum, this start to get messy */
 6058: 	    while (child != NULL) {
 6059: 	        if (child->type == XML_ELEMENT_NODE) {
 6060: 		    name = child->name;
 6061: 		    if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
 6062: 			xmlChar fn[50];
 6063: 			xmlChar *fullname;
 6064: 
 6065: 			fullname = xmlBuildQName(child->name, child->ns->prefix,
 6066: 				                 fn, 50);
 6067: 			if (fullname == NULL)
 6068: 			    return(0);
 6069: 			cont = elemDecl->content;
 6070: 			while (cont != NULL) {
 6071: 			    if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
 6072: 				if (xmlStrEqual(cont->name, fullname))
 6073: 				    break;
 6074: 			    } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
 6075: 			       (cont->c1 != NULL) &&
 6076: 			       (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
 6077: 				if (xmlStrEqual(cont->c1->name, fullname))
 6078: 				    break;
 6079: 			    } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
 6080: 				(cont->c1 == NULL) ||
 6081: 				(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
 6082: 				xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
 6083: 					"Internal: MIXED struct corrupted\n",
 6084: 					NULL);
 6085: 				break;
 6086: 			    }
 6087: 			    cont = cont->c2;
 6088: 			}
 6089: 			if ((fullname != fn) && (fullname != child->name))
 6090: 			    xmlFree(fullname);
 6091: 			if (cont != NULL)
 6092: 			    goto child_ok;
 6093: 		    }
 6094: 		    cont = elemDecl->content;
 6095: 		    while (cont != NULL) {
 6096: 		        if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
 6097: 			    if (xmlStrEqual(cont->name, name)) break;
 6098: 			} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
 6099: 			   (cont->c1 != NULL) &&
 6100: 			   (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
 6101: 			    if (xmlStrEqual(cont->c1->name, name)) break;
 6102: 			} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
 6103: 			    (cont->c1 == NULL) ||
 6104: 			    (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
 6105: 			    xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
 6106: 				    "Internal: MIXED struct corrupted\n",
 6107: 				    NULL);
 6108: 			    break;
 6109: 			}
 6110: 			cont = cont->c2;
 6111: 		    }
 6112: 		    if (cont == NULL) {
 6113: 			xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
 6114: 	       "Element %s is not declared in %s list of possible children\n",
 6115: 			       name, elem->name, NULL);
 6116: 			ret = 0;
 6117: 		    }
 6118: 		}
 6119: child_ok:
 6120: 	        child = child->next;
 6121: 	    }
 6122: 	    break;
 6123:         case XML_ELEMENT_TYPE_ELEMENT:
 6124: 	    if ((doc->standalone == 1) && (extsubset == 1)) {
 6125: 		/*
 6126: 		 * VC: Standalone Document Declaration
 6127: 		 *     - element types with element content, if white space
 6128: 		 *       occurs directly within any instance of those types.
 6129: 		 */
 6130: 		child = elem->children;
 6131: 		while (child != NULL) {
 6132: 		    if (child->type == XML_TEXT_NODE) {
 6133: 			const xmlChar *content = child->content;
 6134: 
 6135: 			while (IS_BLANK_CH(*content))
 6136: 			    content++;
 6137: 			if (*content == 0) {
 6138: 			    xmlErrValidNode(ctxt, elem,
 6139: 			                    XML_DTD_STANDALONE_WHITE_SPACE,
 6140: "standalone: %s declared in the external subset contains white spaces nodes\n",
 6141: 				   elem->name, NULL, NULL);
 6142: 			    ret = 0;
 6143: 			    break;
 6144: 			}
 6145: 		    }
 6146: 		    child =child->next;
 6147: 		}
 6148: 	    }
 6149: 	    child = elem->children;
 6150: 	    cont = elemDecl->content;
 6151: 	    tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
 6152: 	    if (tmp <= 0)
 6153: 		ret = tmp;
 6154: 	    break;
 6155:     }
 6156:     } /* not continuous */
 6157: 
 6158:     /* [ VC: Required Attribute ] */
 6159:     attr = elemDecl->attributes;
 6160:     while (attr != NULL) {
 6161: 	if (attr->def == XML_ATTRIBUTE_REQUIRED) {
 6162: 	    int qualified = -1;
 6163: 
 6164: 	    if ((attr->prefix == NULL) &&
 6165: 		(xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
 6166: 		xmlNsPtr ns;
 6167: 
 6168: 		ns = elem->nsDef;
 6169: 		while (ns != NULL) {
 6170: 		    if (ns->prefix == NULL)
 6171: 			goto found;
 6172: 		    ns = ns->next;
 6173: 		}
 6174: 	    } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
 6175: 		xmlNsPtr ns;
 6176: 
 6177: 		ns = elem->nsDef;
 6178: 		while (ns != NULL) {
 6179: 		    if (xmlStrEqual(attr->name, ns->prefix))
 6180: 			goto found;
 6181: 		    ns = ns->next;
 6182: 		}
 6183: 	    } else {
 6184: 		xmlAttrPtr attrib;
 6185: 
 6186: 		attrib = elem->properties;
 6187: 		while (attrib != NULL) {
 6188: 		    if (xmlStrEqual(attrib->name, attr->name)) {
 6189: 			if (attr->prefix != NULL) {
 6190: 			    xmlNsPtr nameSpace = attrib->ns;
 6191: 
 6192: 			    if (nameSpace == NULL)
 6193: 				nameSpace = elem->ns;
 6194: 			    /*
 6195: 			     * qualified names handling is problematic, having a
 6196: 			     * different prefix should be possible but DTDs don't
 6197: 			     * allow to define the URI instead of the prefix :-(
 6198: 			     */
 6199: 			    if (nameSpace == NULL) {
 6200: 				if (qualified < 0)
 6201: 				    qualified = 0;
 6202: 			    } else if (!xmlStrEqual(nameSpace->prefix,
 6203: 						    attr->prefix)) {
 6204: 				if (qualified < 1)
 6205: 				    qualified = 1;
 6206: 			    } else
 6207: 				goto found;
 6208: 			} else {
 6209: 			    /*
 6210: 			     * We should allow applications to define namespaces
 6211: 			     * for their application even if the DTD doesn't
 6212: 			     * carry one, otherwise, basically we would always
 6213: 			     * break.
 6214: 			     */
 6215: 			    goto found;
 6216: 			}
 6217: 		    }
 6218: 		    attrib = attrib->next;
 6219: 		}
 6220: 	    }
 6221: 	    if (qualified == -1) {
 6222: 		if (attr->prefix == NULL) {
 6223: 		    xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
 6224: 		       "Element %s does not carry attribute %s\n",
 6225: 			   elem->name, attr->name, NULL);
 6226: 		    ret = 0;
 6227: 	        } else {
 6228: 		    xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
 6229: 		       "Element %s does not carry attribute %s:%s\n",
 6230: 			   elem->name, attr->prefix,attr->name);
 6231: 		    ret = 0;
 6232: 		}
 6233: 	    } else if (qualified == 0) {
 6234: 		xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
 6235: 		   "Element %s required attribute %s:%s has no prefix\n",
 6236: 		       elem->name, attr->prefix, attr->name);
 6237: 	    } else if (qualified == 1) {
 6238: 		xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
 6239: 		   "Element %s required attribute %s:%s has different prefix\n",
 6240: 		       elem->name, attr->prefix, attr->name);
 6241: 	    }
 6242: 	} else if (attr->def == XML_ATTRIBUTE_FIXED) {
 6243: 	    /*
 6244: 	     * Special tests checking #FIXED namespace declarations
 6245: 	     * have the right value since this is not done as an
 6246: 	     * attribute checking
 6247: 	     */
 6248: 	    if ((attr->prefix == NULL) &&
 6249: 		(xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
 6250: 		xmlNsPtr ns;
 6251: 
 6252: 		ns = elem->nsDef;
 6253: 		while (ns != NULL) {
 6254: 		    if (ns->prefix == NULL) {
 6255: 			if (!xmlStrEqual(attr->defaultValue, ns->href)) {
 6256: 			    xmlErrValidNode(ctxt, elem,
 6257: 			           XML_DTD_ELEM_DEFAULT_NAMESPACE,
 6258:    "Element %s namespace name for default namespace does not match the DTD\n",
 6259: 				   elem->name, NULL, NULL);
 6260: 			    ret = 0;
 6261: 			}
 6262: 			goto found;
 6263: 		    }
 6264: 		    ns = ns->next;
 6265: 		}
 6266: 	    } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
 6267: 		xmlNsPtr ns;
 6268: 
 6269: 		ns = elem->nsDef;
 6270: 		while (ns != NULL) {
 6271: 		    if (xmlStrEqual(attr->name, ns->prefix)) {
 6272: 			if (!xmlStrEqual(attr->defaultValue, ns->href)) {
 6273: 			    xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
 6274: 		   "Element %s namespace name for %s does not match the DTD\n",
 6275: 				   elem->name, ns->prefix, NULL);
 6276: 			    ret = 0;
 6277: 			}
 6278: 			goto found;
 6279: 		    }
 6280: 		    ns = ns->next;
 6281: 		}
 6282: 	    }
 6283: 	}
 6284: found:
 6285:         attr = attr->nexth;
 6286:     }
 6287:     return(ret);
 6288: }
 6289: 
 6290: /**
 6291:  * xmlValidateRoot:
 6292:  * @ctxt:  the validation context
 6293:  * @doc:  a document instance
 6294:  *
 6295:  * Try to validate a the root element
 6296:  * basically it does the following check as described by the
 6297:  * XML-1.0 recommendation:
 6298:  *  - [ VC: Root Element Type ]
 6299:  * it doesn't try to recurse or apply other check to the element
 6300:  *
 6301:  * returns 1 if valid or 0 otherwise
 6302:  */
 6303: 
 6304: int
 6305: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
 6306:     xmlNodePtr root;
 6307:     int ret;
 6308: 
 6309:     if (doc == NULL) return(0);
 6310: 
 6311:     root = xmlDocGetRootElement(doc);
 6312:     if ((root == NULL) || (root->name == NULL)) {
 6313: 	xmlErrValid(ctxt, XML_DTD_NO_ROOT,
 6314: 	            "no root element\n", NULL);
 6315:         return(0);
 6316:     }
 6317: 
 6318:     /*
 6319:      * When doing post validation against a separate DTD, those may
 6320:      * no internal subset has been generated
 6321:      */
 6322:     if ((doc->intSubset != NULL) &&
 6323: 	(doc->intSubset->name != NULL)) {
 6324: 	/*
 6325: 	 * Check first the document root against the NQName
 6326: 	 */
 6327: 	if (!xmlStrEqual(doc->intSubset->name, root->name)) {
 6328: 	    if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
 6329: 		xmlChar fn[50];
 6330: 		xmlChar *fullname;
 6331: 
 6332: 		fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
 6333: 		if (fullname == NULL) {
 6334: 		    xmlVErrMemory(ctxt, NULL);
 6335: 		    return(0);
 6336: 		}
 6337: 		ret = xmlStrEqual(doc->intSubset->name, fullname);
 6338: 		if ((fullname != fn) && (fullname != root->name))
 6339: 		    xmlFree(fullname);
 6340: 		if (ret == 1)
 6341: 		    goto name_ok;
 6342: 	    }
 6343: 	    if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
 6344: 		(xmlStrEqual(root->name, BAD_CAST "html")))
 6345: 		goto name_ok;
 6346: 	    xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
 6347: 		   "root and DTD name do not match '%s' and '%s'\n",
 6348: 		   root->name, doc->intSubset->name, NULL);
 6349: 	    return(0);
 6350: 	}
 6351:     }
 6352: name_ok:
 6353:     return(1);
 6354: }
 6355: 
 6356: 
 6357: /**
 6358:  * xmlValidateElement:
 6359:  * @ctxt:  the validation context
 6360:  * @doc:  a document instance
 6361:  * @elem:  an element instance
 6362:  *
 6363:  * Try to validate the subtree under an element
 6364:  *
 6365:  * returns 1 if valid or 0 otherwise
 6366:  */
 6367: 
 6368: int
 6369: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
 6370:     xmlNodePtr child;
 6371:     xmlAttrPtr attr;
 6372:     xmlNsPtr ns;
 6373:     const xmlChar *value;
 6374:     int ret = 1;
 6375: 
 6376:     if (elem == NULL) return(0);
 6377: 
 6378:     /*
 6379:      * XInclude elements were added after parsing in the infoset,
 6380:      * they don't really mean anything validation wise.
 6381:      */
 6382:     if ((elem->type == XML_XINCLUDE_START) ||
 6383: 	(elem->type == XML_XINCLUDE_END) ||
 6384: 	(elem->type == XML_NAMESPACE_DECL))
 6385: 	return(1);
 6386: 
 6387:     CHECK_DTD;
 6388: 
 6389:     /*
 6390:      * Entities references have to be handled separately
 6391:      */
 6392:     if (elem->type == XML_ENTITY_REF_NODE) {
 6393: 	return(1);
 6394:     }
 6395: 
 6396:     ret &= xmlValidateOneElement(ctxt, doc, elem);
 6397:     if (elem->type == XML_ELEMENT_NODE) {
 6398: 	attr = elem->properties;
 6399: 	while (attr != NULL) {
 6400: 	    value = xmlNodeListGetString(doc, attr->children, 0);
 6401: 	    ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
 6402: 	    if (value != NULL)
 6403: 		xmlFree((char *)value);
 6404: 	    attr= attr->next;
 6405: 	}
 6406: 	ns = elem->nsDef;
 6407: 	while (ns != NULL) {
 6408: 	    if (elem->ns == NULL)
 6409: 		ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
 6410: 					       ns, ns->href);
 6411: 	    else
 6412: 		ret &= xmlValidateOneNamespace(ctxt, doc, elem,
 6413: 		                               elem->ns->prefix, ns, ns->href);
 6414: 	    ns = ns->next;
 6415: 	}
 6416:     }
 6417:     child = elem->children;
 6418:     while (child != NULL) {
 6419:         ret &= xmlValidateElement(ctxt, doc, child);
 6420:         child = child->next;
 6421:     }
 6422: 
 6423:     return(ret);
 6424: }
 6425: 
 6426: /**
 6427:  * xmlValidateRef:
 6428:  * @ref:   A reference to be validated
 6429:  * @ctxt:  Validation context
 6430:  * @name:  Name of ID we are searching for
 6431:  *
 6432:  */
 6433: static void
 6434: xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
 6435: 	                   const xmlChar *name) {
 6436:     xmlAttrPtr id;
 6437:     xmlAttrPtr attr;
 6438: 
 6439:     if (ref == NULL)
 6440: 	return;
 6441:     if ((ref->attr == NULL) && (ref->name == NULL))
 6442: 	return;
 6443:     attr = ref->attr;
 6444:     if (attr == NULL) {
 6445: 	xmlChar *dup, *str = NULL, *cur, save;
 6446: 
 6447: 	dup = xmlStrdup(name);
 6448: 	if (dup == NULL) {
 6449: 	    ctxt->valid = 0;
 6450: 	    return;
 6451: 	}
 6452: 	cur = dup;
 6453: 	while (*cur != 0) {
 6454: 	    str = cur;
 6455: 	    while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
 6456: 	    save = *cur;
 6457: 	    *cur = 0;
 6458: 	    id = xmlGetID(ctxt->doc, str);
 6459: 	    if (id == NULL) {
 6460: 		xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
 6461: 	   "attribute %s line %d references an unknown ID \"%s\"\n",
 6462: 		       ref->name, ref->lineno, str);
 6463: 		ctxt->valid = 0;
 6464: 	    }
 6465: 	    if (save == 0)
 6466: 		break;
 6467: 	    *cur = save;
 6468: 	    while (IS_BLANK_CH(*cur)) cur++;
 6469: 	}
 6470: 	xmlFree(dup);
 6471:     } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
 6472: 	id = xmlGetID(ctxt->doc, name);
 6473: 	if (id == NULL) {
 6474: 	    xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
 6475: 	   "IDREF attribute %s references an unknown ID \"%s\"\n",
 6476: 		   attr->name, name, NULL);
 6477: 	    ctxt->valid = 0;
 6478: 	}
 6479:     } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
 6480: 	xmlChar *dup, *str = NULL, *cur, save;
 6481: 
 6482: 	dup = xmlStrdup(name);
 6483: 	if (dup == NULL) {
 6484: 	    xmlVErrMemory(ctxt, "IDREFS split");
 6485: 	    ctxt->valid = 0;
 6486: 	    return;
 6487: 	}
 6488: 	cur = dup;
 6489: 	while (*cur != 0) {
 6490: 	    str = cur;
 6491: 	    while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
 6492: 	    save = *cur;
 6493: 	    *cur = 0;
 6494: 	    id = xmlGetID(ctxt->doc, str);
 6495: 	    if (id == NULL) {
 6496: 		xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
 6497: 	   "IDREFS attribute %s references an unknown ID \"%s\"\n",
 6498: 			     attr->name, str, NULL);
 6499: 		ctxt->valid = 0;
 6500: 	    }
 6501: 	    if (save == 0)
 6502: 		break;
 6503: 	    *cur = save;
 6504: 	    while (IS_BLANK_CH(*cur)) cur++;
 6505: 	}
 6506: 	xmlFree(dup);
 6507:     }
 6508: }
 6509: 
 6510: /**
 6511:  * xmlWalkValidateList:
 6512:  * @data:  Contents of current link
 6513:  * @user:  Value supplied by the user
 6514:  *
 6515:  * Returns 0 to abort the walk or 1 to continue
 6516:  */
 6517: static int
 6518: xmlWalkValidateList(const void *data, const void *user)
 6519: {
 6520: 	xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
 6521: 	xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
 6522: 	return 1;
 6523: }
 6524: 
 6525: /**
 6526:  * xmlValidateCheckRefCallback:
 6527:  * @ref_list:  List of references
 6528:  * @ctxt:  Validation context
 6529:  * @name:  Name of ID we are searching for
 6530:  *
 6531:  */
 6532: static void
 6533: xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
 6534: 	                   const xmlChar *name) {
 6535:     xmlValidateMemo memo;
 6536: 
 6537:     if (ref_list == NULL)
 6538: 	return;
 6539:     memo.ctxt = ctxt;
 6540:     memo.name = name;
 6541: 
 6542:     xmlListWalk(ref_list, xmlWalkValidateList, &memo);
 6543: 
 6544: }
 6545: 
 6546: /**
 6547:  * xmlValidateDocumentFinal:
 6548:  * @ctxt:  the validation context
 6549:  * @doc:  a document instance
 6550:  *
 6551:  * Does the final step for the document validation once all the
 6552:  * incremental validation steps have been completed
 6553:  *
 6554:  * basically it does the following checks described by the XML Rec
 6555:  *
 6556:  * Check all the IDREF/IDREFS attributes definition for validity
 6557:  *
 6558:  * returns 1 if valid or 0 otherwise
 6559:  */
 6560: 
 6561: int
 6562: xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
 6563:     xmlRefTablePtr table;
 6564:     unsigned int save;
 6565: 
 6566:     if (ctxt == NULL)
 6567:         return(0);
 6568:     if (doc == NULL) {
 6569:         xmlErrValid(ctxt, XML_DTD_NO_DOC,
 6570: 		"xmlValidateDocumentFinal: doc == NULL\n", NULL);
 6571: 	return(0);
 6572:     }
 6573: 
 6574:     /* trick to get correct line id report */
 6575:     save = ctxt->finishDtd;
 6576:     ctxt->finishDtd = 0;
 6577: 
 6578:     /*
 6579:      * Check all the NOTATION/NOTATIONS attributes
 6580:      */
 6581:     /*
 6582:      * Check all the ENTITY/ENTITIES attributes definition for validity
 6583:      */
 6584:     /*
 6585:      * Check all the IDREF/IDREFS attributes definition for validity
 6586:      */
 6587:     table = (xmlRefTablePtr) doc->refs;
 6588:     ctxt->doc = doc;
 6589:     ctxt->valid = 1;
 6590:     xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
 6591: 
 6592:     ctxt->finishDtd = save;
 6593:     return(ctxt->valid);
 6594: }
 6595: 
 6596: /**
 6597:  * xmlValidateDtd:
 6598:  * @ctxt:  the validation context
 6599:  * @doc:  a document instance
 6600:  * @dtd:  a dtd instance
 6601:  *
 6602:  * Try to validate the document against the dtd instance
 6603:  *
 6604:  * Basically it does check all the definitions in the DtD.
 6605:  * Note the the internal subset (if present) is de-coupled
 6606:  * (i.e. not used), which could give problems if ID or IDREF
 6607:  * is present.
 6608:  *
 6609:  * returns 1 if valid or 0 otherwise
 6610:  */
 6611: 
 6612: int
 6613: xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
 6614:     int ret;
 6615:     xmlDtdPtr oldExt, oldInt;
 6616:     xmlNodePtr root;
 6617: 
 6618:     if (dtd == NULL) return(0);
 6619:     if (doc == NULL) return(0);
 6620:     oldExt = doc->extSubset;
 6621:     oldInt = doc->intSubset;
 6622:     doc->extSubset = dtd;
 6623:     doc->intSubset = NULL;
 6624:     ret = xmlValidateRoot(ctxt, doc);
 6625:     if (ret == 0) {
 6626: 	doc->extSubset = oldExt;
 6627: 	doc->intSubset = oldInt;
 6628: 	return(ret);
 6629:     }
 6630:     if (doc->ids != NULL) {
 6631:           xmlFreeIDTable(doc->ids);
 6632:           doc->ids = NULL;
 6633:     }
 6634:     if (doc->refs != NULL) {
 6635:           xmlFreeRefTable(doc->refs);
 6636:           doc->refs = NULL;
 6637:     }
 6638:     root = xmlDocGetRootElement(doc);
 6639:     ret = xmlValidateElement(ctxt, doc, root);
 6640:     ret &= xmlValidateDocumentFinal(ctxt, doc);
 6641:     doc->extSubset = oldExt;
 6642:     doc->intSubset = oldInt;
 6643:     return(ret);
 6644: }
 6645: 
 6646: static void
 6647: xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
 6648: 	                    const xmlChar *name ATTRIBUTE_UNUSED) {
 6649:     if (cur == NULL)
 6650: 	return;
 6651:     if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
 6652: 	xmlChar *notation = cur->content;
 6653: 
 6654: 	if (notation != NULL) {
 6655: 	    int ret;
 6656: 
 6657: 	    ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
 6658: 	    if (ret != 1) {
 6659: 		ctxt->valid = 0;
 6660: 	    }
 6661: 	}
 6662:     }
 6663: }
 6664: 
 6665: static void
 6666: xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
 6667: 	                    const xmlChar *name ATTRIBUTE_UNUSED) {
 6668:     int ret;
 6669:     xmlDocPtr doc;
 6670:     xmlElementPtr elem = NULL;
 6671: 
 6672:     if (cur == NULL)
 6673: 	return;
 6674:     switch (cur->atype) {
 6675: 	case XML_ATTRIBUTE_CDATA:
 6676: 	case XML_ATTRIBUTE_ID:
 6677: 	case XML_ATTRIBUTE_IDREF	:
 6678: 	case XML_ATTRIBUTE_IDREFS:
 6679: 	case XML_ATTRIBUTE_NMTOKEN:
 6680: 	case XML_ATTRIBUTE_NMTOKENS:
 6681: 	case XML_ATTRIBUTE_ENUMERATION:
 6682: 	    break;
 6683: 	case XML_ATTRIBUTE_ENTITY:
 6684: 	case XML_ATTRIBUTE_ENTITIES:
 6685: 	case XML_ATTRIBUTE_NOTATION:
 6686: 	    if (cur->defaultValue != NULL) {
 6687: 
 6688: 		ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
 6689: 			                         cur->atype, cur->defaultValue);
 6690: 		if ((ret == 0) && (ctxt->valid == 1))
 6691: 		    ctxt->valid = 0;
 6692: 	    }
 6693: 	    if (cur->tree != NULL) {
 6694: 		xmlEnumerationPtr tree = cur->tree;
 6695: 		while (tree != NULL) {
 6696: 		    ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
 6697: 				    cur->name, cur->atype, tree->name);
 6698: 		    if ((ret == 0) && (ctxt->valid == 1))
 6699: 			ctxt->valid = 0;
 6700: 		    tree = tree->next;
 6701: 		}
 6702: 	    }
 6703:     }
 6704:     if (cur->atype == XML_ATTRIBUTE_NOTATION) {
 6705: 	doc = cur->doc;
 6706: 	if (cur->elem == NULL) {
 6707: 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
 6708: 		   "xmlValidateAttributeCallback(%s): internal error\n",
 6709: 		   (const char *) cur->name);
 6710: 	    return;
 6711: 	}
 6712: 
 6713: 	if (doc != NULL)
 6714: 	    elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
 6715: 	if ((elem == NULL) && (doc != NULL))
 6716: 	    elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
 6717: 	if ((elem == NULL) && (cur->parent != NULL) &&
 6718: 	    (cur->parent->type == XML_DTD_NODE))
 6719: 	    elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
 6720: 	if (elem == NULL) {
 6721: 	    xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
 6722: 		   "attribute %s: could not find decl for element %s\n",
 6723: 		   cur->name, cur->elem, NULL);
 6724: 	    return;
 6725: 	}
 6726: 	if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
 6727: 	    xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
 6728: 		   "NOTATION attribute %s declared for EMPTY element %s\n",
 6729: 		   cur->name, cur->elem, NULL);
 6730: 	    ctxt->valid = 0;
 6731: 	}
 6732:     }
 6733: }
 6734: 
 6735: /**
 6736:  * xmlValidateDtdFinal:
 6737:  * @ctxt:  the validation context
 6738:  * @doc:  a document instance
 6739:  *
 6740:  * Does the final step for the dtds validation once all the
 6741:  * subsets have been parsed
 6742:  *
 6743:  * basically it does the following checks described by the XML Rec
 6744:  * - check that ENTITY and ENTITIES type attributes default or
 6745:  *   possible values matches one of the defined entities.
 6746:  * - check that NOTATION type attributes default or
 6747:  *   possible values matches one of the defined notations.
 6748:  *
 6749:  * returns 1 if valid or 0 if invalid and -1 if not well-formed
 6750:  */
 6751: 
 6752: int
 6753: xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
 6754:     xmlDtdPtr dtd;
 6755:     xmlAttributeTablePtr table;
 6756:     xmlEntitiesTablePtr entities;
 6757: 
 6758:     if ((doc == NULL) || (ctxt == NULL)) return(0);
 6759:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
 6760: 	return(0);
 6761:     ctxt->doc = doc;
 6762:     ctxt->valid = 1;
 6763:     dtd = doc->intSubset;
 6764:     if ((dtd != NULL) && (dtd->attributes != NULL)) {
 6765: 	table = (xmlAttributeTablePtr) dtd->attributes;
 6766: 	xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
 6767:     }
 6768:     if ((dtd != NULL) && (dtd->entities != NULL)) {
 6769: 	entities = (xmlEntitiesTablePtr) dtd->entities;
 6770: 	xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
 6771: 		    ctxt);
 6772:     }
 6773:     dtd = doc->extSubset;
 6774:     if ((dtd != NULL) && (dtd->attributes != NULL)) {
 6775: 	table = (xmlAttributeTablePtr) dtd->attributes;
 6776: 	xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
 6777:     }
 6778:     if ((dtd != NULL) && (dtd->entities != NULL)) {
 6779: 	entities = (xmlEntitiesTablePtr) dtd->entities;
 6780: 	xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
 6781: 		    ctxt);
 6782:     }
 6783:     return(ctxt->valid);
 6784: }
 6785: 
 6786: /**
 6787:  * xmlValidateDocument:
 6788:  * @ctxt:  the validation context
 6789:  * @doc:  a document instance
 6790:  *
 6791:  * Try to validate the document instance
 6792:  *
 6793:  * basically it does the all the checks described by the XML Rec
 6794:  * i.e. validates the internal and external subset (if present)
 6795:  * and validate the document tree.
 6796:  *
 6797:  * returns 1 if valid or 0 otherwise
 6798:  */
 6799: 
 6800: int
 6801: xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
 6802:     int ret;
 6803:     xmlNodePtr root;
 6804: 
 6805:     if (doc == NULL)
 6806:         return(0);
 6807:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
 6808:         xmlErrValid(ctxt, XML_DTD_NO_DTD,
 6809: 	            "no DTD found!\n", NULL);
 6810: 	return(0);
 6811:     }
 6812:     if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
 6813: 	(doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
 6814: 	xmlChar *sysID;
 6815: 	if (doc->intSubset->SystemID != NULL) {
 6816: 	    sysID = xmlBuildURI(doc->intSubset->SystemID,
 6817: 			doc->URL);
 6818: 	    if (sysID == NULL) {
 6819: 	        xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
 6820: 			"Could not build URI for external subset \"%s\"\n",
 6821: 			(const char *) doc->intSubset->SystemID);
 6822: 		return 0;
 6823: 	    }
 6824: 	} else
 6825: 	    sysID = NULL;
 6826:         doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
 6827: 			(const xmlChar *)sysID);
 6828: 	if (sysID != NULL)
 6829: 	    xmlFree(sysID);
 6830:         if (doc->extSubset == NULL) {
 6831: 	    if (doc->intSubset->SystemID != NULL) {
 6832: 		xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
 6833: 		       "Could not load the external subset \"%s\"\n",
 6834: 		       (const char *) doc->intSubset->SystemID);
 6835: 	    } else {
 6836: 		xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
 6837: 		       "Could not load the external subset \"%s\"\n",
 6838: 		       (const char *) doc->intSubset->ExternalID);
 6839: 	    }
 6840: 	    return(0);
 6841: 	}
 6842:     }
 6843: 
 6844:     if (doc->ids != NULL) {
 6845:           xmlFreeIDTable(doc->ids);
 6846:           doc->ids = NULL;
 6847:     }
 6848:     if (doc->refs != NULL) {
 6849:           xmlFreeRefTable(doc->refs);
 6850:           doc->refs = NULL;
 6851:     }
 6852:     ret = xmlValidateDtdFinal(ctxt, doc);
 6853:     if (!xmlValidateRoot(ctxt, doc)) return(0);
 6854: 
 6855:     root = xmlDocGetRootElement(doc);
 6856:     ret &= xmlValidateElement(ctxt, doc, root);
 6857:     ret &= xmlValidateDocumentFinal(ctxt, doc);
 6858:     return(ret);
 6859: }
 6860: 
 6861: /************************************************************************
 6862:  *									*
 6863:  *		Routines for dynamic validation editing			*
 6864:  *									*
 6865:  ************************************************************************/
 6866: 
 6867: /**
 6868:  * xmlValidGetPotentialChildren:
 6869:  * @ctree:  an element content tree
 6870:  * @names:  an array to store the list of child names
 6871:  * @len:  a pointer to the number of element in the list
 6872:  * @max:  the size of the array
 6873:  *
 6874:  * Build/extend a list of  potential children allowed by the content tree
 6875:  *
 6876:  * returns the number of element in the list, or -1 in case of error.
 6877:  */
 6878: 
 6879: int
 6880: xmlValidGetPotentialChildren(xmlElementContent *ctree,
 6881:                              const xmlChar **names,
 6882:                              int *len, int max) {
 6883:     int i;
 6884: 
 6885:     if ((ctree == NULL) || (names == NULL) || (len == NULL))
 6886:         return(-1);
 6887:     if (*len >= max) return(*len);
 6888: 
 6889:     switch (ctree->type) {
 6890: 	case XML_ELEMENT_CONTENT_PCDATA:
 6891: 	    for (i = 0; i < *len;i++)
 6892: 		if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
 6893: 	    names[(*len)++] = BAD_CAST "#PCDATA";
 6894: 	    break;
 6895: 	case XML_ELEMENT_CONTENT_ELEMENT:
 6896: 	    for (i = 0; i < *len;i++)
 6897: 		if (xmlStrEqual(ctree->name, names[i])) return(*len);
 6898: 	    names[(*len)++] = ctree->name;
 6899: 	    break;
 6900: 	case XML_ELEMENT_CONTENT_SEQ:
 6901: 	    xmlValidGetPotentialChildren(ctree->c1, names, len, max);
 6902: 	    xmlValidGetPotentialChildren(ctree->c2, names, len, max);
 6903: 	    break;
 6904: 	case XML_ELEMENT_CONTENT_OR:
 6905: 	    xmlValidGetPotentialChildren(ctree->c1, names, len, max);
 6906: 	    xmlValidGetPotentialChildren(ctree->c2, names, len, max);
 6907: 	    break;
 6908:    }
 6909: 
 6910:    return(*len);
 6911: }
 6912: 
 6913: /*
 6914:  * Dummy function to suppress messages while we try out valid elements
 6915:  */
 6916: static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
 6917:                                 const char *msg ATTRIBUTE_UNUSED, ...) {
 6918:     return;
 6919: }
 6920: 
 6921: /**
 6922:  * xmlValidGetValidElements:
 6923:  * @prev:  an element to insert after
 6924:  * @next:  an element to insert next
 6925:  * @names:  an array to store the list of child names
 6926:  * @max:  the size of the array
 6927:  *
 6928:  * This function returns the list of authorized children to insert
 6929:  * within an existing tree while respecting the validity constraints
 6930:  * forced by the Dtd. The insertion point is defined using @prev and
 6931:  * @next in the following ways:
 6932:  *  to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
 6933:  *  to insert next 'node': xmlValidGetValidElements(node, node->next, ...
 6934:  *  to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
 6935:  *  to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
 6936:  *  to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
 6937:  *
 6938:  * pointers to the element names are inserted at the beginning of the array
 6939:  * and do not need to be freed.
 6940:  *
 6941:  * returns the number of element in the list, or -1 in case of error. If
 6942:  *    the function returns the value @max the caller is invited to grow the
 6943:  *    receiving array and retry.
 6944:  */
 6945: 
 6946: int
 6947: xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
 6948:                          int max) {
 6949:     xmlValidCtxt vctxt;
 6950:     int nb_valid_elements = 0;
 6951:     const xmlChar *elements[256];
 6952:     int nb_elements = 0, i;
 6953:     const xmlChar *name;
 6954: 
 6955:     xmlNode *ref_node;
 6956:     xmlNode *parent;
 6957:     xmlNode *test_node;
 6958: 
 6959:     xmlNode *prev_next;
 6960:     xmlNode *next_prev;
 6961:     xmlNode *parent_childs;
 6962:     xmlNode *parent_last;
 6963: 
 6964:     xmlElement *element_desc;
 6965: 
 6966:     if (prev == NULL && next == NULL)
 6967:         return(-1);
 6968: 
 6969:     if (names == NULL) return(-1);
 6970:     if (max <= 0) return(-1);
 6971: 
 6972:     memset(&vctxt, 0, sizeof (xmlValidCtxt));
 6973:     vctxt.error = xmlNoValidityErr;	/* this suppresses err/warn output */
 6974: 
 6975:     nb_valid_elements = 0;
 6976:     ref_node = prev ? prev : next;
 6977:     parent = ref_node->parent;
 6978: 
 6979:     /*
 6980:      * Retrieves the parent element declaration
 6981:      */
 6982:     element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
 6983:                                          parent->name);
 6984:     if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
 6985:         element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
 6986:                                              parent->name);
 6987:     if (element_desc == NULL) return(-1);
 6988: 
 6989:     /*
 6990:      * Do a backup of the current tree structure
 6991:      */
 6992:     prev_next = prev ? prev->next : NULL;
 6993:     next_prev = next ? next->prev : NULL;
 6994:     parent_childs = parent->children;
 6995:     parent_last = parent->last;
 6996: 
 6997:     /*
 6998:      * Creates a dummy node and insert it into the tree
 6999:      */
 7000:     test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
 7001:     test_node->parent = parent;
 7002:     test_node->prev = prev;
 7003:     test_node->next = next;
 7004:     name = test_node->name;
 7005: 
 7006:     if (prev) prev->next = test_node;
 7007:     else parent->children = test_node;
 7008: 
 7009:     if (next) next->prev = test_node;
 7010:     else parent->last = test_node;
 7011: 
 7012:     /*
 7013:      * Insert each potential child node and check if the parent is
 7014:      * still valid
 7015:      */
 7016:     nb_elements = xmlValidGetPotentialChildren(element_desc->content,
 7017: 		       elements, &nb_elements, 256);
 7018: 
 7019:     for (i = 0;i < nb_elements;i++) {
 7020: 	test_node->name = elements[i];
 7021: 	if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
 7022: 	    int j;
 7023: 
 7024: 	    for (j = 0; j < nb_valid_elements;j++)
 7025: 		if (xmlStrEqual(elements[i], names[j])) break;
 7026: 	    names[nb_valid_elements++] = elements[i];
 7027: 	    if (nb_valid_elements >= max) break;
 7028: 	}
 7029:     }
 7030: 
 7031:     /*
 7032:      * Restore the tree structure
 7033:      */
 7034:     if (prev) prev->next = prev_next;
 7035:     if (next) next->prev = next_prev;
 7036:     parent->children = parent_childs;
 7037:     parent->last = parent_last;
 7038: 
 7039:     /*
 7040:      * Free up the dummy node
 7041:      */
 7042:     test_node->name = name;
 7043:     xmlFreeNode(test_node);
 7044: 
 7045:     return(nb_valid_elements);
 7046: }
 7047: #endif /* LIBXML_VALID_ENABLED */
 7048: 
 7049: #define bottom_valid
 7050: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>