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