ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

valid.c
Go to the documentation of this file.
00001 /*
00002  * valid.c : part of the code use to do the DTD handling and the validity
00003  *           checking
00004  *
00005  * See Copyright for the status of this software.
00006  *
00007  * daniel@veillard.com
00008  */
00009 
00010 #define IN_LIBXML
00011 #include "libxml.h"
00012 
00013 #include <string.h>
00014 
00015 #ifdef HAVE_STDLIB_H
00016 #include <stdlib.h>
00017 #endif
00018 
00019 #include <libxml/xmlmemory.h>
00020 #include <libxml/hash.h>
00021 #include <libxml/uri.h>
00022 #include <libxml/valid.h>
00023 #include <libxml/parser.h>
00024 #include <libxml/parserInternals.h>
00025 #include <libxml/xmlerror.h>
00026 #include <libxml/list.h>
00027 #include <libxml/globals.h>
00028 
00029 static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
00030                                int create);
00031 /* #define DEBUG_VALID_ALGO */
00032 /* #define DEBUG_REGEXP_ALGO */
00033 
00034 #define TODO                                \
00035     xmlGenericError(xmlGenericErrorContext,             \
00036         "Unimplemented block at %s:%d\n",               \
00037             __FILE__, __LINE__);
00038 
00039 #ifdef LIBXML_VALID_ENABLED
00040 static int
00041 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
00042                                   const xmlChar *value);
00043 #endif
00044 /************************************************************************
00045  *                                  *
00046  *          Error handling routines             *
00047  *                                  *
00048  ************************************************************************/
00049 
00057 static void
00058 xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
00059 {
00060     xmlGenericErrorFunc channel = NULL;
00061     xmlParserCtxtPtr pctxt = NULL;
00062     void *data = NULL;
00063 
00064     if (ctxt != NULL) {
00065         channel = ctxt->error;
00066         data = ctxt->userData;
00067     /* Use the special values to detect if it is part of a parsing
00068        context */
00069     if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
00070         (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
00071         long delta = (char *) ctxt - (char *) ctxt->userData;
00072         if ((delta > 0) && (delta < 250))
00073         pctxt = ctxt->userData;
00074     }
00075     }
00076     if (extra)
00077         __xmlRaiseError(NULL, channel, data,
00078                         pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
00079                         XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
00080                         "Memory allocation failed : %s\n", extra);
00081     else
00082         __xmlRaiseError(NULL, channel, data,
00083                         pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
00084                         XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
00085                         "Memory allocation failed\n");
00086 }
00087 
00096 static void
00097 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
00098             const char *msg, const char *extra)
00099 {
00100     xmlGenericErrorFunc channel = NULL;
00101     xmlParserCtxtPtr pctxt = NULL;
00102     void *data = NULL;
00103 
00104     if (ctxt != NULL) {
00105         channel = ctxt->error;
00106         data = ctxt->userData;
00107     /* Use the special values to detect if it is part of a parsing
00108        context */
00109     if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
00110         (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
00111         long delta = (char *) ctxt - (char *) ctxt->userData;
00112         if ((delta > 0) && (delta < 250))
00113         pctxt = ctxt->userData;
00114     }
00115     }
00116     if (extra)
00117         __xmlRaiseError(NULL, channel, data,
00118                         pctxt, NULL, XML_FROM_VALID, error,
00119                         XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
00120                         msg, extra);
00121     else
00122         __xmlRaiseError(NULL, channel, data,
00123                         pctxt, NULL, XML_FROM_VALID, error,
00124                         XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
00125                         "%s", msg);
00126 }
00127 
00128 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
00129 
00140 static void
00141 xmlErrValidNode(xmlValidCtxtPtr ctxt,
00142                 xmlNodePtr node, xmlParserErrors error,
00143                 const char *msg, const xmlChar * str1,
00144                 const xmlChar * str2, const xmlChar * str3)
00145 {
00146     xmlStructuredErrorFunc schannel = NULL;
00147     xmlGenericErrorFunc channel = NULL;
00148     xmlParserCtxtPtr pctxt = NULL;
00149     void *data = NULL;
00150 
00151     if (ctxt != NULL) {
00152         channel = ctxt->error;
00153         data = ctxt->userData;
00154     /* Use the special values to detect if it is part of a parsing
00155        context */
00156     if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
00157         (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
00158         long delta = (char *) ctxt - (char *) ctxt->userData;
00159         if ((delta > 0) && (delta < 250))
00160         pctxt = ctxt->userData;
00161     }
00162     }
00163     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
00164                     XML_ERR_ERROR, NULL, 0,
00165                     (const char *) str1,
00166                     (const char *) str1,
00167                     (const char *) str3, 0, 0, msg, str1, str2, str3);
00168 }
00169 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
00170 
00171 #ifdef LIBXML_VALID_ENABLED
00172 
00183 static void
00184 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
00185                 xmlNodePtr node, xmlParserErrors error,
00186                 const char *msg, const xmlChar * str1,
00187                 int int2, const xmlChar * str3)
00188 {
00189     xmlStructuredErrorFunc schannel = NULL;
00190     xmlGenericErrorFunc channel = NULL;
00191     xmlParserCtxtPtr pctxt = NULL;
00192     void *data = NULL;
00193 
00194     if (ctxt != NULL) {
00195         channel = ctxt->error;
00196         data = ctxt->userData;
00197     /* Use the special values to detect if it is part of a parsing
00198        context */
00199     if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
00200         (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
00201         long delta = (char *) ctxt - (char *) ctxt->userData;
00202         if ((delta > 0) && (delta < 250))
00203         pctxt = ctxt->userData;
00204     }
00205     }
00206     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
00207                     XML_ERR_ERROR, NULL, 0,
00208                     (const char *) str1,
00209                     (const char *) str3,
00210                     NULL, int2, 0, msg, str1, int2, str3);
00211 }
00212 
00224 static void
00225 xmlErrValidWarning(xmlValidCtxtPtr ctxt,
00226                 xmlNodePtr node, xmlParserErrors error,
00227                 const char *msg, const xmlChar * str1,
00228                 const xmlChar * str2, const xmlChar * str3)
00229 {
00230     xmlStructuredErrorFunc schannel = NULL;
00231     xmlGenericErrorFunc channel = NULL;
00232     xmlParserCtxtPtr pctxt = NULL;
00233     void *data = NULL;
00234 
00235     if (ctxt != NULL) {
00236         channel = ctxt->warning;
00237         data = ctxt->userData;
00238     /* Use the special values to detect if it is part of a parsing
00239        context */
00240     if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
00241         (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
00242         long delta = (char *) ctxt - (char *) ctxt->userData;
00243         if ((delta > 0) && (delta < 250))
00244         pctxt = ctxt->userData;
00245     }
00246     }
00247     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
00248                     XML_ERR_WARNING, NULL, 0,
00249                     (const char *) str1,
00250                     (const char *) str1,
00251                     (const char *) str3, 0, 0, msg, str1, str2, str3);
00252 }
00253 
00254 
00255 
00256 #ifdef LIBXML_REGEXP_ENABLED
00257 /*
00258  * If regexp are enabled we can do continuous validation without the
00259  * need of a tree to validate the content model. this is done in each
00260  * callbacks.
00261  * Each xmlValidState represent the validation state associated to the
00262  * set of nodes currently open from the document root to the current element.
00263  */
00264 
00265 
00266 typedef struct _xmlValidState {
00267     xmlElementPtr    elemDecl;  /* pointer to the content model */
00268     xmlNodePtr           node;      /* pointer to the current node */
00269     xmlRegExecCtxtPtr    exec;      /* regexp runtime */
00270 } _xmlValidState;
00271 
00272 
00273 static int
00274 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
00275     if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
00276     ctxt->vstateMax = 10;
00277     ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
00278                       sizeof(ctxt->vstateTab[0]));
00279         if (ctxt->vstateTab == NULL) {
00280         xmlVErrMemory(ctxt, "malloc failed");
00281         return(-1);
00282     }
00283     }
00284 
00285     if (ctxt->vstateNr >= ctxt->vstateMax) {
00286         xmlValidState *tmp;
00287 
00288     tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
00289                  2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
00290         if (tmp == NULL) {
00291         xmlVErrMemory(ctxt, "realloc failed");
00292         return(-1);
00293     }
00294     ctxt->vstateMax *= 2;
00295     ctxt->vstateTab = tmp;
00296     }
00297     ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
00298     ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
00299     ctxt->vstateTab[ctxt->vstateNr].node = node;
00300     if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
00301     if (elemDecl->contModel == NULL)
00302         xmlValidBuildContentModel(ctxt, elemDecl);
00303     if (elemDecl->contModel != NULL) {
00304         ctxt->vstateTab[ctxt->vstateNr].exec = 
00305         xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
00306     } else {
00307         ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
00308         xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
00309                         XML_ERR_INTERNAL_ERROR,
00310                 "Failed to build content model regexp for %s\n",
00311                 node->name, NULL, NULL);
00312     }
00313     }
00314     return(ctxt->vstateNr++);
00315 }
00316 
00317 static int
00318 vstateVPop(xmlValidCtxtPtr ctxt) {
00319     xmlElementPtr elemDecl;
00320 
00321     if (ctxt->vstateNr < 1) return(-1);
00322     ctxt->vstateNr--;
00323     elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
00324     ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
00325     ctxt->vstateTab[ctxt->vstateNr].node = NULL;
00326     if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
00327     xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
00328     }
00329     ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
00330     if (ctxt->vstateNr >= 1)
00331     ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
00332     else
00333     ctxt->vstate = NULL;
00334     return(ctxt->vstateNr);
00335 }
00336 
00337 #else /* not LIBXML_REGEXP_ENABLED */
00338 /*
00339  * If regexp are not enabled, it uses a home made algorithm less
00340  * complex and easier to
00341  * debug/maintain than a generic NFA -> DFA state based algo. The
00342  * only restriction is on the deepness of the tree limited by the
00343  * size of the occurs bitfield
00344  *
00345  * this is the content of a saved state for rollbacks
00346  */
00347 
00348 #define ROLLBACK_OR 0
00349 #define ROLLBACK_PARENT 1
00350 
00351 typedef struct _xmlValidState {
00352     xmlElementContentPtr cont;  /* pointer to the content model subtree */
00353     xmlNodePtr           node;  /* pointer to the current node in the list */
00354     long                 occurs;/* bitfield for multiple occurrences */
00355     unsigned char        depth; /* current depth in the overall tree */
00356     unsigned char        state; /* ROLLBACK_XXX */
00357 } _xmlValidState;
00358 
00359 #define MAX_RECURSE 25000
00360 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
00361 #define CONT ctxt->vstate->cont
00362 #define NODE ctxt->vstate->node
00363 #define DEPTH ctxt->vstate->depth
00364 #define OCCURS ctxt->vstate->occurs
00365 #define STATE ctxt->vstate->state
00366 
00367 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
00368 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
00369 
00370 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
00371 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
00372 
00373 static int
00374 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
00375         xmlNodePtr node, unsigned char depth, long occurs,
00376         unsigned char state) {
00377     int i = ctxt->vstateNr - 1;
00378 
00379     if (ctxt->vstateNr > MAX_RECURSE) {
00380     return(-1);
00381     }
00382     if (ctxt->vstateTab == NULL) {
00383     ctxt->vstateMax = 8;
00384     ctxt->vstateTab = (xmlValidState *) xmlMalloc(
00385              ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
00386     if (ctxt->vstateTab == NULL) {
00387         xmlVErrMemory(ctxt, "malloc failed");
00388         return(-1);
00389     }
00390     }
00391     if (ctxt->vstateNr >= ctxt->vstateMax) {
00392         xmlValidState *tmp;
00393 
00394         tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
00395                  2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
00396         if (tmp == NULL) {
00397         xmlVErrMemory(ctxt, "malloc failed");
00398         return(-1);
00399     }
00400     ctxt->vstateMax *= 2;
00401     ctxt->vstateTab = tmp;
00402     ctxt->vstate = &ctxt->vstateTab[0];
00403     }
00404     /*
00405      * Don't push on the stack a state already here
00406      */
00407     if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
00408     (ctxt->vstateTab[i].node == node) &&
00409     (ctxt->vstateTab[i].depth == depth) &&
00410     (ctxt->vstateTab[i].occurs == occurs) &&
00411     (ctxt->vstateTab[i].state == state))
00412     return(ctxt->vstateNr);
00413     ctxt->vstateTab[ctxt->vstateNr].cont = cont;
00414     ctxt->vstateTab[ctxt->vstateNr].node = node;
00415     ctxt->vstateTab[ctxt->vstateNr].depth = depth;
00416     ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
00417     ctxt->vstateTab[ctxt->vstateNr].state = state;
00418     return(ctxt->vstateNr++);
00419 }
00420 
00421 static int
00422 vstateVPop(xmlValidCtxtPtr ctxt) {
00423     if (ctxt->vstateNr <= 1) return(-1);
00424     ctxt->vstateNr--;
00425     ctxt->vstate = &ctxt->vstateTab[0];
00426     ctxt->vstate->cont =  ctxt->vstateTab[ctxt->vstateNr].cont;
00427     ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
00428     ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
00429     ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
00430     ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
00431     return(ctxt->vstateNr);
00432 }
00433 
00434 #endif /* LIBXML_REGEXP_ENABLED */
00435 
00436 static int
00437 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
00438 {
00439     if (ctxt->nodeMax <= 0) {
00440         ctxt->nodeMax = 4;
00441         ctxt->nodeTab =
00442             (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
00443                                      sizeof(ctxt->nodeTab[0]));
00444         if (ctxt->nodeTab == NULL) {
00445         xmlVErrMemory(ctxt, "malloc failed");
00446             ctxt->nodeMax = 0;
00447             return (0);
00448         }
00449     }
00450     if (ctxt->nodeNr >= ctxt->nodeMax) {
00451         xmlNodePtr *tmp;
00452         tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
00453                   ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
00454         if (tmp == NULL) {
00455         xmlVErrMemory(ctxt, "realloc failed");
00456             return (0);
00457         }
00458         ctxt->nodeMax *= 2;
00459     ctxt->nodeTab = tmp;
00460     }
00461     ctxt->nodeTab[ctxt->nodeNr] = value;
00462     ctxt->node = value;
00463     return (ctxt->nodeNr++);
00464 }
00465 static xmlNodePtr
00466 nodeVPop(xmlValidCtxtPtr ctxt)
00467 {
00468     xmlNodePtr ret;
00469 
00470     if (ctxt->nodeNr <= 0)
00471         return (NULL);
00472     ctxt->nodeNr--;
00473     if (ctxt->nodeNr > 0)
00474         ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
00475     else
00476         ctxt->node = NULL;
00477     ret = ctxt->nodeTab[ctxt->nodeNr];
00478     ctxt->nodeTab[ctxt->nodeNr] = NULL;
00479     return (ret);
00480 }
00481 
00482 #ifdef DEBUG_VALID_ALGO
00483 static void
00484 xmlValidPrintNode(xmlNodePtr cur) {
00485     if (cur == NULL) {
00486     xmlGenericError(xmlGenericErrorContext, "null");
00487     return;
00488     }
00489     switch (cur->type) {
00490     case XML_ELEMENT_NODE:
00491         xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
00492         break;
00493     case XML_TEXT_NODE:
00494         xmlGenericError(xmlGenericErrorContext, "text ");
00495         break;
00496     case XML_CDATA_SECTION_NODE:
00497         xmlGenericError(xmlGenericErrorContext, "cdata ");
00498         break;
00499     case XML_ENTITY_REF_NODE:
00500         xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
00501         break;
00502     case XML_PI_NODE:
00503         xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
00504         break;
00505     case XML_COMMENT_NODE:
00506         xmlGenericError(xmlGenericErrorContext, "comment ");
00507         break;
00508     case XML_ATTRIBUTE_NODE:
00509         xmlGenericError(xmlGenericErrorContext, "?attr? ");
00510         break;
00511     case XML_ENTITY_NODE:
00512         xmlGenericError(xmlGenericErrorContext, "?ent? ");
00513         break;
00514     case XML_DOCUMENT_NODE:
00515         xmlGenericError(xmlGenericErrorContext, "?doc? ");
00516         break;
00517     case XML_DOCUMENT_TYPE_NODE:
00518         xmlGenericError(xmlGenericErrorContext, "?doctype? ");
00519         break;
00520     case XML_DOCUMENT_FRAG_NODE:
00521         xmlGenericError(xmlGenericErrorContext, "?frag? ");
00522         break;
00523     case XML_NOTATION_NODE:
00524         xmlGenericError(xmlGenericErrorContext, "?nota? ");
00525         break;
00526     case XML_HTML_DOCUMENT_NODE:
00527         xmlGenericError(xmlGenericErrorContext, "?html? ");
00528         break;
00529 #ifdef LIBXML_DOCB_ENABLED
00530     case XML_DOCB_DOCUMENT_NODE:
00531         xmlGenericError(xmlGenericErrorContext, "?docb? ");
00532         break;
00533 #endif
00534     case XML_DTD_NODE:
00535         xmlGenericError(xmlGenericErrorContext, "?dtd? ");
00536         break;
00537     case XML_ELEMENT_DECL:
00538         xmlGenericError(xmlGenericErrorContext, "?edecl? ");
00539         break;
00540     case XML_ATTRIBUTE_DECL:
00541         xmlGenericError(xmlGenericErrorContext, "?adecl? ");
00542         break;
00543     case XML_ENTITY_DECL:
00544         xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
00545         break;
00546     case XML_NAMESPACE_DECL:
00547         xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
00548         break;
00549     case XML_XINCLUDE_START:
00550         xmlGenericError(xmlGenericErrorContext, "incstart ");
00551         break;
00552     case XML_XINCLUDE_END:
00553         xmlGenericError(xmlGenericErrorContext, "incend ");
00554         break;
00555     }
00556 }
00557 
00558 static void
00559 xmlValidPrintNodeList(xmlNodePtr cur) {
00560     if (cur == NULL)
00561     xmlGenericError(xmlGenericErrorContext, "null ");
00562     while (cur != NULL) {
00563     xmlValidPrintNode(cur);
00564     cur = cur->next;
00565     }
00566 }
00567 
00568 static void
00569 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
00570     char expr[5000];
00571 
00572     expr[0] = 0;
00573     xmlGenericError(xmlGenericErrorContext, "valid: ");
00574     xmlValidPrintNodeList(cur);
00575     xmlGenericError(xmlGenericErrorContext, "against ");
00576     xmlSnprintfElementContent(expr, 5000, cont, 1);
00577     xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
00578 }
00579 
00580 static void
00581 xmlValidDebugState(xmlValidStatePtr state) {
00582     xmlGenericError(xmlGenericErrorContext, "(");
00583     if (state->cont == NULL)
00584     xmlGenericError(xmlGenericErrorContext, "null,");
00585     else
00586     switch (state->cont->type) {
00587             case XML_ELEMENT_CONTENT_PCDATA:
00588         xmlGenericError(xmlGenericErrorContext, "pcdata,");
00589         break;
00590             case XML_ELEMENT_CONTENT_ELEMENT:
00591         xmlGenericError(xmlGenericErrorContext, "%s,",
00592                     state->cont->name);
00593         break;
00594             case XML_ELEMENT_CONTENT_SEQ:
00595         xmlGenericError(xmlGenericErrorContext, "seq,");
00596         break;
00597             case XML_ELEMENT_CONTENT_OR:
00598         xmlGenericError(xmlGenericErrorContext, "or,");
00599         break;
00600     }
00601     xmlValidPrintNode(state->node);
00602     xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
00603         state->depth, state->occurs, state->state);
00604 }
00605 
00606 static void
00607 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
00608     int i, j;
00609 
00610     xmlGenericError(xmlGenericErrorContext, "state: ");
00611     xmlValidDebugState(ctxt->vstate);
00612     xmlGenericError(xmlGenericErrorContext, " stack: %d ",
00613         ctxt->vstateNr - 1);
00614     for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
00615     xmlValidDebugState(&ctxt->vstateTab[j]);
00616     xmlGenericError(xmlGenericErrorContext, "\n");
00617 }
00618 
00619 /*****
00620 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
00621  *****/
00622 
00623 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
00624 #define DEBUG_VALID_MSG(m)                  \
00625     xmlGenericError(xmlGenericErrorContext, "%s\n", m);
00626         
00627 #else
00628 #define DEBUG_VALID_STATE(n,c)
00629 #define DEBUG_VALID_MSG(m)
00630 #endif
00631 
00632 /* TODO: use hash table for accesses to elem and attribute definitions */
00633 
00634 
00635 #define CHECK_DTD                       \
00636    if (doc == NULL) return(0);                  \
00637    else if ((doc->intSubset == NULL) &&             \
00638         (doc->extSubset == NULL)) return(0)
00639 
00640 #ifdef LIBXML_REGEXP_ENABLED
00641 
00642 /************************************************************************
00643  *                                  *
00644  *      Content model validation based on the regexps       *
00645  *                                  *
00646  ************************************************************************/
00647 
00658 static int
00659 xmlValidBuildAContentModel(xmlElementContentPtr content,
00660                    xmlValidCtxtPtr ctxt,
00661                    const xmlChar *name) {
00662     if (content == NULL) {
00663     xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
00664             "Found NULL content in content model of %s\n",
00665             name, NULL, NULL);
00666     return(0);
00667     }
00668     switch (content->type) {
00669     case XML_ELEMENT_CONTENT_PCDATA:
00670         xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
00671                 "Found PCDATA in content model of %s\n",
00672                     name, NULL, NULL);
00673         return(0);
00674         break;
00675     case XML_ELEMENT_CONTENT_ELEMENT: {
00676         xmlAutomataStatePtr oldstate = ctxt->state;
00677         xmlChar fn[50];
00678         xmlChar *fullname;
00679         
00680         fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
00681         if (fullname == NULL) {
00682             xmlVErrMemory(ctxt, "Building content model");
00683         return(0);
00684         }
00685 
00686         switch (content->ocur) {
00687         case XML_ELEMENT_CONTENT_ONCE:
00688             ctxt->state = xmlAutomataNewTransition(ctxt->am,
00689                 ctxt->state, NULL, fullname, NULL);
00690             break;
00691         case XML_ELEMENT_CONTENT_OPT:
00692             ctxt->state = xmlAutomataNewTransition(ctxt->am,
00693                 ctxt->state, NULL, fullname, NULL);
00694             xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
00695             break;
00696         case XML_ELEMENT_CONTENT_PLUS:
00697             ctxt->state = xmlAutomataNewTransition(ctxt->am,
00698                 ctxt->state, NULL, fullname, NULL);
00699             xmlAutomataNewTransition(ctxt->am, ctxt->state,
00700                                  ctxt->state, fullname, NULL);
00701             break;
00702         case XML_ELEMENT_CONTENT_MULT:
00703             ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
00704                             ctxt->state, NULL);
00705             xmlAutomataNewTransition(ctxt->am,
00706                     ctxt->state, ctxt->state, fullname, NULL);
00707             break;
00708         }
00709         if ((fullname != fn) && (fullname != content->name))
00710         xmlFree(fullname);
00711         break;
00712     }
00713     case XML_ELEMENT_CONTENT_SEQ: {
00714         xmlAutomataStatePtr oldstate, oldend;
00715         xmlElementContentOccur ocur;
00716 
00717         /*
00718          * Simply iterate over the content
00719          */
00720         oldstate = ctxt->state;
00721         ocur = content->ocur;
00722         if (ocur != XML_ELEMENT_CONTENT_ONCE) {
00723         ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
00724         oldstate = ctxt->state;
00725         }
00726         do {
00727         xmlValidBuildAContentModel(content->c1, ctxt, name);
00728         content = content->c2;
00729         } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
00730              (content->ocur == XML_ELEMENT_CONTENT_ONCE));
00731         xmlValidBuildAContentModel(content, ctxt, name);
00732         oldend = ctxt->state;
00733         ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
00734         switch (ocur) {
00735         case XML_ELEMENT_CONTENT_ONCE:
00736             break;
00737         case XML_ELEMENT_CONTENT_OPT:
00738             xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
00739             break;
00740         case XML_ELEMENT_CONTENT_MULT:
00741             xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
00742             xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
00743             break;
00744         case XML_ELEMENT_CONTENT_PLUS:
00745             xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
00746             break;
00747         }
00748         break;
00749     }
00750     case XML_ELEMENT_CONTENT_OR: {
00751         xmlAutomataStatePtr oldstate, oldend;
00752         xmlElementContentOccur ocur;
00753 
00754         ocur = content->ocur;
00755         if ((ocur == XML_ELEMENT_CONTENT_PLUS) || 
00756         (ocur == XML_ELEMENT_CONTENT_MULT)) {
00757         ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
00758             ctxt->state, NULL);
00759         }
00760         oldstate = ctxt->state;
00761         oldend = xmlAutomataNewState(ctxt->am);
00762 
00763         /*
00764          * iterate over the subtypes and remerge the end with an
00765          * epsilon transition
00766          */
00767         do {
00768         ctxt->state = oldstate;
00769         xmlValidBuildAContentModel(content->c1, ctxt, name);
00770         xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
00771         content = content->c2;
00772         } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
00773              (content->ocur == XML_ELEMENT_CONTENT_ONCE));
00774         ctxt->state = oldstate;
00775         xmlValidBuildAContentModel(content, ctxt, name);
00776         xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
00777         ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
00778         switch (ocur) {
00779         case XML_ELEMENT_CONTENT_ONCE:
00780             break;
00781         case XML_ELEMENT_CONTENT_OPT:
00782             xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
00783             break;
00784         case XML_ELEMENT_CONTENT_MULT:
00785             xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
00786             xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
00787             break;
00788         case XML_ELEMENT_CONTENT_PLUS:
00789             xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
00790             break;
00791         }
00792         break;
00793     }
00794     default:
00795         xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
00796                     "ContentModel broken for element %s\n",
00797             (const char *) name);
00798         return(0);
00799     }
00800     return(1);
00801 }
00812 int
00813 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
00814 
00815     if ((ctxt == NULL) || (elem == NULL))
00816     return(0);
00817     if (elem->type != XML_ELEMENT_DECL)
00818     return(0);
00819     if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
00820     return(1);
00821     /* TODO: should we rebuild in this case ? */
00822     if (elem->contModel != NULL) {
00823     if (!xmlRegexpIsDeterminist(elem->contModel)) {
00824         ctxt->valid = 0;
00825         return(0);
00826     }
00827     return(1);
00828     }
00829 
00830     ctxt->am = xmlNewAutomata();
00831     if (ctxt->am == NULL) {
00832     xmlErrValidNode(ctxt, (xmlNodePtr) elem,
00833                     XML_ERR_INTERNAL_ERROR,
00834                     "Cannot create automata for element %s\n",
00835                 elem->name, NULL, NULL);
00836     return(0);
00837     }
00838     ctxt->state = xmlAutomataGetInitState(ctxt->am);
00839     xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
00840     xmlAutomataSetFinalState(ctxt->am, ctxt->state);
00841     elem->contModel = xmlAutomataCompile(ctxt->am);
00842     if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
00843     char expr[5000];
00844     expr[0] = 0;
00845     xmlSnprintfElementContent(expr, 5000, elem->content, 1);
00846     xmlErrValidNode(ctxt, (xmlNodePtr) elem,
00847                     XML_DTD_CONTENT_NOT_DETERMINIST,
00848            "Content model of %s is not determinist: %s\n",
00849            elem->name, BAD_CAST expr, NULL);
00850 #ifdef DEBUG_REGEXP_ALGO
00851         xmlRegexpPrint(stderr, elem->contModel);
00852 #endif
00853         ctxt->valid = 0;
00854     ctxt->state = NULL;
00855     xmlFreeAutomata(ctxt->am);
00856     ctxt->am = NULL;
00857     return(0);
00858     }
00859     ctxt->state = NULL;
00860     xmlFreeAutomata(ctxt->am);
00861     ctxt->am = NULL;
00862     return(1);
00863 }
00864 
00865 #endif /* LIBXML_REGEXP_ENABLED */
00866 
00867 /****************************************************************
00868  *                              *
00869  *  Util functions for data allocation/deallocation     *
00870  *                              *
00871  ****************************************************************/
00872 
00880 xmlValidCtxtPtr xmlNewValidCtxt(void) {
00881     xmlValidCtxtPtr ret;
00882 
00883     if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
00884     xmlVErrMemory(NULL, "malloc failed");
00885     return (NULL);
00886     }
00887 
00888     (void) memset(ret, 0, sizeof (xmlValidCtxt));
00889 
00890     return (ret);
00891 }
00892 
00899 void
00900 xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
00901     if (cur->vstateTab != NULL)
00902         xmlFree(cur->vstateTab);
00903     if (cur->nodeTab != NULL)
00904         xmlFree(cur->nodeTab);
00905     xmlFree(cur);
00906 }
00907 
00908 #endif /* LIBXML_VALID_ENABLED */
00909 
00920 xmlElementContentPtr
00921 xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
00922                         xmlElementContentType type) {
00923     xmlElementContentPtr ret;
00924     xmlDictPtr dict = NULL;
00925 
00926     if (doc != NULL)
00927         dict = doc->dict;
00928 
00929     switch(type) {
00930     case XML_ELEMENT_CONTENT_ELEMENT:
00931         if (name == NULL) {
00932             xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
00933             "xmlNewElementContent : name == NULL !\n",
00934             NULL);
00935         }
00936         break;
00937         case XML_ELEMENT_CONTENT_PCDATA:
00938     case XML_ELEMENT_CONTENT_SEQ:
00939     case XML_ELEMENT_CONTENT_OR:
00940         if (name != NULL) {
00941             xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
00942             "xmlNewElementContent : name != NULL !\n",
00943             NULL);
00944         }
00945         break;
00946     default:
00947         xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 
00948             "Internal: ELEMENT content corrupted invalid type\n",
00949             NULL);
00950         return(NULL);
00951     }
00952     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
00953     if (ret == NULL) {
00954     xmlVErrMemory(NULL, "malloc failed");
00955     return(NULL);
00956     }
00957     memset(ret, 0, sizeof(xmlElementContent));
00958     ret->type = type;
00959     ret->ocur = XML_ELEMENT_CONTENT_ONCE;
00960     if (name != NULL) {
00961         int l;
00962     const xmlChar *tmp;
00963 
00964     tmp = xmlSplitQName3(name, &l);
00965     if (tmp == NULL) {
00966         if (dict == NULL)
00967         ret->name = xmlStrdup(name);
00968         else
00969             ret->name = xmlDictLookup(dict, name, -1);
00970     } else {
00971         if (dict == NULL) {
00972         ret->prefix = xmlStrndup(name, l);
00973         ret->name = xmlStrdup(tmp);
00974         } else {
00975             ret->prefix = xmlDictLookup(dict, name, l);
00976         ret->name = xmlDictLookup(dict, tmp, -1);
00977         }
00978     }
00979     }
00980     return(ret);
00981 }
00982 
00993 xmlElementContentPtr
00994 xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
00995     return(xmlNewDocElementContent(NULL, name, type));
00996 }
00997 
01007 xmlElementContentPtr
01008 xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
01009     xmlElementContentPtr ret = NULL, prev = NULL, tmp;
01010     xmlDictPtr dict = NULL;
01011 
01012     if (cur == NULL) return(NULL);
01013 
01014     if (doc != NULL)
01015         dict = doc->dict;
01016 
01017     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
01018     if (ret == NULL) {
01019     xmlVErrMemory(NULL, "malloc failed");
01020     return(NULL);
01021     }
01022     memset(ret, 0, sizeof(xmlElementContent));
01023     ret->type = cur->type;
01024     ret->ocur = cur->ocur;
01025     if (cur->name != NULL) {
01026     if (dict)
01027         ret->name = xmlDictLookup(dict, cur->name, -1);
01028     else
01029         ret->name = xmlStrdup(cur->name);
01030     }
01031     
01032     if (cur->prefix != NULL) {
01033     if (dict)
01034         ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
01035     else
01036         ret->prefix = xmlStrdup(cur->prefix);
01037     }
01038     if (cur->c1 != NULL)
01039         ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
01040     if (ret->c1 != NULL)
01041     ret->c1->parent = ret;
01042     if (cur->c2 != NULL) {
01043         prev = ret;
01044     cur = cur->c2;
01045     while (cur != NULL) {
01046         tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
01047         if (tmp == NULL) {
01048         xmlVErrMemory(NULL, "malloc failed");
01049         return(ret);
01050         }
01051         memset(tmp, 0, sizeof(xmlElementContent));
01052         tmp->type = cur->type;
01053         tmp->ocur = cur->ocur;
01054         prev->c2 = tmp;
01055         if (cur->name != NULL) {
01056         if (dict)
01057             tmp->name = xmlDictLookup(dict, cur->name, -1);
01058         else
01059             tmp->name = xmlStrdup(cur->name);
01060         }
01061         
01062         if (cur->prefix != NULL) {
01063         if (dict)
01064             tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
01065         else
01066             tmp->prefix = xmlStrdup(cur->prefix);
01067         }
01068         if (cur->c1 != NULL)
01069             tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
01070         if (tmp->c1 != NULL)
01071         tmp->c1->parent = ret;
01072         prev = tmp;
01073         cur = cur->c2;
01074     }
01075     }
01076     return(ret);
01077 }
01078 
01088 xmlElementContentPtr
01089 xmlCopyElementContent(xmlElementContentPtr cur) {
01090     return(xmlCopyDocElementContent(NULL, cur));
01091 }
01092 
01100 void
01101 xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
01102     xmlElementContentPtr next;
01103     xmlDictPtr dict = NULL;
01104 
01105     if (doc != NULL)
01106         dict = doc->dict;
01107 
01108     while (cur != NULL) {
01109         next = cur->c2;
01110     switch (cur->type) {
01111         case XML_ELEMENT_CONTENT_PCDATA:
01112         case XML_ELEMENT_CONTENT_ELEMENT:
01113         case XML_ELEMENT_CONTENT_SEQ:
01114         case XML_ELEMENT_CONTENT_OR:
01115         break;
01116         default:
01117         xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 
01118             "Internal: ELEMENT content corrupted invalid type\n",
01119             NULL);
01120         return;
01121     }
01122     if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
01123     if (dict) {
01124         if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
01125             xmlFree((xmlChar *) cur->name);
01126         if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
01127             xmlFree((xmlChar *) cur->prefix);
01128     } else {
01129         if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
01130         if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
01131     }
01132     xmlFree(cur);
01133     cur = next;
01134     }
01135 }
01136 
01144 void
01145 xmlFreeElementContent(xmlElementContentPtr cur) {
01146     xmlFreeDocElementContent(NULL, cur);
01147 }
01148 
01149 #ifdef LIBXML_OUTPUT_ENABLED
01150 
01158 static void
01159 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
01160     if (content == NULL) return;
01161 
01162     if (glob) xmlBufferWriteChar(buf, "(");
01163     switch (content->type) {
01164         case XML_ELEMENT_CONTENT_PCDATA:
01165             xmlBufferWriteChar(buf, "#PCDATA");
01166         break;
01167     case XML_ELEMENT_CONTENT_ELEMENT:
01168         if (content->prefix != NULL) {
01169         xmlBufferWriteCHAR(buf, content->prefix);
01170         xmlBufferWriteChar(buf, ":");
01171         }
01172         xmlBufferWriteCHAR(buf, content->name);
01173         break;
01174     case XML_ELEMENT_CONTENT_SEQ:
01175         if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
01176             (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
01177         xmlDumpElementContent(buf, content->c1, 1);
01178         else
01179         xmlDumpElementContent(buf, content->c1, 0);
01180             xmlBufferWriteChar(buf, " , ");
01181         if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
01182             ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
01183          (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
01184         xmlDumpElementContent(buf, content->c2, 1);
01185         else
01186         xmlDumpElementContent(buf, content->c2, 0);
01187         break;
01188     case XML_ELEMENT_CONTENT_OR:
01189         if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
01190             (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
01191         xmlDumpElementContent(buf, content->c1, 1);
01192         else
01193         xmlDumpElementContent(buf, content->c1, 0);
01194             xmlBufferWriteChar(buf, " | ");
01195         if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
01196             ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
01197          (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
01198         xmlDumpElementContent(buf, content->c2, 1);
01199         else
01200         xmlDumpElementContent(buf, content->c2, 0);
01201         break;
01202     default:
01203         xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 
01204             "Internal: ELEMENT content corrupted invalid type\n",
01205             NULL);
01206     }
01207     if (glob)
01208         xmlBufferWriteChar(buf, ")");
01209     switch (content->ocur) {
01210         case XML_ELEMENT_CONTENT_ONCE:
01211         break;
01212         case XML_ELEMENT_CONTENT_OPT:
01213         xmlBufferWriteChar(buf, "?");
01214         break;
01215         case XML_ELEMENT_CONTENT_MULT:
01216         xmlBufferWriteChar(buf, "*");
01217         break;
01218         case XML_ELEMENT_CONTENT_PLUS:
01219         xmlBufferWriteChar(buf, "+");
01220         break;
01221     }
01222 }
01223 
01232 void
01233 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
01234                      xmlElementContentPtr content ATTRIBUTE_UNUSED,
01235              int englob ATTRIBUTE_UNUSED) {
01236 }
01237 #endif /* LIBXML_OUTPUT_ENABLED */
01238 
01249 void
01250 xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
01251     int len;
01252 
01253     if (content == NULL) return;
01254     len = strlen(buf);
01255     if (size - len < 50) {
01256     if ((size - len > 4) && (buf[len - 1] != '.'))
01257         strcat(buf, " ...");
01258     return;
01259     }
01260     if (englob) strcat(buf, "(");
01261     switch (content->type) {
01262         case XML_ELEMENT_CONTENT_PCDATA:
01263             strcat(buf, "#PCDATA");
01264         break;
01265     case XML_ELEMENT_CONTENT_ELEMENT:
01266         if (content->prefix != NULL) {
01267         if (size - len < xmlStrlen(content->prefix) + 10) {
01268             strcat(buf, " ...");
01269             return;
01270         }
01271         strcat(buf, (char *) content->prefix);
01272         strcat(buf, ":");
01273         }
01274         if (size - len < xmlStrlen(content->name) + 10) {
01275         strcat(buf, " ...");
01276         return;
01277         }
01278         if (content->name != NULL)
01279         strcat(buf, (char *) content->name);
01280         break;
01281     case XML_ELEMENT_CONTENT_SEQ:
01282         if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
01283             (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
01284         xmlSnprintfElementContent(buf, size, content->c1, 1);
01285         else
01286         xmlSnprintfElementContent(buf, size, content->c1, 0);
01287         len = strlen(buf);
01288         if (size - len < 50) {
01289         if ((size - len > 4) && (buf[len - 1] != '.'))
01290             strcat(buf, " ...");
01291         return;
01292         }
01293             strcat(buf, " , ");
01294         if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
01295          (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
01296         (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
01297         xmlSnprintfElementContent(buf, size, content->c2, 1);
01298         else
01299         xmlSnprintfElementContent(buf, size, content->c2, 0);
01300         break;
01301     case XML_ELEMENT_CONTENT_OR:
01302         if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
01303             (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
01304         xmlSnprintfElementContent(buf, size, content->c1, 1);
01305         else
01306         xmlSnprintfElementContent(buf, size, content->c1, 0);
01307         len = strlen(buf);
01308         if (size - len < 50) {
01309         if ((size - len > 4) && (buf[len - 1] != '.'))
01310             strcat(buf, " ...");
01311         return;
01312         }
01313             strcat(buf, " | ");
01314         if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
01315          (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
01316         (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
01317         xmlSnprintfElementContent(buf, size, content->c2, 1);
01318         else
01319         xmlSnprintfElementContent(buf, size, content->c2, 0);
01320         break;
01321     }
01322     if (englob)
01323         strcat(buf, ")");
01324     switch (content->ocur) {
01325         case XML_ELEMENT_CONTENT_ONCE:
01326         break;
01327         case XML_ELEMENT_CONTENT_OPT:
01328         strcat(buf, "?");
01329         break;
01330         case XML_ELEMENT_CONTENT_MULT:
01331         strcat(buf, "*");
01332         break;
01333         case XML_ELEMENT_CONTENT_PLUS:
01334         strcat(buf, "+");
01335         break;
01336     }
01337 }
01338 
01339 /****************************************************************
01340  *                              *
01341  *  Registration of DTD declarations            *
01342  *                              *
01343  ****************************************************************/
01344 
01351 static void
01352 xmlFreeElement(xmlElementPtr elem) {
01353     if (elem == NULL) return;
01354     xmlUnlinkNode((xmlNodePtr) elem);
01355     xmlFreeDocElementContent(elem->doc, elem->content);
01356     if (elem->name != NULL)
01357     xmlFree((xmlChar *) elem->name);
01358     if (elem->prefix != NULL)
01359     xmlFree((xmlChar *) elem->prefix);
01360 #ifdef LIBXML_REGEXP_ENABLED
01361     if (elem->contModel != NULL)
01362     xmlRegFreeRegexp(elem->contModel);
01363 #endif
01364     xmlFree(elem);
01365 }
01366 
01367 
01380 xmlElementPtr
01381 xmlAddElementDecl(xmlValidCtxtPtr ctxt,
01382                   xmlDtdPtr dtd, const xmlChar *name,
01383                   xmlElementTypeVal type,
01384           xmlElementContentPtr content) {
01385     xmlElementPtr ret;
01386     xmlElementTablePtr table;
01387     xmlAttributePtr oldAttributes = NULL;
01388     xmlChar *ns, *uqname;
01389 
01390     if (dtd == NULL) {
01391     return(NULL);
01392     }
01393     if (name == NULL) {
01394     return(NULL);
01395     }
01396 
01397     switch (type) {
01398         case XML_ELEMENT_TYPE_EMPTY:
01399         if (content != NULL) {
01400         xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 
01401                 "xmlAddElementDecl: content != NULL for EMPTY\n",
01402             NULL);
01403         return(NULL);
01404         }
01405         break;
01406     case XML_ELEMENT_TYPE_ANY:
01407         if (content != NULL) {
01408         xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 
01409                 "xmlAddElementDecl: content != NULL for ANY\n",
01410             NULL);
01411         return(NULL);
01412         }
01413         break;
01414     case XML_ELEMENT_TYPE_MIXED:
01415         if (content == NULL) {
01416         xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 
01417                 "xmlAddElementDecl: content == NULL for MIXED\n",
01418             NULL);
01419         return(NULL);
01420         }
01421         break;
01422     case XML_ELEMENT_TYPE_ELEMENT:
01423         if (content == NULL) {
01424         xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 
01425                 "xmlAddElementDecl: content == NULL for ELEMENT\n",
01426             NULL);
01427         return(NULL);
01428         }
01429         break;
01430     default:
01431         xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 
01432             "Internal: ELEMENT decl corrupted invalid type\n",
01433             NULL);
01434         return(NULL);
01435     }
01436 
01437     /*
01438      * check if name is a QName
01439      */
01440     uqname = xmlSplitQName2(name, &ns);
01441     if (uqname != NULL)
01442     name = uqname;
01443 
01444     /*
01445      * Create the Element table if needed.
01446      */
01447     table = (xmlElementTablePtr) dtd->elements;
01448     if (table == NULL) {
01449     xmlDictPtr dict = NULL;
01450 
01451     if (dtd->doc != NULL)
01452         dict = dtd->doc->dict;
01453         table = xmlHashCreateDict(0, dict);
01454     dtd->elements = (void *) table;
01455     }
01456     if (table == NULL) {
01457     xmlVErrMemory(ctxt,
01458             "xmlAddElementDecl: Table creation failed!\n");
01459     if (uqname != NULL)
01460         xmlFree(uqname);
01461     if (ns != NULL)
01462         xmlFree(ns);
01463         return(NULL);
01464     }
01465 
01466     /*
01467      * lookup old attributes inserted on an undefined element in the
01468      * internal subset.
01469      */
01470     if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
01471     ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
01472     if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
01473         oldAttributes = ret->attributes;
01474         ret->attributes = NULL;
01475         xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
01476         xmlFreeElement(ret);
01477     }
01478     }
01479 
01480     /*
01481      * The element may already be present if one of its attribute
01482      * was registered first
01483      */
01484     ret = xmlHashLookup2(table, name, ns);
01485     if (ret != NULL) {
01486     if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
01487 #ifdef LIBXML_VALID_ENABLED
01488         /*
01489          * The element is already defined in this DTD.
01490          */
01491         xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
01492                         "Redefinition of element %s\n",
01493                 name, NULL, NULL);
01494 #endif /* LIBXML_VALID_ENABLED */
01495         if (uqname != NULL)
01496         xmlFree(uqname);
01497             if (ns != NULL)
01498             xmlFree(ns);
01499         return(NULL);
01500     }
01501     if (ns != NULL) {
01502         xmlFree(ns);
01503         ns = NULL;
01504     }
01505     } else {
01506     ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
01507     if (ret == NULL) {
01508         xmlVErrMemory(ctxt, "malloc failed");
01509         if (uqname != NULL)
01510         xmlFree(uqname);
01511             if (ns != NULL)
01512             xmlFree(ns);
01513         return(NULL);
01514     }
01515     memset(ret, 0, sizeof(xmlElement));
01516     ret->type = XML_ELEMENT_DECL;
01517 
01518     /*
01519      * fill the structure.
01520      */
01521     ret->name = xmlStrdup(name);
01522     if (ret->name == NULL) {
01523         xmlVErrMemory(ctxt, "malloc failed");
01524         if (uqname != NULL)
01525         xmlFree(uqname);
01526             if (ns != NULL)
01527             xmlFree(ns);
01528         xmlFree(ret);
01529         return(NULL);
01530     }
01531     ret->prefix = ns;
01532 
01533     /*
01534      * Validity Check:
01535      * Insertion must not fail
01536      */
01537     if (xmlHashAddEntry2(table, name, ns, ret)) {
01538 #ifdef LIBXML_VALID_ENABLED
01539         /*
01540          * The element is already defined in this DTD.
01541          */
01542         xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
01543                         "Redefinition of element %s\n",
01544                 name, NULL, NULL);
01545 #endif /* LIBXML_VALID_ENABLED */
01546         xmlFreeElement(ret);
01547         if (uqname != NULL)
01548         xmlFree(uqname);
01549         return(NULL);
01550     }
01551     /*
01552      * For new element, may have attributes from earlier
01553      * definition in internal subset
01554      */
01555     ret->attributes = oldAttributes;
01556     }
01557 
01558     /*
01559      * Finish to fill the structure.
01560      */
01561     ret->etype = type;
01562     /*
01563      * Avoid a stupid copy when called by the parser
01564      * and flag it by setting a special parent value
01565      * so the parser doesn't unallocate it.
01566      */
01567     if ((ctxt != NULL) &&
01568         ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
01569          (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
01570     ret->content = content;
01571     if (content != NULL)
01572         content->parent = (xmlElementContentPtr) 1;
01573     } else {
01574     ret->content = xmlCopyDocElementContent(dtd->doc, content);
01575     }
01576 
01577     /*
01578      * Link it to the DTD
01579      */
01580     ret->parent = dtd;
01581     ret->doc = dtd->doc;
01582     if (dtd->last == NULL) {
01583     dtd->children = dtd->last = (xmlNodePtr) ret;
01584     } else {
01585         dtd->last->next = (xmlNodePtr) ret;
01586     ret->prev = dtd->last;
01587     dtd->last = (xmlNodePtr) ret;
01588     }
01589     if (uqname != NULL)
01590     xmlFree(uqname);
01591     return(ret);
01592 }
01593 
01600 void
01601 xmlFreeElementTable(xmlElementTablePtr table) {
01602     xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
01603 }
01604 
01605 #ifdef LIBXML_TREE_ENABLED
01606 
01614 static xmlElementPtr
01615 xmlCopyElement(xmlElementPtr elem) {
01616     xmlElementPtr cur;
01617 
01618     cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
01619     if (cur == NULL) {
01620     xmlVErrMemory(NULL, "malloc failed");
01621     return(NULL);
01622     }
01623     memset(cur, 0, sizeof(xmlElement));
01624     cur->type = XML_ELEMENT_DECL;
01625     cur->etype = elem->etype;
01626     if (elem->name != NULL)
01627     cur->name = xmlStrdup(elem->name);
01628     else
01629     cur->name = NULL;
01630     if (elem->prefix != NULL)
01631     cur->prefix = xmlStrdup(elem->prefix);
01632     else
01633     cur->prefix = NULL;
01634     cur->content = xmlCopyElementContent(elem->content);
01635     /* TODO : rebuild the attribute list on the copy */
01636     cur->attributes = NULL;
01637     return(cur);
01638 }
01639 
01648 xmlElementTablePtr
01649 xmlCopyElementTable(xmlElementTablePtr table) {
01650     return((xmlElementTablePtr) xmlHashCopy(table,
01651                                     (xmlHashCopier) xmlCopyElement));
01652 }
01653 #endif /* LIBXML_TREE_ENABLED */
01654 
01655 #ifdef LIBXML_OUTPUT_ENABLED
01656 
01664 void
01665 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
01666     if ((buf == NULL) || (elem == NULL))
01667         return;
01668     switch (elem->etype) {
01669     case XML_ELEMENT_TYPE_EMPTY:
01670         xmlBufferWriteChar(buf, "<!ELEMENT ");
01671         if (elem->prefix != NULL) {
01672         xmlBufferWriteCHAR(buf, elem->prefix);
01673         xmlBufferWriteChar(buf, ":");
01674         }
01675         xmlBufferWriteCHAR(buf, elem->name);
01676         xmlBufferWriteChar(buf, " EMPTY>\n");
01677         break;
01678     case XML_ELEMENT_TYPE_ANY:
01679         xmlBufferWriteChar(buf, "<!ELEMENT ");
01680         if (elem->prefix != NULL) {
01681         xmlBufferWriteCHAR(buf, elem->prefix);
01682         xmlBufferWriteChar(buf, ":");
01683         }
01684         xmlBufferWriteCHAR(buf, elem->name);
01685         xmlBufferWriteChar(buf, " ANY>\n");
01686         break;
01687     case XML_ELEMENT_TYPE_MIXED:
01688         xmlBufferWriteChar(buf, "<!ELEMENT ");
01689         if (elem->prefix != NULL) {
01690         xmlBufferWriteCHAR(buf, elem->prefix);
01691         xmlBufferWriteChar(buf, ":");
01692         }
01693         xmlBufferWriteCHAR(buf, elem->name);
01694         xmlBufferWriteChar(buf, " ");
01695         xmlDumpElementContent(buf, elem->content, 1);
01696         xmlBufferWriteChar(buf, ">\n");
01697         break;
01698     case XML_ELEMENT_TYPE_ELEMENT:
01699         xmlBufferWriteChar(buf, "<!ELEMENT ");
01700         if (elem->prefix != NULL) {
01701         xmlBufferWriteCHAR(buf, elem->prefix);
01702         xmlBufferWriteChar(buf, ":");
01703         }
01704         xmlBufferWriteCHAR(buf, elem->name);
01705         xmlBufferWriteChar(buf, " ");
01706         xmlDumpElementContent(buf, elem->content, 1);
01707         xmlBufferWriteChar(buf, ">\n");
01708         break;
01709     default:
01710         xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 
01711             "Internal: ELEMENT struct corrupted invalid type\n",
01712             NULL);
01713     }
01714 }
01715 
01724 static void
01725 xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
01726     xmlDumpElementDecl(buf, elem);
01727 }
01728 
01736 void
01737 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
01738     if ((buf == NULL) || (table == NULL))
01739         return;
01740     xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
01741 }
01742 #endif /* LIBXML_OUTPUT_ENABLED */
01743 
01753 xmlEnumerationPtr
01754 xmlCreateEnumeration(const xmlChar *name) {
01755     xmlEnumerationPtr ret;
01756 
01757     ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
01758     if (ret == NULL) {
01759     xmlVErrMemory(NULL, "malloc failed");
01760         return(NULL);
01761     }
01762     memset(ret, 0, sizeof(xmlEnumeration));
01763 
01764     if (name != NULL)
01765         ret->name = xmlStrdup(name);
01766     return(ret);
01767 }
01768 
01775 void
01776 xmlFreeEnumeration(xmlEnumerationPtr cur) {
01777     if (cur == NULL) return;
01778 
01779     if (cur->next != NULL) xmlFreeEnumeration(cur->next);
01780 
01781     if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
01782     xmlFree(cur);
01783 }
01784 
01785 #ifdef LIBXML_TREE_ENABLED
01786 
01795 xmlEnumerationPtr
01796 xmlCopyEnumeration(xmlEnumerationPtr cur) {
01797     xmlEnumerationPtr ret;
01798 
01799     if (cur == NULL) return(NULL);
01800     ret = xmlCreateEnumeration((xmlChar *) cur->name);
01801 
01802     if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
01803     else ret->next = NULL;
01804 
01805     return(ret);
01806 }
01807 #endif /* LIBXML_TREE_ENABLED */
01808 
01809 #ifdef LIBXML_OUTPUT_ENABLED
01810 
01817 static void
01818 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
01819     if ((buf == NULL) || (cur == NULL))
01820         return;
01821     
01822     xmlBufferWriteCHAR(buf, cur->name);
01823     if (cur->next == NULL)
01824     xmlBufferWriteChar(buf, ")");
01825     else {
01826     xmlBufferWriteChar(buf, " | ");
01827     xmlDumpEnumeration(buf, cur->next);
01828     }
01829 }
01830 #endif /* LIBXML_OUTPUT_ENABLED */
01831 
01832 #ifdef LIBXML_VALID_ENABLED
01833 
01844 static int
01845 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
01846     xmlAttributePtr cur;
01847     int ret = 0;
01848 
01849     if (elem == NULL) return(0);
01850     cur = elem->attributes;
01851     while (cur != NULL) {
01852         if (cur->atype == XML_ATTRIBUTE_ID) {
01853         ret ++;
01854         if ((ret > 1) && (err))
01855         xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
01856            "Element %s has too many ID attributes defined : %s\n",
01857                elem->name, cur->name, NULL);
01858     }
01859     cur = cur->nexth;
01860     }
01861     return(ret);
01862 }
01863 #endif /* LIBXML_VALID_ENABLED */
01864 
01871 static void
01872 xmlFreeAttribute(xmlAttributePtr attr) {
01873     xmlDictPtr dict;
01874 
01875     if (attr == NULL) return;
01876     if (attr->doc != NULL)
01877     dict = attr->doc->dict;
01878     else
01879     dict = NULL;
01880     xmlUnlinkNode((xmlNodePtr) attr);
01881     if (attr->tree != NULL)
01882         xmlFreeEnumeration(attr->tree);
01883     if (dict) {
01884         if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
01885         xmlFree((xmlChar *) attr->elem);
01886         if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
01887         xmlFree((xmlChar *) attr->name);
01888         if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
01889         xmlFree((xmlChar *) attr->prefix);
01890         if ((attr->defaultValue != NULL) &&
01891         (!xmlDictOwns(dict, attr->defaultValue)))
01892         xmlFree((xmlChar *) attr->defaultValue);
01893     } else {
01894     if (attr->elem != NULL)
01895         xmlFree((xmlChar *) attr->elem);
01896     if (attr->name != NULL)
01897         xmlFree((xmlChar *) attr->name);
01898     if (attr->defaultValue != NULL)
01899         xmlFree((xmlChar *) attr->defaultValue);
01900     if (attr->prefix != NULL)
01901         xmlFree((xmlChar *) attr->prefix);
01902     }
01903     xmlFree(attr);
01904 }
01905 
01906 
01924 xmlAttributePtr
01925 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
01926                     xmlDtdPtr dtd, const xmlChar *elem,
01927                     const xmlChar *name, const xmlChar *ns,
01928             xmlAttributeType type, xmlAttributeDefault def,
01929             const xmlChar *defaultValue, xmlEnumerationPtr tree) {
01930     xmlAttributePtr ret;
01931     xmlAttributeTablePtr table;
01932     xmlElementPtr elemDef;
01933     xmlDictPtr dict = NULL;
01934 
01935     if (dtd == NULL) {
01936     xmlFreeEnumeration(tree);
01937     return(NULL);
01938     }
01939     if (name == NULL) {
01940     xmlFreeEnumeration(tree);
01941     return(NULL);
01942     }
01943     if (elem == NULL) {
01944     xmlFreeEnumeration(tree);
01945     return(NULL);
01946     }
01947     if (dtd->doc != NULL)
01948     dict = dtd->doc->dict;
01949 
01950 #ifdef LIBXML_VALID_ENABLED
01951     /*
01952      * Check the type and possibly the default value.
01953      */
01954     switch (type) {
01955         case XML_ATTRIBUTE_CDATA:
01956         break;
01957         case XML_ATTRIBUTE_ID:
01958         break;
01959         case XML_ATTRIBUTE_IDREF:
01960         break;
01961         case XML_ATTRIBUTE_IDREFS:
01962         break;
01963         case XML_ATTRIBUTE_ENTITY:
01964         break;
01965         case XML_ATTRIBUTE_ENTITIES:
01966         break;
01967         case XML_ATTRIBUTE_NMTOKEN:
01968         break;
01969         case XML_ATTRIBUTE_NMTOKENS:
01970         break;
01971         case XML_ATTRIBUTE_ENUMERATION:
01972         break;
01973         case XML_ATTRIBUTE_NOTATION:
01974         break;
01975     default:
01976         xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 
01977             "Internal: ATTRIBUTE struct corrupted invalid type\n",
01978             NULL);
01979         xmlFreeEnumeration(tree);
01980         return(NULL);
01981     }
01982     if ((defaultValue != NULL) && 
01983         (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
01984     xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
01985                     "Attribute %s of %s: invalid default value\n",
01986                     elem, name, defaultValue);
01987     defaultValue = NULL;
01988     if (ctxt != NULL)
01989         ctxt->valid = 0;
01990     }
01991 #endif /* LIBXML_VALID_ENABLED */
01992 
01993     /*
01994      * Check first that an attribute defined in the external subset wasn't
01995      * already defined in the internal subset
01996      */
01997     if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
01998     (dtd->doc->intSubset != NULL) &&
01999     (dtd->doc->intSubset->attributes != NULL)) {
02000         ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
02001     if (ret != NULL) {
02002         xmlFreeEnumeration(tree);
02003         return(NULL);
02004     }
02005     }
02006 
02007     /*
02008      * Create the Attribute table if needed.
02009      */
02010     table = (xmlAttributeTablePtr) dtd->attributes;
02011     if (table == NULL) {
02012         table = xmlHashCreateDict(0, dict);
02013     dtd->attributes = (void *) table;
02014     }
02015     if (table == NULL) {
02016     xmlVErrMemory(ctxt,
02017             "xmlAddAttributeDecl: Table creation failed!\n");
02018     xmlFreeEnumeration(tree);
02019         return(NULL);
02020     }
02021 
02022 
02023     ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
02024     if (ret == NULL) {
02025     xmlVErrMemory(ctxt, "malloc failed");
02026     xmlFreeEnumeration(tree);
02027     return(NULL);
02028     }
02029     memset(ret, 0, sizeof(xmlAttribute));
02030     ret->type = XML_ATTRIBUTE_DECL;
02031 
02032     /*
02033      * fill the structure.
02034      */
02035     ret->atype = type;
02036     /*
02037      * doc must be set before possible error causes call
02038      * to xmlFreeAttribute (because it's used to check on
02039      * dict use)
02040      */
02041     ret->doc = dtd->doc;
02042     if (dict) {
02043     ret->name = xmlDictLookup(dict, name, -1);
02044     ret->prefix = xmlDictLookup(dict, ns, -1);
02045     ret->elem = xmlDictLookup(dict, elem, -1);
02046     } else {
02047     ret->name = xmlStrdup(name);
02048     ret->prefix = xmlStrdup(ns);
02049     ret->elem = xmlStrdup(elem);
02050     }
02051     ret->def = def;
02052     ret->tree = tree;
02053     if (defaultValue != NULL) {
02054         if (dict)
02055         ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
02056     else
02057         ret->defaultValue = xmlStrdup(defaultValue);
02058     }
02059 
02060     /*
02061      * Validity Check:
02062      * Search the DTD for previous declarations of the ATTLIST
02063      */
02064     if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
02065 #ifdef LIBXML_VALID_ENABLED
02066     /*
02067      * The attribute is already defined in this DTD.
02068      */
02069     xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
02070          "Attribute %s of element %s: already defined\n",
02071          name, elem, NULL);
02072 #endif /* LIBXML_VALID_ENABLED */
02073     xmlFreeAttribute(ret);
02074     return(NULL);
02075     }
02076 
02077     /*
02078      * Validity Check:
02079      * Multiple ID per element
02080      */
02081     elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
02082     if (elemDef != NULL) {
02083 
02084 #ifdef LIBXML_VALID_ENABLED
02085         if ((type == XML_ATTRIBUTE_ID) &&
02086         (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
02087         xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
02088        "Element %s has too may ID attributes defined : %s\n",
02089            elem, name, NULL);
02090         if (ctxt != NULL)
02091         ctxt->valid = 0;
02092     }
02093 #endif /* LIBXML_VALID_ENABLED */
02094 
02095     /*
02096      * Insert namespace default def first they need to be
02097      * processed first.
02098      */
02099     if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
02100         ((ret->prefix != NULL &&
02101          (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
02102         ret->nexth = elemDef->attributes;
02103         elemDef->attributes = ret;
02104     } else {
02105         xmlAttributePtr tmp = elemDef->attributes;
02106 
02107         while ((tmp != NULL) &&
02108            ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
02109             ((ret->prefix != NULL &&
02110              (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
02111         if (tmp->nexth == NULL)
02112             break;
02113         tmp = tmp->nexth;
02114         }
02115         if (tmp != NULL) {
02116         ret->nexth = tmp->nexth;
02117             tmp->nexth = ret;
02118         } else {
02119         ret->nexth = elemDef->attributes;
02120         elemDef->attributes = ret;
02121         }
02122     }
02123     }
02124 
02125     /*
02126      * Link it to the DTD
02127      */
02128     ret->parent = dtd;
02129     if (dtd->last == NULL) {
02130     dtd->children = dtd->last = (xmlNodePtr) ret;
02131     } else {
02132         dtd->last->next = (xmlNodePtr) ret;
02133     ret->prev = dtd->last;
02134     dtd->last = (xmlNodePtr) ret;
02135     }
02136     return(ret);
02137 }
02138 
02145 void
02146 xmlFreeAttributeTable(xmlAttributeTablePtr table) {
02147     xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
02148 }
02149 
02150 #ifdef LIBXML_TREE_ENABLED
02151 
02159 static xmlAttributePtr
02160 xmlCopyAttribute(xmlAttributePtr attr) {
02161     xmlAttributePtr cur;
02162 
02163     cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
02164     if (cur == NULL) {
02165     xmlVErrMemory(NULL, "malloc failed");
02166     return(NULL);
02167     }
02168     memset(cur, 0, sizeof(xmlAttribute));
02169     cur->type = XML_ATTRIBUTE_DECL;
02170     cur->atype = attr->atype;
02171     cur->def = attr->def;
02172     cur->tree = xmlCopyEnumeration(attr->tree);
02173     if (attr->elem != NULL)
02174     cur->elem = xmlStrdup(attr->elem);
02175     if (attr->name != NULL)
02176     cur->name = xmlStrdup(attr->name);
02177     if (attr->prefix != NULL)
02178     cur->prefix = xmlStrdup(attr->prefix);
02179     if (attr->defaultValue != NULL)
02180     cur->defaultValue = xmlStrdup(attr->defaultValue);
02181     return(cur);
02182 }
02183 
02192 xmlAttributeTablePtr
02193 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
02194     return((xmlAttributeTablePtr) xmlHashCopy(table,
02195                     (xmlHashCopier) xmlCopyAttribute));
02196 }
02197 #endif /* LIBXML_TREE_ENABLED */
02198 
02199 #ifdef LIBXML_OUTPUT_ENABLED
02200 
02208 void
02209 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
02210     if ((buf == NULL) || (attr == NULL))
02211         return;
02212     xmlBufferWriteChar(buf, "<!ATTLIST ");
02213     xmlBufferWriteCHAR(buf, attr->elem);
02214     xmlBufferWriteChar(buf, " ");
02215     if (attr->prefix != NULL) {
02216     xmlBufferWriteCHAR(buf, attr->prefix);
02217     xmlBufferWriteChar(buf, ":");
02218     }
02219     xmlBufferWriteCHAR(buf, attr->name);
02220     switch (attr->atype) {
02221     case XML_ATTRIBUTE_CDATA:
02222         xmlBufferWriteChar(buf, " CDATA");
02223         break;
02224     case XML_ATTRIBUTE_ID:
02225         xmlBufferWriteChar(buf, " ID");
02226         break;
02227     case XML_ATTRIBUTE_IDREF:
02228         xmlBufferWriteChar(buf, " IDREF");
02229         break;
02230     case XML_ATTRIBUTE_IDREFS:
02231         xmlBufferWriteChar(buf, " IDREFS");
02232         break;
02233     case XML_ATTRIBUTE_ENTITY:
02234         xmlBufferWriteChar(buf, " ENTITY");
02235         break;
02236     case XML_ATTRIBUTE_ENTITIES:
02237         xmlBufferWriteChar(buf, " ENTITIES");
02238         break;
02239     case XML_ATTRIBUTE_NMTOKEN:
02240         xmlBufferWriteChar(buf, " NMTOKEN");
02241         break;
02242     case XML_ATTRIBUTE_NMTOKENS:
02243         xmlBufferWriteChar(buf, " NMTOKENS");
02244         break;
02245     case XML_ATTRIBUTE_ENUMERATION:
02246         xmlBufferWriteChar(buf, " (");
02247         xmlDumpEnumeration(buf, attr->tree);
02248         break;
02249     case XML_ATTRIBUTE_NOTATION:
02250         xmlBufferWriteChar(buf, " NOTATION (");
02251         xmlDumpEnumeration(buf, attr->tree);
02252         break;
02253     default:
02254         xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 
02255             "Internal: ATTRIBUTE struct corrupted invalid type\n",
02256             NULL);
02257     }
02258     switch (attr->def) {
02259     case XML_ATTRIBUTE_NONE:
02260         break;
02261     case XML_ATTRIBUTE_REQUIRED:
02262         xmlBufferWriteChar(buf, " #REQUIRED");
02263         break;
02264     case XML_ATTRIBUTE_IMPLIED:
02265         xmlBufferWriteChar(buf, " #IMPLIED");
02266         break;
02267     case XML_ATTRIBUTE_FIXED:
02268         xmlBufferWriteChar(buf, " #FIXED");
02269         break;
02270     default:
02271         xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, 
02272             "Internal: ATTRIBUTE struct corrupted invalid def\n",
02273             NULL);
02274     }
02275     if (attr->defaultValue != NULL) {
02276     xmlBufferWriteChar(buf, " ");
02277     xmlBufferWriteQuotedString(buf, attr->defaultValue);
02278     }
02279     xmlBufferWriteChar(buf, ">\n");
02280 }
02281 
02289 static void
02290 xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
02291     xmlDumpAttributeDecl(buf, attr);
02292 }
02293 
02301 void
02302 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
02303     if ((buf == NULL) || (table == NULL))
02304         return;
02305     xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
02306 }
02307 #endif /* LIBXML_OUTPUT_ENABLED */
02308 
02309 /************************************************************************
02310  *                                  *
02311  *              NOTATIONs               *
02312  *                                  *
02313  ************************************************************************/
02320 static void
02321 xmlFreeNotation(xmlNotationPtr nota) {
02322     if (nota == NULL) return;
02323     if (nota->name != NULL)
02324     xmlFree((xmlChar *) nota->name);
02325     if (nota->PublicID != NULL)
02326     xmlFree((xmlChar *) nota->PublicID);
02327     if (nota->SystemID != NULL)
02328     xmlFree((xmlChar *) nota->SystemID);
02329     xmlFree(nota);
02330 }
02331 
02332 
02345 xmlNotationPtr
02346 xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
02347                const xmlChar *name,
02348                    const xmlChar *PublicID, const xmlChar *SystemID) {
02349     xmlNotationPtr ret;
02350     xmlNotationTablePtr table;
02351 
02352     if (dtd == NULL) {
02353     return(NULL);
02354     }
02355     if (name == NULL) {
02356     return(NULL);
02357     }
02358     if ((PublicID == NULL) && (SystemID == NULL)) {
02359     return(NULL);
02360     }
02361 
02362     /*
02363      * Create the Notation table if needed.
02364      */
02365     table = (xmlNotationTablePtr) dtd->notations;
02366     if (table == NULL) {
02367     xmlDictPtr dict = NULL;
02368     if (dtd->doc != NULL)
02369         dict = dtd->doc->dict;
02370 
02371         dtd->notations = table = xmlHashCreateDict(0, dict);
02372     }
02373     if (table == NULL) {
02374     xmlVErrMemory(ctxt,
02375         "xmlAddNotationDecl: Table creation failed!\n");
02376         return(NULL);
02377     }
02378 
02379     ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
02380     if (ret == NULL) {
02381     xmlVErrMemory(ctxt, "malloc failed");
02382     return(NULL);
02383     }
02384     memset(ret, 0, sizeof(xmlNotation));
02385 
02386     /*
02387      * fill the structure.
02388      */
02389     ret->name = xmlStrdup(name);
02390     if (SystemID != NULL)
02391         ret->SystemID = xmlStrdup(SystemID);
02392     if (PublicID != NULL)
02393         ret->PublicID = xmlStrdup(PublicID);
02394 
02395     /*
02396      * Validity Check:
02397      * Check the DTD for previous declarations of the ATTLIST
02398      */
02399     if (xmlHashAddEntry(table, name, ret)) {
02400 #ifdef LIBXML_VALID_ENABLED
02401     xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED, 
02402             "xmlAddNotationDecl: %s already defined\n",
02403             (const char *) name);
02404 #endif /* LIBXML_VALID_ENABLED */
02405     xmlFreeNotation(ret);
02406     return(NULL);
02407     }
02408     return(ret);
02409 }
02410 
02417 void
02418 xmlFreeNotationTable(xmlNotationTablePtr table) {
02419     xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
02420 }
02421 
02422 #ifdef LIBXML_TREE_ENABLED
02423 
02431 static xmlNotationPtr
02432 xmlCopyNotation(xmlNotationPtr nota) {
02433     xmlNotationPtr cur;
02434 
02435     cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
02436     if (cur == NULL) {
02437     xmlVErrMemory(NULL, "malloc failed");
02438     return(NULL);
02439     }
02440     if (nota->name != NULL)
02441     cur->name = xmlStrdup(nota->name);
02442     else
02443     cur->name = NULL;
02444     if (nota->PublicID != NULL)
02445     cur->PublicID = xmlStrdup(nota->PublicID);
02446     else
02447     cur->PublicID = NULL;
02448     if (nota->SystemID != NULL)
02449     cur->SystemID = xmlStrdup(nota->SystemID);
02450     else
02451     cur->SystemID = NULL;
02452     return(cur);
02453 }
02454 
02463 xmlNotationTablePtr
02464 xmlCopyNotationTable(xmlNotationTablePtr table) {
02465     return((xmlNotationTablePtr) xmlHashCopy(table,
02466                     (xmlHashCopier) xmlCopyNotation));
02467 }
02468 #endif /* LIBXML_TREE_ENABLED */
02469 
02470 #ifdef LIBXML_OUTPUT_ENABLED
02471 
02478 void
02479 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
02480     if ((buf == NULL) || (nota == NULL))
02481         return;
02482     xmlBufferWriteChar(buf, "<!NOTATION ");
02483     xmlBufferWriteCHAR(buf, nota->name);
02484     if (nota->PublicID != NULL) {
02485     xmlBufferWriteChar(buf, " PUBLIC ");
02486     xmlBufferWriteQuotedString(buf, nota->PublicID);
02487     if (nota->SystemID != NULL) {
02488         xmlBufferWriteChar(buf, " ");
02489         xmlBufferWriteQuotedString(buf, nota->SystemID);
02490     }
02491     } else {
02492     xmlBufferWriteChar(buf, " SYSTEM ");
02493     xmlBufferWriteQuotedString(buf, nota->SystemID);
02494     }
02495     xmlBufferWriteChar(buf, " >\n");
02496 }
02497 
02505 static void
02506 xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
02507     xmlDumpNotationDecl(buf, nota);
02508 }
02509 
02517 void
02518 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
02519     if ((buf == NULL) || (table == NULL))
02520         return;
02521     xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
02522 }
02523 #endif /* LIBXML_OUTPUT_ENABLED */
02524 
02525 /************************************************************************
02526  *                                  *
02527  *              IDs                 *
02528  *                                  *
02529  ************************************************************************/
02537 #define DICT_FREE(str)                      \
02538     if ((str) && ((!dict) ||                \
02539         (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))  \
02540         xmlFree((char *)(str));
02541 
02548 static void
02549 xmlFreeID(xmlIDPtr id) {
02550     xmlDictPtr dict = NULL;
02551 
02552     if (id == NULL) return;
02553 
02554     if (id->doc != NULL)
02555         dict = id->doc->dict;
02556 
02557     if (id->value != NULL)
02558     DICT_FREE(id->value)
02559     if (id->name != NULL)
02560     DICT_FREE(id->name)
02561     xmlFree(id);
02562 }
02563 
02564 
02576 xmlIDPtr 
02577 xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
02578          xmlAttrPtr attr) {
02579     xmlIDPtr ret;
02580     xmlIDTablePtr table;
02581 
02582     if (doc == NULL) {
02583     return(NULL);
02584     }
02585     if (value == NULL) {
02586     return(NULL);
02587     }
02588     if (attr == NULL) {
02589     return(NULL);
02590     }
02591 
02592     /*
02593      * Create the ID table if needed.
02594      */
02595     table = (xmlIDTablePtr) doc->ids;
02596     if (table == NULL)  {
02597         doc->ids = table = xmlHashCreateDict(0, doc->dict);
02598     }
02599     if (table == NULL) {
02600     xmlVErrMemory(ctxt,
02601         "xmlAddID: Table creation failed!\n");
02602         return(NULL);
02603     }
02604 
02605     ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
02606     if (ret == NULL) {
02607     xmlVErrMemory(ctxt, "malloc failed");
02608     return(NULL);
02609     }
02610 
02611     /*
02612      * fill the structure.
02613      */
02614     ret->value = xmlStrdup(value);
02615     ret->doc = doc;
02616     if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
02617     /*
02618      * Operating in streaming mode, attr is gonna disapear
02619      */
02620     if (doc->dict != NULL)
02621         ret->name = xmlDictLookup(doc->dict, attr->name, -1);
02622     else
02623         ret->name = xmlStrdup(attr->name);
02624     ret->attr = NULL;
02625     } else {
02626     ret->attr = attr;
02627     ret->name = NULL;
02628     }
02629     ret->lineno = xmlGetLineNo(attr->parent);
02630 
02631     if (xmlHashAddEntry(table, value, ret) < 0) {
02632 #ifdef LIBXML_VALID_ENABLED
02633     /*
02634      * The id is already defined in this DTD.
02635      */
02636     if ((ctxt != NULL) && (ctxt->error != NULL)) {
02637         xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
02638                         "ID %s already defined\n",
02639                 value, NULL, NULL);
02640     }
02641 #endif /* LIBXML_VALID_ENABLED */
02642     xmlFreeID(ret);
02643     return(NULL);
02644     }
02645     if (attr != NULL)
02646     attr->atype = XML_ATTRIBUTE_ID;
02647     return(ret);
02648 }
02649 
02656 void
02657 xmlFreeIDTable(xmlIDTablePtr table) {
02658     xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
02659 }
02660 
02674 int
02675 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
02676     if ((attr == NULL) || (attr->name == NULL)) return(0);
02677     if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
02678         (!strcmp((char *) attr->name, "id")) &&
02679         (!strcmp((char *) attr->ns->prefix, "xml")))
02680     return(1);
02681     if (doc == NULL) return(0);
02682     if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
02683         (doc->type != XML_HTML_DOCUMENT_NODE)) {
02684     return(0);
02685     } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
02686         if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
02687         ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
02688         ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
02689         return(1);
02690     return(0);    
02691     } else if (elem == NULL) {
02692     return(0);
02693     } else {
02694     xmlAttributePtr attrDecl = NULL;
02695 
02696     xmlChar felem[50], fattr[50];
02697     xmlChar *fullelemname, *fullattrname;
02698 
02699     fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
02700         xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
02701         (xmlChar *)elem->name;
02702 
02703     fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
02704         xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
02705         (xmlChar *)attr->name;
02706 
02707     if (fullelemname != NULL && fullattrname != NULL) {
02708         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
02709                                  fullattrname);
02710         if ((attrDecl == NULL) && (doc->extSubset != NULL))
02711         attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
02712                          fullattrname);
02713     }
02714 
02715     if ((fullattrname != fattr) && (fullattrname != attr->name))
02716         xmlFree(fullattrname);
02717     if ((fullelemname != felem) && (fullelemname != elem->name))
02718         xmlFree(fullelemname);
02719 
02720         if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
02721         return(1);
02722     }
02723     return(0);
02724 }
02725 
02735 int
02736 xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
02737     xmlIDTablePtr table;
02738     xmlIDPtr id;
02739     xmlChar *ID;
02740 
02741     if (doc == NULL) return(-1);
02742     if (attr == NULL) return(-1);
02743     table = (xmlIDTablePtr) doc->ids;
02744     if (table == NULL) 
02745         return(-1);
02746 
02747     if (attr == NULL)
02748     return(-1);
02749     ID = xmlNodeListGetString(doc, attr->children, 1);
02750     if (ID == NULL)
02751     return(-1);
02752     id = xmlHashLookup(table, ID);
02753     if (id == NULL || id->attr != attr) {
02754     xmlFree(ID);
02755     return(-1);
02756     }
02757     xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
02758     xmlFree(ID);
02759     attr->atype = 0;
02760     return(0);
02761 }
02762 
02772 xmlAttrPtr 
02773 xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
02774     xmlIDTablePtr table;
02775     xmlIDPtr id;
02776 
02777     if (doc == NULL) {
02778     return(NULL);
02779     }
02780 
02781     if (ID == NULL) {
02782     return(NULL);
02783     }
02784 
02785     table = (xmlIDTablePtr) doc->ids;
02786     if (table == NULL) 
02787         return(NULL);
02788 
02789     id = xmlHashLookup(table, ID);
02790     if (id == NULL)
02791     return(NULL);
02792     if (id->attr == NULL) {
02793     /*
02794      * We are operating on a stream, return a well known reference
02795      * since the attribute node doesn't exist anymore
02796      */
02797     return((xmlAttrPtr) doc);
02798     }
02799     return(id->attr);
02800 }
02801 
02802 /************************************************************************
02803  *                                  *
02804  *              Refs                    *
02805  *                                  *
02806  ************************************************************************/
02807 typedef struct xmlRemoveMemo_t 
02808 {
02809     xmlListPtr l;
02810     xmlAttrPtr ap;
02811 } xmlRemoveMemo;
02812 
02813 typedef xmlRemoveMemo *xmlRemoveMemoPtr;
02814 
02815 typedef struct xmlValidateMemo_t 
02816 {
02817     xmlValidCtxtPtr ctxt;
02818     const xmlChar *name;
02819 } xmlValidateMemo;
02820 
02821 typedef xmlValidateMemo *xmlValidateMemoPtr;
02822 
02829 static void
02830 xmlFreeRef(xmlLinkPtr lk) {
02831     xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
02832     if (ref == NULL) return;
02833     if (ref->value != NULL)
02834         xmlFree((xmlChar *)ref->value);
02835     if (ref->name != NULL)
02836         xmlFree((xmlChar *)ref->name);
02837     xmlFree(ref);
02838 }
02839 
02846 static void
02847 xmlFreeRefList(xmlListPtr list_ref) {
02848     if (list_ref == NULL) return;
02849     xmlListDelete(list_ref);
02850 }
02851 
02859 static int
02860 xmlWalkRemoveRef(const void *data, const void *user)
02861 {
02862     xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
02863     xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
02864     xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
02865 
02866     if (attr0 == attr1) { /* Matched: remove and terminate walk */
02867         xmlListRemoveFirst(ref_list, (void *)data);
02868         return 0;
02869     }
02870     return 1;
02871 }
02872 
02880 static int
02881 xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
02882                 const void *data1 ATTRIBUTE_UNUSED)
02883 {
02884     return (0);
02885 }
02886 
02898 xmlRefPtr 
02899 xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
02900     xmlAttrPtr attr) {
02901     xmlRefPtr ret;
02902     xmlRefTablePtr table;
02903     xmlListPtr ref_list;
02904 
02905     if (doc == NULL) {
02906         return(NULL);
02907     }
02908     if (value == NULL) {
02909         return(NULL);
02910     }
02911     if (attr == NULL) {
02912         return(NULL);
02913     }
02914 
02915     /*
02916      * Create the Ref table if needed.
02917      */
02918     table = (xmlRefTablePtr) doc->refs;
02919     if (table == NULL) {
02920         doc->refs = table = xmlHashCreateDict(0, doc->dict);
02921     }
02922     if (table == NULL) {
02923     xmlVErrMemory(ctxt,
02924             "xmlAddRef: Table creation failed!\n");
02925         return(NULL);
02926     }
02927 
02928     ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
02929     if (ret == NULL) {
02930     xmlVErrMemory(ctxt, "malloc failed");
02931         return(NULL);
02932     }
02933 
02934     /*
02935      * fill the structure.
02936      */
02937     ret->value = xmlStrdup(value);
02938     if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
02939     /*
02940      * Operating in streaming mode, attr is gonna disapear
02941      */
02942     ret->name = xmlStrdup(attr->name);
02943     ret->attr = NULL;
02944     } else {
02945     ret->name = NULL;
02946     ret->attr = attr;
02947     }
02948     ret->lineno = xmlGetLineNo(attr->parent);
02949 
02950     /* To add a reference :-
02951      * References are maintained as a list of references,
02952      * Lookup the entry, if no entry create new nodelist
02953      * Add the owning node to the NodeList
02954      * Return the ref
02955      */
02956 
02957     if (NULL == (ref_list = xmlHashLookup(table, value))) {
02958         if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
02959         xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
02960             "xmlAddRef: Reference list creation failed!\n",
02961             NULL);
02962         goto failed;
02963         }
02964         if (xmlHashAddEntry(table, value, ref_list) < 0) {
02965             xmlListDelete(ref_list);
02966         xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
02967             "xmlAddRef: Reference list insertion failed!\n",
02968             NULL);
02969         goto failed;
02970         }
02971     }
02972     if (xmlListAppend(ref_list, ret) != 0) {
02973     xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
02974             "xmlAddRef: Reference list insertion failed!\n",
02975             NULL);
02976         goto failed;
02977     }
02978     return(ret);
02979 failed:
02980     if (ret != NULL) {
02981         if (ret->value != NULL)
02982         xmlFree((char *)ret->value);
02983         if (ret->name != NULL)
02984         xmlFree((char *)ret->name);
02985         xmlFree(ret);
02986     }
02987     return(NULL);
02988 }
02989 
02996 void
02997 xmlFreeRefTable(xmlRefTablePtr table) {
02998     xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
02999 }
03000 
03013 int
03014 xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
03015     if (attr == NULL)
03016         return(0);
03017     if (doc == NULL) {
03018         doc = attr->doc;
03019     if (doc == NULL) return(0);
03020     }
03021 
03022     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
03023         return(0);
03024     } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
03025         /* TODO @@@ */
03026         return(0);    
03027     } else {
03028         xmlAttributePtr attrDecl;
03029 
03030         if (elem == NULL) return(0);
03031         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
03032         if ((attrDecl == NULL) && (doc->extSubset != NULL))
03033             attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
03034                                  elem->name, attr->name);
03035 
03036     if ((attrDecl != NULL) &&
03037         (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
03038          attrDecl->atype == XML_ATTRIBUTE_IDREFS))
03039     return(1);
03040     }
03041     return(0);
03042 }
03043 
03053 int
03054 xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
03055     xmlListPtr ref_list;
03056     xmlRefTablePtr table;
03057     xmlChar *ID;
03058     xmlRemoveMemo target;
03059 
03060     if (doc == NULL) return(-1);
03061     if (attr == NULL) return(-1);
03062     table = (xmlRefTablePtr) doc->refs;
03063     if (table == NULL) 
03064         return(-1);
03065 
03066     if (attr == NULL)
03067         return(-1);
03068     ID = xmlNodeListGetString(doc, attr->children, 1);
03069     if (ID == NULL)
03070         return(-1);
03071     ref_list = xmlHashLookup(table, ID);
03072 
03073     if(ref_list == NULL) {
03074         xmlFree(ID);
03075         return (-1);
03076     }
03077     /* At this point, ref_list refers to a list of references which
03078      * have the same key as the supplied attr. Our list of references
03079      * is ordered by reference address and we don't have that information
03080      * here to use when removing. We'll have to walk the list and
03081      * check for a matching attribute, when we find one stop the walk
03082      * and remove the entry.
03083      * The list is ordered by reference, so that means we don't have the
03084      * key. Passing the list and the reference to the walker means we
03085      * will have enough data to be able to remove the entry.
03086      */
03087     target.l = ref_list;
03088     target.ap = attr;
03089     
03090     /* Remove the supplied attr from our list */
03091     xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
03092 
03093     /*If the list is empty then remove the list entry in the hash */
03094     if (xmlListEmpty(ref_list))
03095         xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
03096         xmlFreeRefList);
03097     xmlFree(ID);
03098     return(0);
03099 }
03100 
03110 xmlListPtr 
03111 xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
03112     xmlRefTablePtr table;
03113 
03114     if (doc == NULL) {
03115         return(NULL);
03116     }
03117 
03118     if (ID == NULL) {
03119         return(NULL);
03120     }
03121 
03122     table = (xmlRefTablePtr) doc->refs;
03123     if (table == NULL) 
03124         return(NULL);
03125 
03126     return (xmlHashLookup(table, ID));
03127 }
03128 
03129 /************************************************************************
03130  *                                  *
03131  *      Routines for validity checking              *
03132  *                                  *
03133  ************************************************************************/
03134 
03145 xmlElementPtr
03146 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
03147     xmlElementTablePtr table;
03148     xmlElementPtr cur;
03149     xmlChar *uqname = NULL, *prefix = NULL;
03150 
03151     if ((dtd == NULL) || (name == NULL)) return(NULL);
03152     if (dtd->elements == NULL)
03153     return(NULL);
03154     table = (xmlElementTablePtr) dtd->elements;
03155 
03156     uqname = xmlSplitQName2(name, &prefix);
03157     if (uqname != NULL)
03158         name = uqname;
03159     cur = xmlHashLookup2(table, name, prefix);
03160     if (prefix != NULL) xmlFree(prefix);
03161     if (uqname != NULL) xmlFree(uqname);
03162     return(cur);
03163 }
03175 static xmlElementPtr
03176 xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
03177     xmlElementTablePtr table;
03178     xmlElementPtr cur;
03179     xmlChar *uqname = NULL, *prefix = NULL;
03180 
03181     if (dtd == NULL) return(NULL);
03182     if (dtd->elements == NULL) {
03183     xmlDictPtr dict = NULL;
03184 
03185     if (dtd->doc != NULL)
03186         dict = dtd->doc->dict;
03187 
03188     if (!create) 
03189         return(NULL);
03190     /*
03191      * Create the Element table if needed.
03192      */
03193     table = (xmlElementTablePtr) dtd->elements;
03194     if (table == NULL) {
03195         table = xmlHashCreateDict(0, dict);
03196         dtd->elements = (void *) table;
03197     }
03198     if (table == NULL) {
03199         xmlVErrMemory(NULL, "element table allocation failed");
03200         return(NULL);
03201     }
03202     }
03203     table = (xmlElementTablePtr) dtd->elements;
03204 
03205     uqname = xmlSplitQName2(name, &prefix);
03206     if (uqname != NULL)
03207         name = uqname;
03208     cur = xmlHashLookup2(table, name, prefix);
03209     if ((cur == NULL) && (create)) {
03210     cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
03211     if (cur == NULL) {
03212         xmlVErrMemory(NULL, "malloc failed");
03213         return(NULL);
03214     }
03215     memset(cur, 0, sizeof(xmlElement));
03216     cur->type = XML_ELEMENT_DECL;
03217 
03218     /*
03219      * fill the structure.
03220      */
03221     cur->name = xmlStrdup(name);
03222     cur->prefix = xmlStrdup(prefix);
03223     cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
03224 
03225     xmlHashAddEntry2(table, name, prefix, cur);
03226     }
03227     if (prefix != NULL) xmlFree(prefix);
03228     if (uqname != NULL) xmlFree(uqname);
03229     return(cur);
03230 }
03231 
03243 xmlElementPtr
03244 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
03245                   const xmlChar *prefix) {
03246     xmlElementTablePtr table;
03247 
03248     if (dtd == NULL) return(NULL);
03249     if (dtd->elements == NULL) return(NULL);
03250     table = (xmlElementTablePtr) dtd->elements;
03251 
03252     return(xmlHashLookup2(table, name, prefix));
03253 }
03254 
03267 xmlAttributePtr
03268 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
03269     xmlAttributeTablePtr table;
03270     xmlAttributePtr cur;
03271     xmlChar *uqname = NULL, *prefix = NULL;
03272 
03273     if (dtd == NULL) return(NULL);
03274     if (dtd->attributes == NULL) return(NULL);
03275 
03276     table = (xmlAttributeTablePtr) dtd->attributes;
03277     if (table == NULL)
03278     return(NULL);
03279 
03280     uqname = xmlSplitQName2(name, &prefix);
03281 
03282     if (uqname != NULL) {
03283     cur = xmlHashLookup3(table, uqname, prefix, elem);
03284     if (prefix != NULL) xmlFree(prefix);
03285     if (uqname != NULL) xmlFree(uqname);
03286     } else
03287     cur = xmlHashLookup3(table, name, NULL, elem);
03288     return(cur);
03289 }
03290 
03304 xmlAttributePtr
03305 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
03306               const xmlChar *prefix) {
03307     xmlAttributeTablePtr table;
03308 
03309     if (dtd == NULL) return(NULL);
03310     if (dtd->attributes == NULL) return(NULL);
03311     table = (xmlAttributeTablePtr) dtd->attributes;
03312 
03313     return(xmlHashLookup3(table, name, prefix, elem));
03314 }
03315 
03326 xmlNotationPtr
03327 xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
03328     xmlNotationTablePtr table;
03329 
03330     if (dtd == NULL) return(NULL);
03331     if (dtd->notations == NULL) return(NULL);
03332     table = (xmlNotationTablePtr) dtd->notations;
03333 
03334     return(xmlHashLookup(table, name));
03335 }
03336 
03337 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
03338 
03350 int
03351 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
03352                        const xmlChar *notationName) {
03353     xmlNotationPtr notaDecl;
03354     if ((doc == NULL) || (doc->intSubset == NULL) ||
03355         (notationName == NULL)) return(-1);
03356 
03357     notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
03358     if ((notaDecl == NULL) && (doc->extSubset != NULL))
03359     notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
03360 
03361     if ((notaDecl == NULL) && (ctxt != NULL)) {
03362     xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
03363                     "NOTATION %s is not declared\n",
03364                 notationName, NULL, NULL);
03365     return(0);
03366     }
03367     return(1);
03368 }
03369 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
03370 
03382 int
03383 xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
03384     xmlElementPtr elemDecl;
03385 
03386     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
03387 
03388     elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
03389     if ((elemDecl == NULL) && (doc->extSubset != NULL))
03390     elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
03391     if (elemDecl == NULL) return(-1);
03392     switch (elemDecl->etype) {
03393     case XML_ELEMENT_TYPE_UNDEFINED:
03394         return(-1);
03395     case XML_ELEMENT_TYPE_ELEMENT:
03396         return(0);
03397         case XML_ELEMENT_TYPE_EMPTY:
03398         /*
03399          * return 1 for EMPTY since we want VC error to pop up
03400          * on <empty>     </empty> for example
03401          */
03402     case XML_ELEMENT_TYPE_ANY:
03403     case XML_ELEMENT_TYPE_MIXED:
03404         return(1);
03405     }
03406     return(1);
03407 }
03408 
03409 #ifdef LIBXML_VALID_ENABLED
03410 
03411 static int
03412 xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
03413     if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
03414         /*
03415      * Use the new checks of production [4] [4a] amd [5] of the
03416      * Update 5 of XML-1.0
03417      */
03418     if (((c >= 'a') && (c <= 'z')) ||
03419         ((c >= 'A') && (c <= 'Z')) ||
03420         (c == '_') || (c == ':') ||
03421         ((c >= 0xC0) && (c <= 0xD6)) ||
03422         ((c >= 0xD8) && (c <= 0xF6)) ||
03423         ((c >= 0xF8) && (c <= 0x2FF)) ||
03424         ((c >= 0x370) && (c <= 0x37D)) ||
03425         ((c >= 0x37F) && (c <= 0x1FFF)) ||
03426         ((c >= 0x200C) && (c <= 0x200D)) ||
03427         ((c >= 0x2070) && (c <= 0x218F)) ||
03428         ((c >= 0x2C00) && (c <= 0x2FEF)) ||
03429         ((c >= 0x3001) && (c <= 0xD7FF)) ||
03430         ((c >= 0xF900) && (c <= 0xFDCF)) ||
03431         ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
03432         ((c >= 0x10000) && (c <= 0xEFFFF)))
03433         return(1);
03434     } else {
03435         if (IS_LETTER(c) || (c == '_') || (c == ':'))
03436         return(1);
03437     }
03438     return(0);
03439 }
03440 
03441 static int
03442 xmlIsDocNameChar(xmlDocPtr doc, int c) {
03443     if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
03444         /*
03445      * Use the new checks of production [4] [4a] amd [5] of the
03446      * Update 5 of XML-1.0
03447      */
03448     if (((c >= 'a') && (c <= 'z')) ||
03449         ((c >= 'A') && (c <= 'Z')) ||
03450         ((c >= '0') && (c <= '9')) || /* !start */
03451         (c == '_') || (c == ':') ||
03452         (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
03453         ((c >= 0xC0) && (c <= 0xD6)) ||
03454         ((c >= 0xD8) && (c <= 0xF6)) ||
03455         ((c >= 0xF8) && (c <= 0x2FF)) ||
03456         ((c >= 0x300) && (c <= 0x36F)) || /* !start */
03457         ((c >= 0x370) && (c <= 0x37D)) ||
03458         ((c >= 0x37F) && (c <= 0x1FFF)) ||
03459         ((c >= 0x200C) && (c <= 0x200D)) ||
03460         ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
03461         ((c >= 0x2070) && (c <= 0x218F)) ||
03462         ((c >= 0x2C00) && (c <= 0x2FEF)) ||
03463         ((c >= 0x3001) && (c <= 0xD7FF)) ||
03464         ((c >= 0xF900) && (c <= 0xFDCF)) ||
03465         ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
03466         ((c >= 0x10000) && (c <= 0xEFFFF)))
03467          return(1);
03468     } else {
03469         if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
03470             (c == '.') || (c == '-') ||
03471         (c == '_') || (c == ':') ||
03472         (IS_COMBINING(c)) ||
03473         (IS_EXTENDER(c)))
03474         return(1);
03475     }
03476     return(0);
03477 }
03478 
03489 static int
03490 xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
03491     const xmlChar *cur;
03492     int val, len;
03493 
03494     if (value == NULL) return(0);
03495     cur = value;
03496     val = xmlStringCurrentChar(NULL, cur, &len);
03497     cur += len;
03498     if (!xmlIsDocNameStartChar(doc, val))
03499     return(0);
03500 
03501     val = xmlStringCurrentChar(NULL, cur, &len);
03502     cur += len;
03503     while (xmlIsDocNameChar(doc, val)) {
03504     val = xmlStringCurrentChar(NULL, cur, &len);
03505     cur += len;
03506     }
03507 
03508     if (val != 0) return(0);
03509 
03510     return(1);
03511 }
03512 
03522 int
03523 xmlValidateNameValue(const xmlChar *value) {
03524     return(xmlValidateNameValueInternal(NULL, value));
03525 }
03526 
03537 static int
03538 xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
03539     const xmlChar *cur;
03540     int val, len;
03541 
03542     if (value == NULL) return(0);
03543     cur = value;
03544     val = xmlStringCurrentChar(NULL, cur, &len);
03545     cur += len;
03546 
03547     if (!xmlIsDocNameStartChar(doc, val))
03548     return(0);
03549 
03550     val = xmlStringCurrentChar(NULL, cur, &len);
03551     cur += len;
03552     while (xmlIsDocNameChar(doc, val)) {
03553     val = xmlStringCurrentChar(NULL, cur, &len);
03554     cur += len;
03555     }
03556 
03557     /* Should not test IS_BLANK(val) here -- see erratum E20*/
03558     while (val == 0x20) {
03559     while (val == 0x20) {
03560         val = xmlStringCurrentChar(NULL, cur, &len);
03561         cur += len;
03562     }
03563 
03564     if (!xmlIsDocNameStartChar(doc, val))
03565         return(0);
03566 
03567     val = xmlStringCurrentChar(NULL, cur, &len);
03568     cur += len;
03569 
03570     while (xmlIsDocNameChar(doc, val)) {
03571         val = xmlStringCurrentChar(NULL, cur, &len);
03572         cur += len;
03573     }
03574     }
03575 
03576     if (val != 0) return(0);
03577 
03578     return(1);
03579 }
03580 
03590 int
03591 xmlValidateNamesValue(const xmlChar *value) {
03592     return(xmlValidateNamesValueInternal(NULL, value));
03593 }
03594 
03607 static int
03608 xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
03609     const xmlChar *cur;
03610     int val, len;
03611 
03612     if (value == NULL) return(0);
03613     cur = value;
03614     val = xmlStringCurrentChar(NULL, cur, &len);
03615     cur += len;
03616 
03617     if (!xmlIsDocNameChar(doc, val))
03618     return(0);
03619 
03620     val = xmlStringCurrentChar(NULL, cur, &len);
03621     cur += len;
03622     while (xmlIsDocNameChar(doc, val)) {
03623     val = xmlStringCurrentChar(NULL, cur, &len);
03624     cur += len;
03625     }
03626 
03627     if (val != 0) return(0);
03628 
03629     return(1);
03630 }
03631 
03643 int
03644 xmlValidateNmtokenValue(const xmlChar *value) {
03645     return(xmlValidateNmtokenValueInternal(NULL, value));
03646 }
03647 
03660 static int
03661 xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
03662     const xmlChar *cur;
03663     int val, len;
03664 
03665     if (value == NULL) return(0);
03666     cur = value;
03667     val = xmlStringCurrentChar(NULL, cur, &len);
03668     cur += len;
03669 
03670     while (IS_BLANK(val)) {
03671     val = xmlStringCurrentChar(NULL, cur, &len);
03672     cur += len;
03673     }
03674 
03675     if (!xmlIsDocNameChar(doc, val))
03676     return(0);
03677 
03678     while (xmlIsDocNameChar(doc, val)) {
03679     val = xmlStringCurrentChar(NULL, cur, &len);
03680     cur += len;
03681     }
03682 
03683     /* Should not test IS_BLANK(val) here -- see erratum E20*/
03684     while (val == 0x20) {
03685     while (val == 0x20) {
03686         val = xmlStringCurrentChar(NULL, cur, &len);
03687         cur += len;
03688     }
03689     if (val == 0) return(1);
03690 
03691     if (!xmlIsDocNameChar(doc, val))
03692         return(0);
03693 
03694     val = xmlStringCurrentChar(NULL, cur, &len);
03695     cur += len;
03696 
03697     while (xmlIsDocNameChar(doc, val)) {
03698         val = xmlStringCurrentChar(NULL, cur, &len);
03699         cur += len;
03700     }
03701     }
03702 
03703     if (val != 0) return(0);
03704 
03705     return(1);
03706 }
03707 
03719 int
03720 xmlValidateNmtokensValue(const xmlChar *value) {
03721     return(xmlValidateNmtokensValueInternal(NULL, value));
03722 }
03723 
03739 int
03740 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
03741                          xmlNotationPtr nota ATTRIBUTE_UNUSED) {
03742     int ret = 1;
03743 
03744     return(ret);
03745 }
03746 
03758 static int
03759 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
03760                                   const xmlChar *value) {
03761     switch (type) {
03762     case XML_ATTRIBUTE_ENTITIES:
03763     case XML_ATTRIBUTE_IDREFS:
03764         return(xmlValidateNamesValueInternal(doc, value));
03765     case XML_ATTRIBUTE_ENTITY:
03766     case XML_ATTRIBUTE_IDREF:
03767     case XML_ATTRIBUTE_ID:
03768     case XML_ATTRIBUTE_NOTATION:
03769         return(xmlValidateNameValueInternal(doc, value));
03770     case XML_ATTRIBUTE_NMTOKENS:
03771     case XML_ATTRIBUTE_ENUMERATION:
03772         return(xmlValidateNmtokensValueInternal(doc, value));
03773     case XML_ATTRIBUTE_NMTOKEN:
03774         return(xmlValidateNmtokenValueInternal(doc, value));
03775         case XML_ATTRIBUTE_CDATA:
03776         break;
03777     }
03778     return(1);
03779 }
03780 
03805 int
03806 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
03807     return(xmlValidateAttributeValueInternal(NULL, type, value));
03808 }
03809 
03839 static int
03840 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
03841       const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
03842     int ret = 1;
03843     switch (type) {
03844     case XML_ATTRIBUTE_IDREFS:
03845     case XML_ATTRIBUTE_IDREF:
03846     case XML_ATTRIBUTE_ID:
03847     case XML_ATTRIBUTE_NMTOKENS:
03848     case XML_ATTRIBUTE_ENUMERATION:
03849     case XML_ATTRIBUTE_NMTOKEN:
03850         case XML_ATTRIBUTE_CDATA:
03851         break;
03852     case XML_ATTRIBUTE_ENTITY: {
03853         xmlEntityPtr ent;
03854 
03855         ent = xmlGetDocEntity(doc, value);
03856         /* yeah it's a bit messy... */
03857         if ((ent == NULL) && (doc->standalone == 1)) {
03858         doc->standalone = 0;
03859         ent = xmlGetDocEntity(doc, value);
03860         } 
03861         if (ent == NULL) {
03862         xmlErrValidNode(ctxt, (xmlNodePtr) doc,
03863                 XML_DTD_UNKNOWN_ENTITY,
03864    "ENTITY attribute %s reference an unknown entity \"%s\"\n",
03865                name, value, NULL);
03866         ret = 0;
03867         } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
03868         xmlErrValidNode(ctxt, (xmlNodePtr) doc,
03869                 XML_DTD_ENTITY_TYPE,
03870    "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
03871                name, value, NULL);
03872         ret = 0;
03873         }
03874         break;
03875         }
03876     case XML_ATTRIBUTE_ENTITIES: {
03877         xmlChar *dup, *nam = NULL, *cur, save;
03878         xmlEntityPtr ent;
03879 
03880         dup = xmlStrdup(value);
03881         if (dup == NULL)
03882         return(0);
03883         cur = dup;
03884         while (*cur != 0) {
03885         nam = cur;
03886         while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
03887         save = *cur;
03888         *cur = 0;
03889         ent = xmlGetDocEntity(doc, nam);
03890         if (ent == NULL) {
03891             xmlErrValidNode(ctxt, (xmlNodePtr) doc,
03892                     XML_DTD_UNKNOWN_ENTITY,
03893        "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
03894                name, nam, NULL);
03895             ret = 0;
03896         } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
03897             xmlErrValidNode(ctxt, (xmlNodePtr) doc,
03898                     XML_DTD_ENTITY_TYPE,
03899        "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
03900                name, nam, NULL);
03901             ret = 0;
03902         }
03903         if (save == 0)
03904             break;
03905         *cur = save;
03906         while (IS_BLANK_CH(*cur)) cur++;
03907         }
03908         xmlFree(dup);
03909         break;
03910     }
03911     case XML_ATTRIBUTE_NOTATION: {
03912         xmlNotationPtr nota;
03913 
03914         nota = xmlGetDtdNotationDesc(doc->intSubset, value);
03915         if ((nota == NULL) && (doc->extSubset != NULL))
03916         nota = xmlGetDtdNotationDesc(doc->extSubset, value);
03917 
03918         if (nota == NULL) {
03919         xmlErrValidNode(ctxt, (xmlNodePtr) doc,
03920                         XML_DTD_UNKNOWN_NOTATION,
03921        "NOTATION attribute %s reference an unknown notation \"%s\"\n",
03922                name, value, NULL);
03923         ret = 0;
03924         }
03925         break;
03926         }
03927     }
03928     return(ret);
03929 }
03930 
03955 xmlChar *
03956 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
03957          xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
03958     xmlChar *ret, *dst;
03959     const xmlChar *src;
03960     xmlAttributePtr attrDecl = NULL;
03961     int extsubset = 0;
03962 
03963     if (doc == NULL) return(NULL);
03964     if (elem == NULL) return(NULL);
03965     if (name == NULL) return(NULL);
03966     if (value == NULL) return(NULL);
03967 
03968     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
03969     xmlChar fn[50];
03970     xmlChar *fullname;
03971     
03972     fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
03973     if (fullname == NULL)
03974         return(NULL);
03975     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
03976     if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
03977         attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
03978         if (attrDecl != NULL)
03979         extsubset = 1;
03980     }
03981     if ((fullname != fn) && (fullname != elem->name))
03982         xmlFree(fullname);
03983     }
03984     if ((attrDecl == NULL) && (doc->intSubset != NULL))
03985     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
03986     if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
03987     attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
03988     if (attrDecl != NULL)
03989         extsubset = 1;
03990     }
03991 
03992     if (attrDecl == NULL)
03993     return(NULL);
03994     if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
03995     return(NULL);
03996 
03997     ret = xmlStrdup(value);
03998     if (ret == NULL)
03999     return(NULL);
04000     src = value;
04001     dst = ret;
04002     while (*src == 0x20) src++;
04003     while (*src != 0) {
04004     if (*src == 0x20) {
04005         while (*src == 0x20) src++;
04006         if (*src != 0)
04007         *dst++ = 0x20;
04008     } else {
04009         *dst++ = *src++;
04010     }
04011     }
04012     *dst = 0;
04013     if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
04014     xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
04015 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
04016            name, elem->name, NULL);
04017     ctxt->valid = 0;
04018     }
04019     return(ret);
04020 }
04021 
04041 xmlChar *
04042 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
04043                     const xmlChar *name, const xmlChar *value) {
04044     xmlChar *ret, *dst;
04045     const xmlChar *src;
04046     xmlAttributePtr attrDecl = NULL;
04047 
04048     if (doc == NULL) return(NULL);
04049     if (elem == NULL) return(NULL);
04050     if (name == NULL) return(NULL);
04051     if (value == NULL) return(NULL);
04052 
04053     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
04054     xmlChar fn[50];
04055     xmlChar *fullname;
04056 
04057     fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
04058     if (fullname == NULL)
04059         return(NULL);
04060     if ((fullname != fn) && (fullname != elem->name))
04061         xmlFree(fullname);
04062     }
04063     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
04064     if ((attrDecl == NULL) && (doc->extSubset != NULL))
04065     attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
04066 
04067     if (attrDecl == NULL)
04068     return(NULL);
04069     if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
04070     return(NULL);
04071 
04072     ret = xmlStrdup(value);
04073     if (ret == NULL)
04074     return(NULL);
04075     src = value;
04076     dst = ret;
04077     while (*src == 0x20) src++;
04078     while (*src != 0) {
04079     if (*src == 0x20) {
04080         while (*src == 0x20) src++;
04081         if (*src != 0)
04082         *dst++ = 0x20;
04083     } else {
04084         *dst++ = *src++;
04085     }
04086     }
04087     *dst = 0;
04088     return(ret);
04089 }
04090 
04091 static void
04092 xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
04093                            const xmlChar* name ATTRIBUTE_UNUSED) {
04094     if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
04095 }
04096 
04115 int
04116 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
04117                          xmlAttributePtr attr) {
04118     int ret = 1;
04119     int val;
04120     CHECK_DTD;
04121     if(attr == NULL) return(1);
04122 
04123     /* Attribute Default Legal */
04124     /* Enumeration */
04125     if (attr->defaultValue != NULL) {
04126     val = xmlValidateAttributeValueInternal(doc, attr->atype,
04127                                             attr->defaultValue);
04128     if (val == 0) {
04129         xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
04130            "Syntax of default value for attribute %s of %s is not valid\n",
04131                attr->name, attr->elem, NULL);
04132     }
04133         ret &= val;
04134     }
04135 
04136     /* ID Attribute Default */
04137     if ((attr->atype == XML_ATTRIBUTE_ID)&&
04138         (attr->def != XML_ATTRIBUTE_IMPLIED) &&
04139     (attr->def != XML_ATTRIBUTE_REQUIRED)) {
04140     xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
04141           "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
04142            attr->name, attr->elem, NULL);
04143     ret = 0;
04144     }
04145 
04146     /* One ID per Element Type */
04147     if (attr->atype == XML_ATTRIBUTE_ID) {
04148         int nbId;
04149 
04150     /* the trick is that we parse DtD as their own internal subset */
04151         xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
04152                                               attr->elem);
04153     if (elem != NULL) {
04154         nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
04155     } else {
04156         xmlAttributeTablePtr table;
04157 
04158         /*
04159          * The attribute may be declared in the internal subset and the
04160          * element in the external subset.
04161          */
04162         nbId = 0;
04163         if (doc->intSubset != NULL) {
04164         table = (xmlAttributeTablePtr) doc->intSubset->attributes;
04165         xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
04166                  xmlValidateAttributeIdCallback, &nbId);
04167         }
04168     }
04169     if (nbId > 1) {
04170         
04171         xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
04172        "Element %s has %d ID attribute defined in the internal subset : %s\n",
04173            attr->elem, nbId, attr->name);
04174     } else if (doc->extSubset != NULL) {
04175         int extId = 0;
04176         elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
04177         if (elem != NULL) {
04178         extId = xmlScanIDAttributeDecl(NULL, elem, 0);
04179         }
04180         if (extId > 1) {
04181         xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
04182        "Element %s has %d ID attribute defined in the external subset : %s\n",
04183                attr->elem, extId, attr->name);
04184         } else if (extId + nbId > 1) {
04185         xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
04186 "Element %s has ID attributes defined in the internal and external subset : %s\n",
04187                attr->elem, attr->name, NULL);
04188         }
04189     }
04190     }
04191 
04192     /* Validity Constraint: Enumeration */
04193     if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
04194         xmlEnumerationPtr tree = attr->tree;
04195     while (tree != NULL) {
04196         if (xmlStrEqual(tree->name, attr->defaultValue)) break;
04197         tree = tree->next;
04198     }
04199     if (tree == NULL) {
04200         xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
04201 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
04202            attr->defaultValue, attr->name, attr->elem);
04203         ret = 0;
04204     }
04205     }
04206 
04207     return(ret);
04208 }
04209 
04226 int
04227 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
04228                        xmlElementPtr elem) {
04229     int ret = 1;
04230     xmlElementPtr tst;
04231 
04232     CHECK_DTD;
04233     
04234     if (elem == NULL) return(1);
04235 
04236 #if 0
04237 #ifdef LIBXML_REGEXP_ENABLED
04238     /* Build the regexp associated to the content model */
04239     ret = xmlValidBuildContentModel(ctxt, elem);
04240 #endif
04241 #endif
04242 
04243     /* No Duplicate Types */
04244     if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
04245     xmlElementContentPtr cur, next;
04246         const xmlChar *name;
04247 
04248     cur = elem->content;
04249     while (cur != NULL) {
04250         if (cur->type != XML_ELEMENT_CONTENT_OR) break;
04251         if (cur->c1 == NULL) break;
04252         if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
04253         name = cur->c1->name;
04254         next = cur->c2;
04255         while (next != NULL) {
04256             if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
04257                 if ((xmlStrEqual(next->name, name)) &&
04258                 (xmlStrEqual(next->prefix, cur->c1->prefix))) {
04259                 if (cur->c1->prefix == NULL) {
04260                 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
04261            "Definition of %s has duplicate references of %s\n",
04262                        elem->name, name, NULL);
04263                 } else {
04264                 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
04265            "Definition of %s has duplicate references of %s:%s\n",
04266                        elem->name, cur->c1->prefix, name);
04267                 }
04268                 ret = 0;
04269             }
04270             break;
04271             }
04272             if (next->c1 == NULL) break;
04273             if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
04274             if ((xmlStrEqual(next->c1->name, name)) &&
04275                 (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
04276             if (cur->c1->prefix == NULL) {
04277                 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
04278            "Definition of %s has duplicate references to %s\n",
04279                    elem->name, name, NULL);
04280             } else {
04281                 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
04282            "Definition of %s has duplicate references to %s:%s\n",
04283                    elem->name, cur->c1->prefix, name);
04284             }
04285             ret = 0;
04286             }
04287             next = next->c2;
04288         }
04289         }
04290         cur = cur->c2;
04291     }
04292     }
04293 
04294     /* VC: Unique Element Type Declaration */
04295     tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
04296     if ((tst != NULL ) && (tst != elem) &&
04297     ((tst->prefix == elem->prefix) ||
04298      (xmlStrEqual(tst->prefix, elem->prefix))) &&
04299     (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
04300     xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
04301                     "Redefinition of element %s\n",
04302                elem->name, NULL, NULL);
04303     ret = 0;
04304     }
04305     tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
04306     if ((tst != NULL ) && (tst != elem) &&
04307     ((tst->prefix == elem->prefix) ||
04308      (xmlStrEqual(tst->prefix, elem->prefix))) &&
04309     (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
04310     xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
04311                     "Redefinition of element %s\n",
04312                elem->name, NULL, NULL);
04313     ret = 0;
04314     }
04315     /* One ID per Element Type
04316      * already done when registering the attribute
04317     if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
04318     ret = 0;
04319     } */
04320     return(ret);
04321 }
04322 
04348 int
04349 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
04350                         xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) 
04351 {
04352     xmlAttributePtr attrDecl =  NULL;
04353     int val;
04354     int ret = 1;
04355 
04356     CHECK_DTD;
04357     if ((elem == NULL) || (elem->name == NULL)) return(0);
04358     if ((attr == NULL) || (attr->name == NULL)) return(0);
04359 
04360     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
04361     xmlChar fn[50];
04362     xmlChar *fullname;
04363     
04364     fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
04365     if (fullname == NULL)
04366         return(0);
04367     if (attr->ns != NULL) {
04368         attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
04369                                   attr->name, attr->ns->prefix);
04370         if ((attrDecl == NULL) && (doc->extSubset != NULL))
04371         attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
04372                           attr->name, attr->ns->prefix);
04373     } else {
04374         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
04375         if ((attrDecl == NULL) && (doc->extSubset != NULL))
04376         attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
04377                          fullname, attr->name);
04378     }
04379     if ((fullname != fn) && (fullname != elem->name))
04380         xmlFree(fullname);
04381     }
04382     if (attrDecl == NULL) {
04383     if (attr->ns != NULL) {
04384         attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
04385                                   attr->name, attr->ns->prefix);
04386         if ((attrDecl == NULL) && (doc->extSubset != NULL))
04387         attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
04388                           attr->name, attr->ns->prefix);
04389     } else {
04390         attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
04391                                  elem->name, attr->name);
04392         if ((attrDecl == NULL) && (doc->extSubset != NULL))
04393         attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
04394                          elem->name, attr->name);
04395     }
04396     }
04397 
04398 
04399     /* Validity Constraint: Attribute Value Type */
04400     if (attrDecl == NULL) {
04401     xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
04402            "No declaration for attribute %s of element %s\n",
04403            attr->name, elem->name, NULL);
04404     return(0);
04405     }
04406     attr->atype = attrDecl->atype;
04407 
04408     val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
04409     if (val == 0) {
04410         xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
04411        "Syntax of value for attribute %s of %s is not valid\n",
04412            attr->name, elem->name, NULL);
04413         ret = 0;
04414     }
04415 
04416     /* Validity constraint: Fixed Attribute Default */
04417     if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
04418     if (!xmlStrEqual(value, attrDecl->defaultValue)) {
04419         xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
04420        "Value for attribute %s of %s is different from default \"%s\"\n",
04421            attr->name, elem->name, attrDecl->defaultValue);
04422         ret = 0;
04423     }
04424     }
04425 
04426     /* Validity Constraint: ID uniqueness */
04427     if (attrDecl->atype == XML_ATTRIBUTE_ID) {
04428         if (xmlAddID(ctxt, doc, value, attr) == NULL)
04429         ret = 0;
04430     }
04431 
04432     if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
04433     (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
04434         if (xmlAddRef(ctxt, doc, value, attr) == NULL)
04435         ret = 0;
04436     }
04437 
04438     /* Validity Constraint: Notation Attributes */
04439     if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
04440         xmlEnumerationPtr tree = attrDecl->tree;
04441         xmlNotationPtr nota;
04442 
04443         /* First check that the given NOTATION was declared */
04444     nota = xmlGetDtdNotationDesc(doc->intSubset, value);
04445     if (nota == NULL)
04446         nota = xmlGetDtdNotationDesc(doc->extSubset, value);
04447     
04448     if (nota == NULL) {
04449         xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
04450        "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
04451            value, attr->name, elem->name);
04452         ret = 0;
04453         }
04454 
04455     /* Second, verify that it's among the list */
04456     while (tree != NULL) {
04457         if (xmlStrEqual(tree->name, value)) break;
04458         tree = tree->next;
04459     }
04460     if (tree == NULL) {
04461         xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
04462 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
04463            value, attr->name, elem->name);
04464         ret = 0;
04465     }
04466     }
04467 
04468     /* Validity Constraint: Enumeration */
04469     if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
04470         xmlEnumerationPtr tree = attrDecl->tree;
04471     while (tree != NULL) {
04472         if (xmlStrEqual(tree->name, value)) break;
04473         tree = tree->next;
04474     }
04475     if (tree == NULL) {
04476         xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
04477        "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
04478            value, attr->name, elem->name);
04479         ret = 0;
04480     }
04481     }
04482 
04483     /* Fixed Attribute Default */
04484     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
04485         (!xmlStrEqual(attrDecl->defaultValue, value))) {
04486     xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
04487        "Value for attribute %s of %s must be \"%s\"\n",
04488            attr->name, elem->name, attrDecl->defaultValue);
04489         ret = 0;
04490     }
04491 
04492     /* Extra check for the attribute value */
04493     ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
04494                       attrDecl->atype, value);
04495 
04496     return(ret);
04497 }
04498 
04525 int
04526 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
04527 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
04528     /* xmlElementPtr elemDecl; */
04529     xmlAttributePtr attrDecl =  NULL;
04530     int val;
04531     int ret = 1;
04532 
04533     CHECK_DTD;
04534     if ((elem == NULL) || (elem->name == NULL)) return(0);
04535     if ((ns == NULL) || (ns->href == NULL)) return(0);
04536 
04537     if (prefix != NULL) {
04538     xmlChar fn[50];
04539     xmlChar *fullname;
04540     
04541     fullname = xmlBuildQName(elem->name, prefix, fn, 50);
04542     if (fullname == NULL) {
04543         xmlVErrMemory(ctxt, "Validating namespace");
04544         return(0);
04545     }
04546     if (ns->prefix != NULL) {
04547         attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
04548                                   ns->prefix, BAD_CAST "xmlns");
04549         if ((attrDecl == NULL) && (doc->extSubset != NULL))
04550         attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
04551                       ns->prefix, BAD_CAST "xmlns");
04552     } else {
04553         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
04554                                  BAD_CAST "xmlns");
04555         if ((attrDecl == NULL) && (doc->extSubset != NULL))
04556         attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
04557                              BAD_CAST "xmlns");
04558     }
04559     if ((fullname != fn) && (fullname != elem->name))
04560         xmlFree(fullname);
04561     }
04562     if (attrDecl == NULL) {
04563     if (ns->prefix != NULL) {
04564         attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
04565                                   ns->prefix, BAD_CAST "xmlns");
04566         if ((attrDecl == NULL) && (doc->extSubset != NULL))
04567         attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
04568                           ns->prefix, BAD_CAST "xmlns");
04569     } else {
04570         attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
04571                                  elem->name, BAD_CAST "xmlns");
04572         if ((attrDecl == NULL) && (doc->extSubset != NULL))
04573         attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
04574                          elem->name, BAD_CAST "xmlns");
04575     }
04576     }
04577 
04578 
04579     /* Validity Constraint: Attribute Value Type */
04580     if (attrDecl == NULL) {
04581     if (ns->prefix != NULL) {
04582         xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
04583            "No declaration for attribute xmlns:%s of element %s\n",
04584            ns->prefix, elem->name, NULL);
04585     } else {
04586         xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
04587            "No declaration for attribute xmlns of element %s\n",
04588            elem->name, NULL, NULL);
04589     }
04590     return(0);
04591     }
04592 
04593     val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
04594     if (val == 0) {
04595     if (ns->prefix != NULL) {
04596         xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
04597            "Syntax of value for attribute xmlns:%s of %s is not valid\n",
04598            ns->prefix, elem->name, NULL);
04599     } else {
04600         xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
04601            "Syntax of value for attribute xmlns of %s is not valid\n",
04602            elem->name, NULL, NULL);
04603     }
04604         ret = 0;
04605     }
04606 
04607     /* Validity constraint: Fixed Attribute Default */
04608     if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
04609     if (!xmlStrEqual(value, attrDecl->defaultValue)) {
04610         if (ns->prefix != NULL) {
04611         xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
04612        "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
04613                ns->prefix, elem->name, attrDecl->defaultValue);
04614         } else {
04615         xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
04616        "Value for attribute xmlns of %s is different from default \"%s\"\n",
04617                elem->name, attrDecl->defaultValue, NULL);
04618         }
04619         ret = 0;
04620     }
04621     }
04622 
04623     /* Validity Constraint: ID uniqueness */
04624     if (attrDecl->atype == XML_ATTRIBUTE_ID) {
04625         if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
04626         ret = 0;
04627     }
04628 
04629     if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
04630     (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
04631         if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
04632         ret = 0;
04633     }
04634 
04635     /* Validity Constraint: Notation Attributes */
04636     if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
04637         xmlEnumerationPtr tree = attrDecl->tree;
04638         xmlNotationPtr nota;
04639 
04640         /* First check that the given NOTATION was declared */
04641     nota = xmlGetDtdNotationDesc(doc->intSubset, value);
04642     if (nota == NULL)
04643         nota = xmlGetDtdNotationDesc(doc->extSubset, value);
04644     
04645     if (nota == NULL) {
04646         if (ns->prefix != NULL) {
04647         xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
04648        "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
04649                value, ns->prefix, elem->name);
04650         } else {
04651         xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
04652        "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
04653                value, elem->name, NULL);
04654         }
04655         ret = 0;
04656         }
04657 
04658     /* Second, verify that it's among the list */
04659     while (tree != NULL) {
04660         if (xmlStrEqual(tree->name, value)) break;
04661         tree = tree->next;
04662     }
04663     if (tree == NULL) {
04664         if (ns->prefix != NULL) {
04665         xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
04666 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
04667                value, ns->prefix, elem->name);
04668         } else {
04669         xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
04670 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
04671                value, elem->name, NULL);
04672         }
04673         ret = 0;
04674     }
04675     }
04676 
04677     /* Validity Constraint: Enumeration */
04678     if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
04679         xmlEnumerationPtr tree = attrDecl->tree;
04680     while (tree != NULL) {
04681         if (xmlStrEqual(tree->name, value)) break;
04682         tree = tree->next;
04683     }
04684     if (tree == NULL) {
04685         if (ns->prefix != NULL) {
04686         xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
04687 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
04688                value, ns->prefix, elem->name);
04689         } else {
04690         xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
04691 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
04692                value, elem->name, NULL);
04693         }
04694         ret = 0;
04695     }
04696     }
04697 
04698     /* Fixed Attribute Default */
04699     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
04700         (!xmlStrEqual(attrDecl->defaultValue, value))) {
04701     if (ns->prefix != NULL) {
04702         xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
04703            "Value for attribute xmlns:%s of %s must be \"%s\"\n",
04704            ns->prefix, elem->name, attrDecl->defaultValue);
04705     } else {
04706         xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
04707            "Value for attribute xmlns of %s must be \"%s\"\n",
04708            elem->name, attrDecl->defaultValue, NULL);
04709     }
04710         ret = 0;
04711     }
04712 
04713     /* Extra check for the attribute value */
04714     if (ns->prefix != NULL) {
04715     ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
04716                       attrDecl->atype, value);
04717     } else {
04718     ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
04719                       attrDecl->atype, value);
04720     }
04721 
04722     return(ret);
04723 }
04724 
04725 #ifndef  LIBXML_REGEXP_ENABLED
04726 
04736 static xmlNodePtr
04737 xmlValidateSkipIgnorable(xmlNodePtr child) {
04738     while (child != NULL) {
04739     switch (child->type) {
04740         /* These things are ignored (skipped) during validation.  */
04741         case XML_PI_NODE:
04742         case XML_COMMENT_NODE:
04743         case XML_XINCLUDE_START:
04744         case XML_XINCLUDE_END:
04745         child = child->next;
04746         break;
04747         case XML_TEXT_NODE:
04748         if (xmlIsBlankNode(child))
04749             child = child->next;
04750         else
04751             return(child);
04752         break;
04753         /* keep current node */
04754         default:
04755         return(child);
04756     }
04757     }
04758     return(child);
04759 }
04760 
04772 static int
04773 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
04774     int ret = -1;
04775     int determinist = 1;
04776 
04777     NODE = xmlValidateSkipIgnorable(NODE);
04778     if ((NODE == NULL) && (CONT == NULL))
04779     return(1);
04780     if ((NODE == NULL) && 
04781     ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
04782      (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
04783     return(1);
04784     }
04785     if (CONT == NULL) return(-1);
04786     if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
04787     return(-2);
04788 
04789     /*
04790      * We arrive here when more states need to be examined
04791      */
04792 cont:
04793 
04794     /*
04795      * We just recovered from a rollback generated by a possible
04796      * epsilon transition, go directly to the analysis phase
04797      */
04798     if (STATE == ROLLBACK_PARENT) {
04799     DEBUG_VALID_MSG("restored parent branch");
04800     DEBUG_VALID_STATE(NODE, CONT)
04801     ret = 1;
04802     goto analyze;
04803     }
04804 
04805     DEBUG_VALID_STATE(NODE, CONT)
04806     /*
04807      * we may have to save a backup state here. This is the equivalent
04808      * of handling epsilon transition in NFAs.
04809      */
04810     if ((CONT != NULL) &&
04811     ((CONT->parent == NULL) ||
04812      (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
04813     ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
04814      (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
04815      ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
04816     DEBUG_VALID_MSG("saving parent branch");
04817     if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
04818         return(0);
04819     }
04820 
04821 
04822     /*
04823      * Check first if the content matches
04824      */
04825     switch (CONT->type) {
04826     case XML_ELEMENT_CONTENT_PCDATA:
04827         if (NODE == NULL) {
04828         DEBUG_VALID_MSG("pcdata failed no node");
04829         ret = 0;
04830         break;
04831         }
04832         if (NODE->type == XML_TEXT_NODE) {
04833         DEBUG_VALID_MSG("pcdata found, skip to next");
04834         /*
04835          * go to next element in the content model
04836          * skipping ignorable elems
04837          */
04838         do {
04839             NODE = NODE->next;
04840             NODE = xmlValidateSkipIgnorable(NODE);
04841             if ((NODE != NULL) &&
04842             (NODE->type == XML_ENTITY_REF_NODE))
04843             return(-2);
04844         } while ((NODE != NULL) &&
04845              ((NODE->type != XML_ELEMENT_NODE) &&
04846               (NODE->type != XML_TEXT_NODE) &&
04847               (NODE->type != XML_CDATA_SECTION_NODE)));
04848                 ret = 1;
04849         break;
04850         } else {
04851         DEBUG_VALID_MSG("pcdata failed");
04852         ret = 0;
04853         break;
04854         }
04855         break;
04856     case XML_ELEMENT_CONTENT_ELEMENT:
04857         if (NODE == NULL) {
04858         DEBUG_VALID_MSG("element failed no node");
04859         ret = 0;
04860         break;
04861         }
04862         ret = ((NODE->type == XML_ELEMENT_NODE) &&
04863            (xmlStrEqual(NODE->name, CONT->name)));
04864         if (ret == 1) {
04865         if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
04866             ret = (CONT->prefix == NULL);
04867         } else if (CONT->prefix == NULL) {
04868             ret = 0;
04869         } else {
04870             ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
04871         }
04872         }
04873         if (ret == 1) {
04874         DEBUG_VALID_MSG("element found, skip to next");
04875         /*
04876          * go to next element in the content model
04877          * skipping ignorable elems
04878          */
04879         do {
04880             NODE = NODE->next;
04881             NODE = xmlValidateSkipIgnorable(NODE);
04882             if ((NODE != NULL) &&
04883             (NODE->type == XML_ENTITY_REF_NODE))
04884             return(-2);
04885         } while ((NODE != NULL) &&
04886              ((NODE->type != XML_ELEMENT_NODE) &&
04887               (NODE->type != XML_TEXT_NODE) &&
04888               (NODE->type != XML_CDATA_SECTION_NODE)));
04889         } else {
04890         DEBUG_VALID_MSG("element failed");
04891         ret = 0;
04892         break;
04893         }
04894         break;
04895     case XML_ELEMENT_CONTENT_OR:
04896         /*
04897          * Small optimization.
04898          */
04899         if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
04900         if ((NODE == NULL) ||
04901             (!xmlStrEqual(NODE->name, CONT->c1->name))) {
04902             DEPTH++;
04903             CONT = CONT->c2;
04904             goto cont;
04905         }
04906         if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
04907             ret = (CONT->c1->prefix == NULL);
04908         } else if (CONT->c1->prefix == NULL) {
04909             ret = 0;
04910         } else {
04911             ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
04912         }
04913         if (ret == 0) {
04914             DEPTH++;
04915             CONT = CONT->c2;
04916             goto cont;
04917         }
04918         }
04919 
04920         /*
04921          * save the second branch 'or' branch
04922          */
04923         DEBUG_VALID_MSG("saving 'or' branch");
04924         if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
04925                 OCCURS, ROLLBACK_OR) < 0)
04926         return(-1);
04927         DEPTH++;
04928         CONT = CONT->c1;
04929         goto cont;
04930     case XML_ELEMENT_CONTENT_SEQ:
04931         /*
04932          * Small optimization.
04933          */
04934         if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
04935         ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
04936          (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
04937         if ((NODE == NULL) ||
04938             (!xmlStrEqual(NODE->name, CONT->c1->name))) {
04939             DEPTH++;
04940             CONT = CONT->c2;
04941             goto cont;
04942         }
04943         if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
04944             ret = (CONT->c1->prefix == NULL);
04945         } else if (CONT->c1->prefix == NULL) {
04946             ret = 0;
04947         } else {
04948             ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
04949         }
04950         if (ret == 0) {
04951             DEPTH++;
04952             CONT = CONT->c2;
04953             goto cont;
04954         }
04955         }
04956         DEPTH++;
04957         CONT = CONT->c1;
04958         goto cont;
04959     }
04960 
04961     /*
04962      * At this point handle going up in the tree
04963      */
04964     if (ret == -1) {
04965     DEBUG_VALID_MSG("error found returning");
04966     return(ret);
04967     }
04968 analyze:
04969     while (CONT != NULL) {
04970     /*
04971      * First do the analysis depending on the occurrence model at
04972      * this level.
04973      */
04974     if (ret == 0) {
04975         switch (CONT->ocur) {
04976         xmlNodePtr cur;
04977 
04978         case XML_ELEMENT_CONTENT_ONCE:
04979             cur = ctxt->vstate->node;
04980             DEBUG_VALID_MSG("Once branch failed, rollback");
04981             if (vstateVPop(ctxt) < 0 ) {
04982             DEBUG_VALID_MSG("exhaustion, failed");
04983             return(0);
04984             }
04985             if (cur != ctxt->vstate->node)
04986             determinist = -3;
04987             goto cont;
04988         case XML_ELEMENT_CONTENT_PLUS:
04989             if (OCCURRENCE == 0) {
04990             cur = ctxt->vstate->node;
04991             DEBUG_VALID_MSG("Plus branch failed, rollback");
04992             if (vstateVPop(ctxt) < 0 ) {
04993                 DEBUG_VALID_MSG("exhaustion, failed");
04994                 return(0);
04995             }
04996             if (cur != ctxt->vstate->node)
04997                 determinist = -3;
04998             goto cont;
04999             }
05000             DEBUG_VALID_MSG("Plus branch found");
05001             ret = 1;
05002             break;
05003         case XML_ELEMENT_CONTENT_MULT:
05004 #ifdef DEBUG_VALID_ALGO
05005             if (OCCURRENCE == 0) {
05006             DEBUG_VALID_MSG("Mult branch failed");
05007             } else {
05008             DEBUG_VALID_MSG("Mult branch found");
05009             }
05010 #endif
05011             ret = 1;
05012             break;
05013         case XML_ELEMENT_CONTENT_OPT:
05014             DEBUG_VALID_MSG("Option branch failed");
05015             ret = 1;
05016             break;
05017         }
05018     } else {
05019         switch (CONT->ocur) {
05020         case XML_ELEMENT_CONTENT_OPT:
05021             DEBUG_VALID_MSG("Option branch succeeded");
05022             ret = 1;
05023             break;
05024         case XML_ELEMENT_CONTENT_ONCE:
05025             DEBUG_VALID_MSG("Once branch succeeded");
05026             ret = 1;
05027             break;
05028         case XML_ELEMENT_CONTENT_PLUS:
05029             if (STATE == ROLLBACK_PARENT) {
05030             DEBUG_VALID_MSG("Plus branch rollback");
05031             ret = 1;
05032             break;
05033             }
05034             if (NODE == NULL) {
05035             DEBUG_VALID_MSG("Plus branch exhausted");
05036             ret = 1;
05037             break;
05038             }
05039             DEBUG_VALID_MSG("Plus branch succeeded, continuing");
05040             SET_OCCURRENCE;
05041             goto cont;
05042         case XML_ELEMENT_CONTENT_MULT:
05043             if (STATE == ROLLBACK_PARENT) {
05044             DEBUG_VALID_MSG("Mult branch rollback");
05045             ret = 1;
05046             break;
05047             }
05048             if (NODE == NULL) {
05049             DEBUG_VALID_MSG("Mult branch exhausted");
05050             ret = 1;
05051             break;
05052             }
05053             DEBUG_VALID_MSG("Mult branch succeeded, continuing");
05054             /* SET_OCCURRENCE; */
05055             goto cont;
05056         }
05057     }
05058     STATE = 0;
05059 
05060     /*
05061      * Then act accordingly at the parent level
05062      */
05063     RESET_OCCURRENCE;
05064     if (CONT->parent == NULL)
05065         break;
05066 
05067     switch (CONT->parent->type) {
05068         case XML_ELEMENT_CONTENT_PCDATA:
05069         DEBUG_VALID_MSG("Error: parent pcdata");
05070         return(-1);
05071         case XML_ELEMENT_CONTENT_ELEMENT:
05072         DEBUG_VALID_MSG("Error: parent element");
05073         return(-1);
05074         case XML_ELEMENT_CONTENT_OR:
05075         if (ret == 1) {
05076             DEBUG_VALID_MSG("Or succeeded");
05077             CONT = CONT->parent;
05078             DEPTH--;
05079         } else {
05080             DEBUG_VALID_MSG("Or failed");
05081             CONT = CONT->parent;
05082             DEPTH--;
05083         }
05084         break;
05085         case XML_ELEMENT_CONTENT_SEQ:
05086         if (ret == 0) {
05087             DEBUG_VALID_MSG("Sequence failed");
05088             CONT = CONT->parent;
05089             DEPTH--;
05090         } else if (CONT == CONT->parent->c1) {
05091             DEBUG_VALID_MSG("Sequence testing 2nd branch");
05092             CONT = CONT->parent->c2;
05093             goto cont;
05094         } else {
05095             DEBUG_VALID_MSG("Sequence succeeded");
05096             CONT = CONT->parent;
05097             DEPTH--;
05098         }
05099     }
05100     }
05101     if (NODE != NULL) {
05102     xmlNodePtr cur;
05103 
05104     cur = ctxt->vstate->node;
05105     DEBUG_VALID_MSG("Failed, remaining input, rollback");
05106     if (vstateVPop(ctxt) < 0 ) {
05107         DEBUG_VALID_MSG("exhaustion, failed");
05108         return(0);
05109     }
05110     if (cur != ctxt->vstate->node)
05111         determinist = -3;
05112     goto cont;
05113     }
05114     if (ret == 0) {
05115     xmlNodePtr cur;
05116 
05117     cur = ctxt->vstate->node;
05118     DEBUG_VALID_MSG("Failure, rollback");
05119     if (vstateVPop(ctxt) < 0 ) {
05120         DEBUG_VALID_MSG("exhaustion, failed");
05121         return(0);
05122     }
05123     if (cur != ctxt->vstate->node)
05124         determinist = -3;
05125     goto cont;
05126     }
05127     return(determinist);
05128 }
05129 #endif
05130 
05141 static void
05142 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
05143     xmlNodePtr cur;
05144     int len;
05145 
05146     if (node == NULL) return;
05147     if (glob) strcat(buf, "(");
05148     cur = node;
05149     while (cur != NULL) {
05150     len = strlen(buf);
05151     if (size - len < 50) {
05152         if ((size - len > 4) && (buf[len - 1] != '.'))
05153         strcat(buf, " ...");
05154         return;
05155     }
05156         switch (cur->type) {
05157             case XML_ELEMENT_NODE:
05158         if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
05159             if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
05160             if ((size - len > 4) && (buf[len - 1] != '.'))
05161                 strcat(buf, " ...");
05162             return;
05163             }
05164             strcat(buf, (char *) cur->ns->prefix);
05165             strcat(buf, ":");
05166         }
05167                 if (size - len < xmlStrlen(cur->name) + 10) {
05168             if ((size - len > 4) && (buf[len - 1] != '.'))
05169             strcat(buf, " ...");
05170             return;
05171         }
05172             strcat(buf, (char *) cur->name);
05173         if (cur->next != NULL)
05174             strcat(buf, " ");
05175         break;
05176             case XML_TEXT_NODE:
05177         if (xmlIsBlankNode(cur))
05178             break;
05179             case XML_CDATA_SECTION_NODE:
05180             case XML_ENTITY_REF_NODE:
05181             strcat(buf, "CDATA");
05182         if (cur->next != NULL)
05183             strcat(buf, " ");
05184         break;
05185             case XML_ATTRIBUTE_NODE:
05186             case XML_DOCUMENT_NODE:
05187 #ifdef LIBXML_DOCB_ENABLED
05188         case XML_DOCB_DOCUMENT_NODE:
05189 #endif
05190         case XML_HTML_DOCUMENT_NODE:
05191             case XML_DOCUMENT_TYPE_NODE:
05192             case XML_DOCUMENT_FRAG_NODE:
05193             case XML_NOTATION_NODE:
05194         case XML_NAMESPACE_DECL:
05195             strcat(buf, "???");
05196         if (cur->next != NULL)
05197             strcat(buf, " ");
05198         break;
05199             case XML_ENTITY_NODE:
05200             case XML_PI_NODE:
05201             case XML_DTD_NODE:
05202             case XML_COMMENT_NODE:
05203         case XML_ELEMENT_DECL:
05204         case XML_ATTRIBUTE_DECL:
05205         case XML_ENTITY_DECL:
05206         case XML_XINCLUDE_START:
05207         case XML_XINCLUDE_END:
05208         break;
05209     }
05210     cur = cur->next;
05211     }
05212     if (glob) strcat(buf, ")");
05213 }
05214 
05228 static int
05229 xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
05230        xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
05231     int ret = 1;
05232 #ifndef  LIBXML_REGEXP_ENABLED
05233     xmlNodePtr repl = NULL, last = NULL, tmp;
05234 #endif
05235     xmlNodePtr cur;
05236     xmlElementContentPtr cont;
05237     const xmlChar *name;
05238 
05239     if (elemDecl == NULL)
05240     return(-1);
05241     cont = elemDecl->content;
05242     name = elemDecl->name;
05243 
05244 #ifdef LIBXML_REGEXP_ENABLED
05245     /* Build the regexp associated to the content model */
05246     if (elemDecl->contModel == NULL)
05247     ret = xmlValidBuildContentModel(ctxt, elemDecl);
05248     if (elemDecl->contModel == NULL) {
05249     return(-1);
05250     } else {
05251     xmlRegExecCtxtPtr exec;
05252 
05253     if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
05254         return(-1);
05255     }
05256     ctxt->nodeMax = 0;
05257     ctxt->nodeNr = 0;
05258     ctxt->nodeTab = NULL;
05259     exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
05260     if (exec != NULL) {
05261         cur = child;
05262         while (cur != NULL) {
05263         switch (cur->type) {
05264             case XML_ENTITY_REF_NODE:
05265             /*
05266              * Push the current node to be able to roll back
05267              * and process within the entity
05268              */
05269             if ((cur->children != NULL) &&
05270                 (cur->children->children != NULL)) {
05271                 nodeVPush(ctxt, cur);
05272                 cur = cur->children->children;
05273                 continue;
05274             }
05275             break;
05276             case XML_TEXT_NODE:
05277             if (xmlIsBlankNode(cur))
05278                 break;
05279             ret = 0;
05280             goto fail;
05281             case XML_CDATA_SECTION_NODE:
05282             /* TODO */
05283             ret = 0;
05284             goto fail;
05285             case XML_ELEMENT_NODE:
05286             if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
05287                 xmlChar fn[50];
05288                 xmlChar *fullname;
05289                 
05290                 fullname = xmlBuildQName(cur->name,
05291                                      cur->ns->prefix, fn, 50);
05292                 if (fullname == NULL) {
05293                 ret = -1;
05294                 goto fail;
05295                 }
05296                             ret = xmlRegExecPushString(exec, fullname, NULL);
05297                 if ((fullname != fn) && (fullname != cur->name))
05298                 xmlFree(fullname);
05299             } else {
05300                 ret = xmlRegExecPushString(exec, cur->name, NULL);
05301             }
05302             break;
05303             default:
05304             break;
05305         }
05306         /*
05307          * Switch to next element
05308          */
05309         cur = cur->next;
05310         while (cur == NULL) {
05311             cur = nodeVPop(ctxt);
05312             if (cur == NULL)
05313             break;
05314             cur = cur->next;
05315         }
05316         }
05317         ret = xmlRegExecPushString(exec, NULL, NULL);
05318 fail:
05319         xmlRegFreeExecCtxt(exec);
05320     }
05321     }
05322 #else  /* LIBXML_REGEXP_ENABLED */
05323     /*
05324      * Allocate the stack
05325      */
05326     ctxt->vstateMax = 8;
05327     ctxt->vstateTab = (xmlValidState *) xmlMalloc(
05328          ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
05329     if (ctxt->vstateTab == NULL) {
05330     xmlVErrMemory(ctxt, "malloc failed");
05331     return(-1);
05332     }
05333     /*
05334      * The first entry in the stack is reserved to the current state
05335      */
05336     ctxt->nodeMax = 0;
05337     ctxt->nodeNr = 0;
05338     ctxt->nodeTab = NULL;
05339     ctxt->vstate = &ctxt->vstateTab[0];
05340     ctxt->vstateNr = 1;
05341     CONT = cont;
05342     NODE = child;
05343     DEPTH = 0;
05344     OCCURS = 0;
05345     STATE = 0;
05346     ret = xmlValidateElementType(ctxt);
05347     if ((ret == -3) && (warn)) {
05348     xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
05349            "Content model for Element %s is ambiguous\n",
05350                        name, NULL, NULL);
05351     } else if (ret == -2) {
05352     /*
05353      * An entities reference appeared at this level.
05354      * Buid a minimal representation of this node content
05355      * sufficient to run the validation process on it
05356      */
05357     DEBUG_VALID_MSG("Found an entity reference, linearizing");
05358     cur = child;
05359     while (cur != NULL) {
05360         switch (cur->type) {
05361         case XML_ENTITY_REF_NODE:
05362             /*
05363              * Push the current node to be able to roll back
05364              * and process within the entity
05365              */
05366             if ((cur->children != NULL) &&
05367             (cur->children->children != NULL)) {
05368             nodeVPush(ctxt, cur);
05369             cur = cur->children->children;
05370             continue;
05371             }
05372             break;
05373         case XML_TEXT_NODE:
05374             if (xmlIsBlankNode(cur))
05375             break;
05376             /* no break on purpose */
05377         case XML_CDATA_SECTION_NODE:
05378             /* no break on purpose */
05379         case XML_ELEMENT_NODE:
05380             /*
05381              * Allocate a new node and minimally fills in
05382              * what's required
05383              */
05384             tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
05385             if (tmp == NULL) {
05386             xmlVErrMemory(ctxt, "malloc failed");
05387             xmlFreeNodeList(repl);
05388             ret = -1;
05389             goto done;
05390             }
05391             tmp->type = cur->type;
05392             tmp->name = cur->name;
05393             tmp->ns = cur->ns;
05394             tmp->next = NULL;
05395             tmp->content = NULL;
05396             if (repl == NULL)
05397             repl = last = tmp;
05398             else {
05399             last->next = tmp;
05400             last = tmp;
05401             }
05402             if (cur->type == XML_CDATA_SECTION_NODE) {
05403             /* 
05404              * E59 spaces in CDATA does not match the
05405              * nonterminal S
05406              */
05407             tmp->content = xmlStrdup(BAD_CAST "CDATA");
05408             }
05409             break;
05410         default:
05411             break;
05412         }
05413         /*
05414          * Switch to next element
05415          */
05416         cur = cur->next;
05417         while (cur == NULL) {
05418         cur = nodeVPop(ctxt);
05419         if (cur == NULL)
05420             break;
05421         cur = cur->next;
05422         }
05423     }
05424 
05425     /*
05426      * Relaunch the validation
05427      */
05428     ctxt->vstate = &ctxt->vstateTab[0];
05429     ctxt->vstateNr = 1;
05430     CONT = cont;
05431     NODE = repl;
05432     DEPTH = 0;
05433     OCCURS = 0;
05434     STATE = 0;
05435     ret = xmlValidateElementType(ctxt);
05436     }
05437 #endif /* LIBXML_REGEXP_ENABLED */
05438     if ((warn) && ((ret != 1) && (ret != -3))) {
05439     if (ctxt != NULL) {
05440         char expr[5000];
05441         char list[5000];
05442 
05443         expr[0] = 0;
05444         xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
05445         list[0] = 0;
05446 #ifndef LIBXML_REGEXP_ENABLED
05447         if (repl != NULL)
05448         xmlSnprintfElements(&list[0], 5000, repl, 1);
05449         else
05450 #endif /* LIBXML_REGEXP_ENABLED */
05451         xmlSnprintfElements(&list[0], 5000, child, 1);
05452 
05453         if (name != NULL) {
05454         xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
05455        "Element %s content does not follow the DTD, expecting %s, got %s\n",
05456                name, BAD_CAST expr, BAD_CAST list);
05457         } else {
05458         xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
05459        "Element content does not follow the DTD, expecting %s, got %s\n",
05460                BAD_CAST expr, BAD_CAST list, NULL);
05461         }
05462     } else {
05463         if (name != NULL) {
05464         xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
05465                "Element %s content does not follow the DTD\n",
05466                name, NULL, NULL);
05467         } else {
05468         xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
05469                "Element content does not follow the DTD\n",
05470                         NULL, NULL, NULL);
05471         }
05472     }
05473     ret = 0;
05474     }
05475     if (ret == -3)
05476     ret = 1;
05477 
05478 #ifndef  LIBXML_REGEXP_ENABLED
05479 done:
05480     /*
05481      * Deallocate the copy if done, and free up the validation stack
05482      */
05483     while (repl != NULL) {
05484     tmp = repl->next;
05485     xmlFree(repl);
05486     repl = tmp;
05487     }
05488     ctxt->vstateMax = 0;
05489     if (ctxt->vstateTab != NULL) {
05490     xmlFree(ctxt->vstateTab);
05491     ctxt->vstateTab = NULL;
05492     }
05493 #endif
05494     ctxt->nodeMax = 0;
05495     ctxt->nodeNr = 0;
05496     if (ctxt->nodeTab != NULL) {
05497     xmlFree(ctxt->nodeTab);
05498     ctxt->nodeTab = NULL;
05499     }
05500     return(ret);
05501 
05502 }
05503 
05514 static int
05515 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
05516                            xmlNodePtr elem) {
05517     int ret = 1;
05518     xmlNodePtr cur, child;
05519 
05520     if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
05521     return(0);
05522 
05523     child = elem->children;
05524 
05525     cur = child;
05526     while (cur != NULL) {
05527     switch (cur->type) {
05528         case XML_ENTITY_REF_NODE:
05529         /*
05530          * Push the current node to be able to roll back
05531          * and process within the entity
05532          */
05533         if ((cur->children != NULL) &&
05534             (cur->children->children != NULL)) {
05535             nodeVPush(ctxt, cur);
05536             cur = cur->children->children;
05537             continue;
05538         }
05539         break;
05540         case XML_COMMENT_NODE:
05541         case XML_PI_NODE:
05542         case XML_TEXT_NODE:
05543         case XML_CDATA_SECTION_NODE:
05544         break;
05545         default:
05546         ret = 0;
05547         goto done;
05548     }
05549     /*
05550      * Switch to next element
05551      */
05552     cur = cur->next;
05553     while (cur == NULL) {
05554         cur = nodeVPop(ctxt);
05555         if (cur == NULL)
05556         break;
05557         cur = cur->next;
05558     }
05559     }
05560 done:
05561     ctxt->nodeMax = 0;
05562     ctxt->nodeNr = 0;
05563     if (ctxt->nodeTab != NULL) {
05564     xmlFree(ctxt->nodeTab);
05565     ctxt->nodeTab = NULL;
05566     }
05567     return(ret);
05568 }
05569 
05580 static int
05581 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
05582                   xmlElementContentPtr cont, const xmlChar *qname) {
05583     const xmlChar *name;
05584     int plen;
05585     name = xmlSplitQName3(qname, &plen);
05586 
05587     if (name == NULL) {
05588     while (cont != NULL) {
05589         if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
05590         if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
05591             return(1);
05592         } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
05593            (cont->c1 != NULL) &&
05594            (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
05595         if ((cont->c1->prefix == NULL) &&
05596             (xmlStrEqual(cont->c1->name, qname)))
05597             return(1);
05598         } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
05599         (cont->c1 == NULL) ||
05600         (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
05601         xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, 
05602             "Internal: MIXED struct corrupted\n",
05603             NULL);
05604         break;
05605         }
05606         cont = cont->c2;
05607     }
05608     } else {
05609     while (cont != NULL) {
05610         if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
05611         if ((cont->prefix != NULL) &&
05612             (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
05613             (xmlStrEqual(cont->name, name)))
05614             return(1);
05615         } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
05616            (cont->c1 != NULL) &&
05617            (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
05618         if ((cont->c1->prefix != NULL) &&
05619             (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
05620             (xmlStrEqual(cont->c1->name, name)))
05621             return(1);
05622         } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
05623         (cont->c1 == NULL) ||
05624         (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
05625         xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, 
05626             "Internal: MIXED struct corrupted\n",
05627             NULL);
05628         break;
05629         }
05630         cont = cont->c2;
05631     }
05632     }
05633     return(0);
05634 }
05635 
05648 static xmlElementPtr
05649 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
05650                 xmlNodePtr elem, int *extsubset) {
05651     xmlElementPtr elemDecl = NULL;
05652     const xmlChar *prefix = NULL;
05653 
05654     if ((ctxt == NULL) || (doc == NULL) || 
05655         (elem == NULL) || (elem->name == NULL))
05656         return(NULL);
05657     if (extsubset != NULL)
05658     *extsubset = 0;
05659 
05660     /*
05661      * Fetch the declaration for the qualified name
05662      */
05663     if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
05664     prefix = elem->ns->prefix;
05665 
05666     if (prefix != NULL) {
05667     elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
05668                                  elem->name, prefix);
05669     if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
05670         elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
05671                                      elem->name, prefix);
05672         if ((elemDecl != NULL) && (extsubset != NULL))
05673         *extsubset = 1;
05674     }
05675     }
05676 
05677     /*
05678      * Fetch the declaration for the non qualified name
05679      * This is "non-strict" validation should be done on the
05680      * full QName but in that case being flexible makes sense.
05681      */
05682     if (elemDecl == NULL) {
05683     elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
05684     if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
05685         elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
05686         if ((elemDecl != NULL) && (extsubset != NULL))
05687         *extsubset = 1;
05688     }
05689     }
05690     if (elemDecl == NULL) {
05691     xmlErrValidNode(ctxt, elem,
05692             XML_DTD_UNKNOWN_ELEM,
05693            "No declaration for element %s\n",
05694            elem->name, NULL, NULL);
05695     }
05696     return(elemDecl);
05697 }
05698 
05699 #ifdef LIBXML_REGEXP_ENABLED
05700 
05711 int
05712 xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
05713                        xmlNodePtr elem, const xmlChar *qname) {
05714     int ret = 1;
05715     xmlElementPtr eDecl;
05716     int extsubset = 0;
05717 
05718     if (ctxt == NULL)
05719         return(0);
05720 /* printf("PushElem %s\n", qname); */
05721     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
05722     xmlValidStatePtr state = ctxt->vstate;
05723     xmlElementPtr elemDecl;
05724 
05725     /*
05726      * Check the new element agaisnt the content model of the new elem.
05727      */
05728     if (state->elemDecl != NULL) {
05729         elemDecl = state->elemDecl;
05730 
05731         switch(elemDecl->etype) {
05732         case XML_ELEMENT_TYPE_UNDEFINED:
05733             ret = 0;
05734             break;
05735         case XML_ELEMENT_TYPE_EMPTY:
05736             xmlErrValidNode(ctxt, state->node,
05737                     XML_DTD_NOT_EMPTY,
05738            "Element %s was declared EMPTY this one has content\n",
05739                state->node->name, NULL, NULL);
05740             ret = 0;
05741             break;
05742         case XML_ELEMENT_TYPE_ANY:
05743             /* I don't think anything is required then */
05744             break;
05745         case XML_ELEMENT_TYPE_MIXED:
05746             /* simple case of declared as #PCDATA */
05747             if ((elemDecl->content != NULL) &&
05748             (elemDecl->content->type ==
05749              XML_ELEMENT_CONTENT_PCDATA)) {
05750             xmlErrValidNode(ctxt, state->node,
05751                     XML_DTD_NOT_PCDATA,
05752            "Element %s was declared #PCDATA but contains non text nodes\n",
05753                 state->node->name, NULL, NULL);
05754             ret = 0;
05755             } else {
05756             ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
05757                                     qname);
05758             if (ret != 1) {
05759                 xmlErrValidNode(ctxt, state->node,
05760                         XML_DTD_INVALID_CHILD,
05761            "Element %s is not declared in %s list of possible children\n",
05762                     qname, state->node->name, NULL);
05763             }
05764             }
05765             break;
05766         case XML_ELEMENT_TYPE_ELEMENT:
05767             /*
05768              * TODO:
05769              * VC: Standalone Document Declaration
05770              *     - element types with element content, if white space
05771              *       occurs directly within any instance of those types.
05772              */
05773             if (state->exec != NULL) {
05774             ret = xmlRegExecPushString(state->exec, qname, NULL);
05775             if (ret < 0) {
05776                 xmlErrValidNode(ctxt, state->node,
05777                         XML_DTD_CONTENT_MODEL,
05778            "Element %s content does not follow the DTD, Misplaced %s\n",
05779                    state->node->name, qname, NULL);
05780                 ret = 0;
05781             } else {
05782                 ret = 1;
05783             }
05784             }
05785             break;
05786         }
05787     }
05788     }
05789     eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
05790     vstateVPush(ctxt, eDecl, elem);
05791     return(ret);
05792 }
05793 
05804 int
05805 xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
05806     int ret = 1;
05807 
05808 /* printf("CDATA %s %d\n", data, len); */
05809     if (ctxt == NULL)
05810         return(0);
05811     if (len <= 0)
05812     return(ret);
05813     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
05814     xmlValidStatePtr state = ctxt->vstate;
05815     xmlElementPtr elemDecl;
05816 
05817     /*
05818      * Check the new element agaisnt the content model of the new elem.
05819      */
05820     if (state->elemDecl != NULL) {
05821         elemDecl = state->elemDecl;
05822 
05823         switch(elemDecl->etype) {
05824         case XML_ELEMENT_TYPE_UNDEFINED:
05825             ret = 0;
05826             break;
05827         case XML_ELEMENT_TYPE_EMPTY:
05828             xmlErrValidNode(ctxt, state->node,
05829                     XML_DTD_NOT_EMPTY,
05830            "Element %s was declared EMPTY this one has content\n",
05831                state->node->name, NULL, NULL);
05832             ret = 0;
05833             break;
05834         case XML_ELEMENT_TYPE_ANY:
05835             break;
05836         case XML_ELEMENT_TYPE_MIXED:
05837             break;
05838         case XML_ELEMENT_TYPE_ELEMENT:
05839             if (len > 0) {
05840             int i;
05841 
05842             for (i = 0;i < len;i++) {
05843                 if (!IS_BLANK_CH(data[i])) {
05844                 xmlErrValidNode(ctxt, state->node,
05845                         XML_DTD_CONTENT_MODEL,
05846        "Element %s content does not follow the DTD, Text not allowed\n",
05847                        state->node->name, NULL, NULL);
05848                 ret = 0;
05849                 goto done;
05850                 }
05851             }
05852             /*
05853              * TODO:
05854              * VC: Standalone Document Declaration
05855              *  element types with element content, if white space
05856              *  occurs directly within any instance of those types.
05857              */
05858             }
05859             break;
05860         }
05861     }
05862     }
05863 done:
05864     return(ret);
05865 }
05866 
05878 int
05879 xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
05880                       xmlNodePtr elem ATTRIBUTE_UNUSED,
05881               const xmlChar *qname ATTRIBUTE_UNUSED) {
05882     int ret = 1;
05883 
05884     if (ctxt == NULL)
05885         return(0);
05886 /* printf("PopElem %s\n", qname); */
05887     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
05888     xmlValidStatePtr state = ctxt->vstate;
05889     xmlElementPtr elemDecl;
05890 
05891     /*
05892      * Check the new element agaisnt the content model of the new elem.
05893      */
05894     if (state->elemDecl != NULL) {
05895         elemDecl = state->elemDecl;
05896 
05897         if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
05898         if (state->exec != NULL) {
05899             ret = xmlRegExecPushString(state->exec, NULL, NULL);
05900             if (ret == 0) {
05901             xmlErrValidNode(ctxt, state->node,
05902                             XML_DTD_CONTENT_MODEL,
05903        "Element %s content does not follow the DTD, Expecting more child\n",
05904                    state->node->name, NULL,NULL);
05905             } else {
05906             /*
05907              * previous validation errors should not generate
05908              * a new one here
05909              */
05910             ret = 1;
05911             }
05912         }
05913         }
05914     }
05915     vstateVPop(ctxt);
05916     }
05917     return(ret);
05918 }
05919 #endif /* LIBXML_REGEXP_ENABLED */
05920 
05939 int
05940 xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
05941                       xmlNodePtr elem) {
05942     xmlElementPtr elemDecl = NULL;
05943     xmlElementContentPtr cont;
05944     xmlAttributePtr attr;
05945     xmlNodePtr child;
05946     int ret = 1, tmp;
05947     const xmlChar *name;
05948     int extsubset = 0;
05949 
05950     CHECK_DTD;
05951 
05952     if (elem == NULL) return(0);
05953     switch (elem->type) {
05954         case XML_ATTRIBUTE_NODE:
05955         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
05956            "Attribute element not expected\n", NULL, NULL ,NULL);
05957         return(0);
05958         case XML_TEXT_NODE:
05959         if (elem->children != NULL) {
05960         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
05961                         "Text element has children !\n",
05962                 NULL,NULL,NULL);
05963         return(0);
05964         }
05965         if (elem->ns != NULL) {
05966         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
05967                         "Text element has namespace !\n",
05968                 NULL,NULL,NULL);
05969         return(0);
05970         }
05971         if (elem->content == NULL) {
05972         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
05973                         "Text element has no content !\n",
05974                 NULL,NULL,NULL);
05975         return(0);
05976         }
05977         return(1);
05978         case XML_XINCLUDE_START:
05979         case XML_XINCLUDE_END:
05980             return(1);
05981         case XML_CDATA_SECTION_NODE:
05982         case XML_ENTITY_REF_NODE:
05983         case XML_PI_NODE:
05984         case XML_COMMENT_NODE:
05985         return(1);
05986         case XML_ENTITY_NODE:
05987         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
05988            "Entity element not expected\n", NULL, NULL ,NULL);
05989         return(0);
05990         case XML_NOTATION_NODE:
05991         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
05992            "Notation element not expected\n", NULL, NULL ,NULL);
05993         return(0);
05994         case XML_DOCUMENT_NODE:
05995         case XML_DOCUMENT_TYPE_NODE:
05996         case XML_DOCUMENT_FRAG_NODE:
05997         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
05998            "Document element not expected\n", NULL, NULL ,NULL);
05999         return(0);
06000         case XML_HTML_DOCUMENT_NODE:
06001         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
06002            "HTML Document not expected\n", NULL, NULL ,NULL);
06003         return(0);
06004         case XML_ELEMENT_NODE:
06005         break;
06006     default:
06007         xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
06008            "unknown element type\n", NULL, NULL ,NULL);
06009         return(0);
06010     }
06011 
06012     /*
06013      * Fetch the declaration
06014      */
06015     elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
06016     if (elemDecl == NULL)
06017     return(0);
06018 
06019     /*
06020      * If vstateNr is not zero that means continuous validation is 
06021      * activated, do not try to check the content model at that level.
06022      */
06023     if (ctxt->vstateNr == 0) {
06024     /* Check that the element content matches the definition */
06025     switch (elemDecl->etype) {
06026         case XML_ELEMENT_TYPE_UNDEFINED:
06027         xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
06028                         "No declaration for element %s\n",
06029            elem->name, NULL, NULL);
06030         return(0);
06031         case XML_ELEMENT_TYPE_EMPTY:
06032         if (elem->children != NULL) {
06033         xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
06034            "Element %s was declared EMPTY this one has content\n",
06035                    elem->name, NULL, NULL);
06036         ret = 0;
06037         }
06038         break;
06039         case XML_ELEMENT_TYPE_ANY:
06040         /* I don't think anything is required then */
06041         break;
06042         case XML_ELEMENT_TYPE_MIXED:
06043 
06044         /* simple case of declared as #PCDATA */
06045         if ((elemDecl->content != NULL) &&
06046         (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
06047         ret = xmlValidateOneCdataElement(ctxt, doc, elem);
06048         if (!ret) {
06049             xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
06050            "Element %s was declared #PCDATA but contains non text nodes\n",
06051                elem->name, NULL, NULL);
06052         }
06053         break;
06054         }
06055         child = elem->children;
06056         /* Hum, this start to get messy */
06057         while (child != NULL) {
06058             if (child->type == XML_ELEMENT_NODE) {
06059             name = child->name;
06060             if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
06061             xmlChar fn[50];
06062             xmlChar *fullname;
06063             
06064             fullname = xmlBuildQName(child->name, child->ns->prefix,
06065                                  fn, 50);
06066             if (fullname == NULL)
06067                 return(0);
06068             cont = elemDecl->content;
06069             while (cont != NULL) {
06070                 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
06071                 if (xmlStrEqual(cont->name, fullname))
06072                     break;
06073                 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
06074                    (cont->c1 != NULL) &&
06075                    (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
06076                 if (xmlStrEqual(cont->c1->name, fullname))
06077                     break;
06078                 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
06079                 (cont->c1 == NULL) ||
06080                 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
06081                 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, 
06082                     "Internal: MIXED struct corrupted\n",
06083                     NULL);
06084                 break;
06085                 }
06086                 cont = cont->c2;
06087             }
06088             if ((fullname != fn) && (fullname != child->name))
06089                 xmlFree(fullname);
06090             if (cont != NULL)
06091                 goto child_ok;
06092             }
06093             cont = elemDecl->content;
06094             while (cont != NULL) {
06095                 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
06096                 if (xmlStrEqual(cont->name, name)) break;
06097             } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
06098                (cont->c1 != NULL) &&
06099                (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
06100                 if (xmlStrEqual(cont->c1->name, name)) break;
06101             } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
06102                 (cont->c1 == NULL) ||
06103                 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
06104                 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, 
06105                     "Internal: MIXED struct corrupted\n",
06106                     NULL);
06107                 break;
06108             }
06109             cont = cont->c2;
06110             }
06111             if (cont == NULL) {
06112             xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
06113            "Element %s is not declared in %s list of possible children\n",
06114                    name, elem->name, NULL);
06115             ret = 0;
06116             }
06117         }
06118 child_ok:
06119             child = child->next;
06120         }
06121         break;
06122         case XML_ELEMENT_TYPE_ELEMENT:
06123         if ((doc->standalone == 1) && (extsubset == 1)) {
06124         /*
06125          * VC: Standalone Document Declaration
06126          *     - element types with element content, if white space
06127          *       occurs directly within any instance of those types.
06128          */
06129         child = elem->children;
06130         while (child != NULL) {
06131             if (child->type == XML_TEXT_NODE) {
06132             const xmlChar *content = child->content;
06133 
06134             while (IS_BLANK_CH(*content))
06135                 content++;
06136             if (*content == 0) {
06137                 xmlErrValidNode(ctxt, elem,
06138                                 XML_DTD_STANDALONE_WHITE_SPACE,
06139 "standalone: %s declared in the external subset contains white spaces nodes\n",
06140                    elem->name, NULL, NULL);
06141                 ret = 0;
06142                 break;
06143             }
06144             }
06145             child =child->next;
06146         }
06147         }
06148         child = elem->children;
06149         cont = elemDecl->content;
06150         tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
06151         if (tmp <= 0)
06152         ret = tmp;
06153         break;
06154     }
06155     } /* not continuous */
06156 
06157     /* [ VC: Required Attribute ] */
06158     attr = elemDecl->attributes;
06159     while (attr != NULL) {
06160     if (attr->def == XML_ATTRIBUTE_REQUIRED) {
06161         int qualified = -1;
06162 
06163         if ((attr->prefix == NULL) &&
06164         (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
06165         xmlNsPtr ns;
06166 
06167         ns = elem->nsDef;
06168         while (ns != NULL) {
06169             if (ns->prefix == NULL)
06170             goto found;
06171             ns = ns->next;
06172         }
06173         } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
06174         xmlNsPtr ns;
06175 
06176         ns = elem->nsDef;
06177         while (ns != NULL) {
06178             if (xmlStrEqual(attr->name, ns->prefix))
06179             goto found;
06180             ns = ns->next;
06181         }
06182         } else {
06183         xmlAttrPtr attrib;
06184         
06185         attrib = elem->properties;
06186         while (attrib != NULL) {
06187             if (xmlStrEqual(attrib->name, attr->name)) {
06188             if (attr->prefix != NULL) {
06189                 xmlNsPtr nameSpace = attrib->ns;
06190 
06191                 if (nameSpace == NULL)
06192                 nameSpace = elem->ns;
06193                 /*
06194                  * qualified names handling is problematic, having a
06195                  * different prefix should be possible but DTDs don't
06196                  * allow to define the URI instead of the prefix :-(
06197                  */
06198                 if (nameSpace == NULL) {
06199                 if (qualified < 0) 
06200                     qualified = 0;
06201                 } else if (!xmlStrEqual(nameSpace->prefix,
06202                             attr->prefix)) {
06203                 if (qualified < 1) 
06204                     qualified = 1;
06205                 } else
06206                 goto found;
06207             } else {
06208                 /*
06209                  * We should allow applications to define namespaces
06210                  * for their application even if the DTD doesn't 
06211                  * carry one, otherwise, basically we would always
06212                  * break.
06213                  */
06214                 goto found;
06215             }
06216             }
06217             attrib = attrib->next;
06218         }
06219         }
06220         if (qualified == -1) {
06221         if (attr->prefix == NULL) {
06222             xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
06223                "Element %s does not carry attribute %s\n",
06224                elem->name, attr->name, NULL);
06225             ret = 0;
06226             } else {
06227             xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
06228                "Element %s does not carry attribute %s:%s\n",
06229                elem->name, attr->prefix,attr->name);
06230             ret = 0;
06231         }
06232         } else if (qualified == 0) {
06233         xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
06234            "Element %s required attribute %s:%s has no prefix\n",
06235                elem->name, attr->prefix, attr->name);
06236         } else if (qualified == 1) {
06237         xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
06238            "Element %s required attribute %s:%s has different prefix\n",
06239                elem->name, attr->prefix, attr->name);
06240         }
06241     } else if (attr->def == XML_ATTRIBUTE_FIXED) {
06242         /*
06243          * Special tests checking #FIXED namespace declarations
06244          * have the right value since this is not done as an
06245          * attribute checking
06246          */
06247         if ((attr->prefix == NULL) &&
06248         (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
06249         xmlNsPtr ns;
06250 
06251         ns = elem->nsDef;
06252         while (ns != NULL) {
06253             if (ns->prefix == NULL) {
06254             if (!xmlStrEqual(attr->defaultValue, ns->href)) {
06255                 xmlErrValidNode(ctxt, elem,
06256                        XML_DTD_ELEM_DEFAULT_NAMESPACE,
06257    "Element %s namespace name for default namespace does not match the DTD\n",
06258                    elem->name, NULL, NULL);
06259                 ret = 0;
06260             }
06261             goto found;
06262             }
06263             ns = ns->next;
06264         }
06265         } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
06266         xmlNsPtr ns;
06267 
06268         ns = elem->nsDef;
06269         while (ns != NULL) {
06270             if (xmlStrEqual(attr->name, ns->prefix)) {
06271             if (!xmlStrEqual(attr->defaultValue, ns->href)) {
06272                 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
06273            "Element %s namespace name for %s does not match the DTD\n",
06274                    elem->name, ns->prefix, NULL);
06275                 ret = 0;
06276             }
06277             goto found;
06278             }
06279             ns = ns->next;
06280         }
06281         }
06282     }
06283 found:      
06284         attr = attr->nexth;
06285     }
06286     return(ret);
06287 }
06288 
06303 int
06304 xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
06305     xmlNodePtr root;
06306     int ret;
06307 
06308     if (doc == NULL) return(0);
06309 
06310     root = xmlDocGetRootElement(doc);
06311     if ((root == NULL) || (root->name == NULL)) {
06312     xmlErrValid(ctxt, XML_DTD_NO_ROOT,
06313                 "no root element\n", NULL);
06314         return(0);
06315     }
06316 
06317     /*
06318      * When doing post validation against a separate DTD, those may
06319      * no internal subset has been generated
06320      */
06321     if ((doc->intSubset != NULL) &&
06322     (doc->intSubset->name != NULL)) {
06323     /*
06324      * Check first the document root against the NQName
06325      */
06326     if (!xmlStrEqual(doc->intSubset->name, root->name)) {
06327         if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
06328         xmlChar fn[50];
06329         xmlChar *fullname;
06330         
06331         fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
06332         if (fullname == NULL) {
06333             xmlVErrMemory(ctxt, NULL);
06334             return(0);
06335         }
06336         ret = xmlStrEqual(doc->intSubset->name, fullname);
06337         if ((fullname != fn) && (fullname != root->name))
06338             xmlFree(fullname);
06339         if (ret == 1)
06340             goto name_ok;
06341         } 
06342         if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
06343         (xmlStrEqual(root->name, BAD_CAST "html")))
06344         goto name_ok;
06345         xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
06346            "root and DTD name do not match '%s' and '%s'\n",
06347            root->name, doc->intSubset->name, NULL);
06348         return(0);
06349     }
06350     }
06351 name_ok:
06352     return(1);
06353 }
06354 
06355 
06367 int
06368 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
06369     xmlNodePtr child;
06370     xmlAttrPtr attr;
06371     xmlNsPtr ns;
06372     const xmlChar *value;
06373     int ret = 1;
06374 
06375     if (elem == NULL) return(0);
06376 
06377     /*
06378      * XInclude elements were added after parsing in the infoset,
06379      * they don't really mean anything validation wise.
06380      */
06381     if ((elem->type == XML_XINCLUDE_START) ||
06382     (elem->type == XML_XINCLUDE_END))
06383     return(1);
06384 
06385     CHECK_DTD;
06386 
06387     /*
06388      * Entities references have to be handled separately
06389      */
06390     if (elem->type == XML_ENTITY_REF_NODE) {
06391     return(1);
06392     }
06393 
06394     ret &= xmlValidateOneElement(ctxt, doc, elem);
06395     if (elem->type == XML_ELEMENT_NODE) {
06396     attr = elem->properties;
06397     while (attr != NULL) {
06398         value = xmlNodeListGetString(doc, attr->children, 0);
06399         ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
06400         if (value != NULL)
06401         xmlFree((char *)value);
06402         attr= attr->next;
06403     }
06404     ns = elem->nsDef;
06405     while (ns != NULL) {
06406         if (elem->ns == NULL)
06407         ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
06408                            ns, ns->href);
06409         else
06410         ret &= xmlValidateOneNamespace(ctxt, doc, elem,
06411                                        elem->ns->prefix, ns, ns->href);
06412         ns = ns->next;
06413     }
06414     }
06415     child = elem->children;
06416     while (child != NULL) {
06417         ret &= xmlValidateElement(ctxt, doc, child);
06418         child = child->next;
06419     }
06420 
06421     return(ret);
06422 }
06423 
06431 static void
06432 xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
06433                        const xmlChar *name) {
06434     xmlAttrPtr id;
06435     xmlAttrPtr attr;
06436 
06437     if (ref == NULL)
06438     return;
06439     if ((ref->attr == NULL) && (ref->name == NULL))
06440     return;
06441     attr = ref->attr;
06442     if (attr == NULL) {
06443     xmlChar *dup, *str = NULL, *cur, save;
06444 
06445     dup = xmlStrdup(name);
06446     if (dup == NULL) {
06447         ctxt->valid = 0;
06448         return;
06449     }
06450     cur = dup;
06451     while (*cur != 0) {
06452         str = cur;
06453         while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
06454         save = *cur;
06455         *cur = 0;
06456         id = xmlGetID(ctxt->doc, str);
06457         if (id == NULL) {
06458         xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
06459        "attribute %s line %d references an unknown ID \"%s\"\n",
06460                ref->name, ref->lineno, str);
06461         ctxt->valid = 0;
06462         }
06463         if (save == 0)
06464         break;
06465         *cur = save;
06466         while (IS_BLANK_CH(*cur)) cur++;
06467     }
06468     xmlFree(dup);
06469     } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
06470     id = xmlGetID(ctxt->doc, name);
06471     if (id == NULL) {
06472         xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
06473        "IDREF attribute %s references an unknown ID \"%s\"\n",
06474            attr->name, name, NULL);
06475         ctxt->valid = 0;
06476     }
06477     } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
06478     xmlChar *dup, *str = NULL, *cur, save;
06479 
06480     dup = xmlStrdup(name);
06481     if (dup == NULL) {
06482         xmlVErrMemory(ctxt, "IDREFS split");
06483         ctxt->valid = 0;
06484         return;
06485     }
06486     cur = dup;
06487     while (*cur != 0) {
06488         str = cur;
06489         while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
06490         save = *cur;
06491         *cur = 0;
06492         id = xmlGetID(ctxt->doc, str);
06493         if (id == NULL) {
06494         xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
06495        "IDREFS attribute %s references an unknown ID \"%s\"\n",
06496                  attr->name, str, NULL);
06497         ctxt->valid = 0;
06498         }
06499         if (save == 0)
06500         break;
06501         *cur = save;
06502         while (IS_BLANK_CH(*cur)) cur++;
06503     }
06504     xmlFree(dup);
06505     }
06506 }
06507 
06515 static int
06516 xmlWalkValidateList(const void *data, const void *user)
06517 {
06518     xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
06519     xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
06520     return 1;
06521 }
06522 
06530 static void
06531 xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
06532                        const xmlChar *name) {
06533     xmlValidateMemo memo;
06534 
06535     if (ref_list == NULL)
06536     return;
06537     memo.ctxt = ctxt;
06538     memo.name = name;
06539 
06540     xmlListWalk(ref_list, xmlWalkValidateList, &memo);
06541     
06542 }
06543 
06559 int
06560 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
06561     xmlRefTablePtr table;
06562 
06563     if (ctxt == NULL)
06564         return(0);
06565     if (doc == NULL) {
06566         xmlErrValid(ctxt, XML_DTD_NO_DOC, 
06567         "xmlValidateDocumentFinal: doc == NULL\n", NULL);
06568     return(0);
06569     }
06570 
06571     /*
06572      * Check all the NOTATION/NOTATIONS attributes
06573      */
06574     /*
06575      * Check all the ENTITY/ENTITIES attributes definition for validity
06576      */
06577     /*
06578      * Check all the IDREF/IDREFS attributes definition for validity
06579      */
06580     table = (xmlRefTablePtr) doc->refs;
06581     ctxt->doc = doc;
06582     ctxt->valid = 1;
06583     xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
06584     return(ctxt->valid);
06585 }
06586 
06603 int
06604 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
06605     int ret;
06606     xmlDtdPtr oldExt, oldInt;
06607     xmlNodePtr root;
06608 
06609     if (dtd == NULL) return(0);
06610     if (doc == NULL) return(0);
06611     oldExt = doc->extSubset;
06612     oldInt = doc->intSubset;
06613     doc->extSubset = dtd;
06614     doc->intSubset = NULL;
06615     ret = xmlValidateRoot(ctxt, doc);
06616     if (ret == 0) {
06617     doc->extSubset = oldExt;
06618     doc->intSubset = oldInt;
06619     return(ret);
06620     }
06621     if (doc->ids != NULL) {
06622           xmlFreeIDTable(doc->ids);
06623           doc->ids = NULL;
06624     }
06625     if (doc->refs != NULL) {
06626           xmlFreeRefTable(doc->refs);
06627           doc->refs = NULL;
06628     }
06629     root = xmlDocGetRootElement(doc);
06630     ret = xmlValidateElement(ctxt, doc, root);
06631     ret &= xmlValidateDocumentFinal(ctxt, doc);
06632     doc->extSubset = oldExt;
06633     doc->intSubset = oldInt;
06634     return(ret);
06635 }
06636 
06637 static void
06638 xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
06639                         const xmlChar *name ATTRIBUTE_UNUSED) {
06640     if (cur == NULL)
06641     return;
06642     if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
06643     xmlChar *notation = cur->content;
06644 
06645     if (notation != NULL) {
06646         int ret;
06647 
06648         ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
06649         if (ret != 1) {
06650         ctxt->valid = 0;
06651         }
06652     }
06653     }
06654 }
06655 
06656 static void
06657 xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
06658                         const xmlChar *name ATTRIBUTE_UNUSED) {
06659     int ret;
06660     xmlDocPtr doc;
06661     xmlElementPtr elem = NULL;
06662 
06663     if (cur == NULL)
06664     return;
06665     switch (cur->atype) {
06666     case XML_ATTRIBUTE_CDATA:
06667     case XML_ATTRIBUTE_ID:
06668     case XML_ATTRIBUTE_IDREF    :
06669     case XML_ATTRIBUTE_IDREFS:
06670     case XML_ATTRIBUTE_NMTOKEN:
06671     case XML_ATTRIBUTE_NMTOKENS:
06672     case XML_ATTRIBUTE_ENUMERATION:
06673         break;
06674     case XML_ATTRIBUTE_ENTITY:
06675     case XML_ATTRIBUTE_ENTITIES:
06676     case XML_ATTRIBUTE_NOTATION:
06677         if (cur->defaultValue != NULL) {
06678         
06679         ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
06680                                      cur->atype, cur->defaultValue);
06681         if ((ret == 0) && (ctxt->valid == 1))
06682             ctxt->valid = 0;
06683         }
06684         if (cur->tree != NULL) {
06685         xmlEnumerationPtr tree = cur->tree;
06686         while (tree != NULL) {
06687             ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
06688                     cur->name, cur->atype, tree->name);
06689             if ((ret == 0) && (ctxt->valid == 1))
06690             ctxt->valid = 0;
06691             tree = tree->next;
06692         }
06693         }
06694     }
06695     if (cur->atype == XML_ATTRIBUTE_NOTATION) {
06696     doc = cur->doc;
06697     if (cur->elem == NULL) {
06698         xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
06699            "xmlValidateAttributeCallback(%s): internal error\n",
06700            (const char *) cur->name);
06701         return;
06702     }
06703 
06704     if (doc != NULL)
06705         elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
06706     if ((elem == NULL) && (doc != NULL))
06707         elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
06708     if ((elem == NULL) && (cur->parent != NULL) &&
06709         (cur->parent->type == XML_DTD_NODE))
06710         elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
06711     if (elem == NULL) {
06712         xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
06713            "attribute %s: could not find decl for element %s\n",
06714            cur->name, cur->elem, NULL);
06715         return;
06716     }
06717     if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
06718         xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
06719            "NOTATION attribute %s declared for EMPTY element %s\n",
06720            cur->name, cur->elem, NULL);
06721         ctxt->valid = 0;
06722     }
06723     }
06724 }
06725 
06743 int
06744 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
06745     xmlDtdPtr dtd;
06746     xmlAttributeTablePtr table;
06747     xmlEntitiesTablePtr entities;
06748 
06749     if ((doc == NULL) || (ctxt == NULL)) return(0);
06750     if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
06751     return(0);
06752     ctxt->doc = doc;
06753     ctxt->valid = 1;
06754     dtd = doc->intSubset;
06755     if ((dtd != NULL) && (dtd->attributes != NULL)) {
06756     table = (xmlAttributeTablePtr) dtd->attributes;
06757     xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
06758     }
06759     if ((dtd != NULL) && (dtd->entities != NULL)) {
06760     entities = (xmlEntitiesTablePtr) dtd->entities;
06761     xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
06762             ctxt);
06763     }
06764     dtd = doc->extSubset;
06765     if ((dtd != NULL) && (dtd->attributes != NULL)) {
06766     table = (xmlAttributeTablePtr) dtd->attributes;
06767     xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
06768     }
06769     if ((dtd != NULL) && (dtd->entities != NULL)) {
06770     entities = (xmlEntitiesTablePtr) dtd->entities;
06771     xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
06772             ctxt);
06773     }
06774     return(ctxt->valid);
06775 }
06776 
06791 int
06792 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
06793     int ret;
06794     xmlNodePtr root;
06795 
06796     if (doc == NULL)
06797         return(0);
06798     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
06799         xmlErrValid(ctxt, XML_DTD_NO_DTD,
06800                 "no DTD found!\n", NULL);
06801     return(0);
06802     }
06803     if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
06804     (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
06805     xmlChar *sysID;
06806     if (doc->intSubset->SystemID != NULL) {
06807         sysID = xmlBuildURI(doc->intSubset->SystemID,
06808                 doc->URL);
06809         if (sysID == NULL) {
06810             xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
06811             "Could not build URI for external subset \"%s\"\n",
06812             (const char *) doc->intSubset->SystemID);
06813         return 0;
06814         }
06815     } else
06816         sysID = NULL;
06817         doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
06818             (const xmlChar *)sysID);
06819     if (sysID != NULL)
06820         xmlFree(sysID);
06821         if (doc->extSubset == NULL) {
06822         if (doc->intSubset->SystemID != NULL) {
06823         xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
06824                "Could not load the external subset \"%s\"\n",
06825                (const char *) doc->intSubset->SystemID);
06826         } else {
06827         xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
06828                "Could not load the external subset \"%s\"\n",
06829                (const char *) doc->intSubset->ExternalID);
06830         }
06831         return(0);
06832     }
06833     }
06834 
06835     if (doc->ids != NULL) {
06836           xmlFreeIDTable(doc->ids);
06837           doc->ids = NULL;
06838     }
06839     if (doc->refs != NULL) {
06840           xmlFreeRefTable(doc->refs);
06841           doc->refs = NULL;
06842     }
06843     ret = xmlValidateDtdFinal(ctxt, doc);
06844     if (!xmlValidateRoot(ctxt, doc)) return(0);
06845 
06846     root = xmlDocGetRootElement(doc);
06847     ret &= xmlValidateElement(ctxt, doc, root);
06848     ret &= xmlValidateDocumentFinal(ctxt, doc);
06849     return(ret);
06850 }
06851 
06852 /************************************************************************
06853  *                                  *
06854  *      Routines for dynamic validation editing         *
06855  *                                  *
06856  ************************************************************************/
06857 
06870 int
06871 xmlValidGetPotentialChildren(xmlElementContent *ctree,
06872                              const xmlChar **names,
06873                              int *len, int max) {
06874     int i;
06875 
06876     if ((ctree == NULL) || (names == NULL) || (len == NULL))
06877         return(-1);
06878     if (*len >= max) return(*len);
06879 
06880     switch (ctree->type) {
06881     case XML_ELEMENT_CONTENT_PCDATA: 
06882         for (i = 0; i < *len;i++)
06883         if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
06884         names[(*len)++] = BAD_CAST "#PCDATA";
06885         break;
06886     case XML_ELEMENT_CONTENT_ELEMENT: 
06887         for (i = 0; i < *len;i++)
06888         if (xmlStrEqual(ctree->name, names[i])) return(*len);
06889         names[(*len)++] = ctree->name;
06890         break;
06891     case XML_ELEMENT_CONTENT_SEQ: 
06892         xmlValidGetPotentialChildren(ctree->c1, names, len, max);
06893         xmlValidGetPotentialChildren(ctree->c2, names, len, max);
06894         break;
06895     case XML_ELEMENT_CONTENT_OR:
06896         xmlValidGetPotentialChildren(ctree->c1, names, len, max);
06897         xmlValidGetPotentialChildren(ctree->c2, names, len, max);
06898         break;
06899    }
06900    
06901    return(*len);
06902 }
06903 
06904 /*
06905  * Dummy function to suppress messages while we try out valid elements
06906  */
06907 static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
06908                                 const char *msg ATTRIBUTE_UNUSED, ...) {
06909     return;
06910 }
06911 
06937 int
06938 xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
06939                          int max) {
06940     xmlValidCtxt vctxt;
06941     int nb_valid_elements = 0;
06942     const xmlChar *elements[256];
06943     int nb_elements = 0, i;
06944     const xmlChar *name;
06945     
06946     xmlNode *ref_node;
06947     xmlNode *parent;
06948     xmlNode *test_node;
06949     
06950     xmlNode *prev_next;
06951     xmlNode *next_prev;
06952     xmlNode *parent_childs;
06953     xmlNode *parent_last;
06954     
06955     xmlElement *element_desc;
06956 
06957     if (prev == NULL && next == NULL)
06958         return(-1);
06959 
06960     if (names == NULL) return(-1);
06961     if (max <= 0) return(-1);
06962 
06963     memset(&vctxt, 0, sizeof (xmlValidCtxt));
06964     vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
06965 
06966     nb_valid_elements = 0;
06967     ref_node = prev ? prev : next;
06968     parent = ref_node->parent;
06969 
06970     /*
06971      * Retrieves the parent element declaration
06972      */
06973     element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
06974                                          parent->name);
06975     if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
06976         element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
06977                                              parent->name);
06978     if (element_desc == NULL) return(-1);
06979     
06980     /*
06981      * Do a backup of the current tree structure
06982      */
06983     prev_next = prev ? prev->next : NULL;
06984     next_prev = next ? next->prev : NULL;
06985     parent_childs = parent->children;
06986     parent_last = parent->last;
06987 
06988     /*
06989      * Creates a dummy node and insert it into the tree
06990      */    
06991     test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
06992     test_node->parent = parent;
06993     test_node->prev = prev;
06994     test_node->next = next;
06995     name = test_node->name;
06996     
06997     if (prev) prev->next = test_node;
06998     else parent->children = test_node;
06999         
07000     if (next) next->prev = test_node;
07001     else parent->last = test_node;
07002 
07003     /*
07004      * Insert each potential child node and check if the parent is
07005      * still valid
07006      */
07007     nb_elements = xmlValidGetPotentialChildren(element_desc->content,
07008                elements, &nb_elements, 256);
07009     
07010     for (i = 0;i < nb_elements;i++) {
07011     test_node->name = elements[i];
07012     if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
07013         int j;
07014 
07015         for (j = 0; j < nb_valid_elements;j++)
07016         if (xmlStrEqual(elements[i], names[j])) break;
07017         names[nb_valid_elements++] = elements[i];
07018         if (nb_valid_elements >= max) break;
07019     }
07020     }
07021 
07022     /*
07023      * Restore the tree structure
07024      */
07025     if (prev) prev->next = prev_next;
07026     if (next) next->prev = next_prev;
07027     parent->children = parent_childs;
07028     parent->last = parent_last;
07029 
07030     /*
07031      * Free up the dummy node
07032      */
07033     test_node->name = name;
07034     xmlFreeNode(test_node);
07035 
07036     return(nb_valid_elements);
07037 }
07038 #endif /* LIBXML_VALID_ENABLED */
07039 
07040 #define bottom_valid
07041 #include "elfgcchack.h"

Generated on Sun May 27 2012 04:34:45 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.