Annotation of embedaddon/libxml2/valid.c, revision 1.1

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

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