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