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