Annotation of XML/valid.c, revision 1.46

1.1       daniel      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@w3.org
                      8:  */
                      9: 
1.29      daniel     10: #ifdef WIN32
1.41      daniel     11: #include "win32config.h"
1.29      daniel     12: #else
1.30      daniel     13: #include "config.h"
1.29      daniel     14: #endif
                     15: 
1.1       daniel     16: #include <stdio.h>
1.29      daniel     17: #include <string.h>
                     18: 
                     19: #ifdef HAVE_STDLIB_H
1.1       daniel     20: #include <stdlib.h>
1.29      daniel     21: #endif
                     22: 
1.26      daniel     23: #include "xmlmemory.h"
1.1       daniel     24: #include "valid.h"
                     25: #include "parser.h"
1.16      daniel     26: #include "parserInternals.h"
                     27: 
1.42      daniel     28: /* TODO: use hash table for accesses to elem and attribute dedinitions */
                     29: 
1.16      daniel     30: #define VERROR                                                 \
                     31:    if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
                     32: 
                     33: #define VWARNING                                               \
                     34:    if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
                     35: 
                     36: #define CHECK_DTD                                              \
                     37:    if (doc == NULL) return(0);                                 \
                     38:    else if (doc->intSubset == NULL) return(0)
1.1       daniel     39: 
1.31      daniel     40: xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
                     41: xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
1.15      daniel     42: 
1.1       daniel     43: /****************************************************************
                     44:  *                                                             *
                     45:  *     Util functions for data allocation/deallocation         *
                     46:  *                                                             *
                     47:  ****************************************************************/
                     48: 
                     49: /**
                     50:  * xmlNewElementContent:
                     51:  * @name:  the subelement name or NULL
                     52:  * @type:  the type of element content decl
                     53:  *
                     54:  * Allocate an element content structure.
                     55:  *
1.6       daniel     56:  * Returns NULL if not, othervise the new element content structure
1.1       daniel     57:  */
                     58: xmlElementContentPtr
1.31      daniel     59: xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
1.2       daniel     60:     xmlElementContentPtr ret;
                     61: 
                     62:     switch(type) {
                     63:        case XML_ELEMENT_CONTENT_ELEMENT:
                     64:            if (name == NULL) {
                     65:                fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
                     66:            }
                     67:            break;
                     68:         case XML_ELEMENT_CONTENT_PCDATA:
                     69:        case XML_ELEMENT_CONTENT_SEQ:
                     70:        case XML_ELEMENT_CONTENT_OR:
                     71:            if (name != NULL) {
                     72:                fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
                     73:            }
                     74:            break;
                     75:        default:
                     76:            fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
1.44      daniel     77:            return(NULL);
1.2       daniel     78:     }
1.26      daniel     79:     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1.2       daniel     80:     if (ret == NULL) {
                     81:        fprintf(stderr, "xmlNewElementContent : out of memory!\n");
                     82:        return(NULL);
                     83:     }
                     84:     ret->type = type;
                     85:     ret->ocur = XML_ELEMENT_CONTENT_ONCE;
                     86:     if (name != NULL)
                     87:         ret->name = xmlStrdup(name);
                     88:     else
                     89:         ret->name = NULL;
1.4       daniel     90:     ret->c1 = ret->c2 = NULL;
1.2       daniel     91:     return(ret);
                     92: }
                     93: 
                     94: /**
                     95:  * xmlCopyElementContent:
                     96:  * @content:  An element content pointer.
                     97:  *
                     98:  * Build a copy of an element content description.
                     99:  * 
1.6       daniel    100:  * Returns the new xmlElementContentPtr or NULL in case of error.
1.2       daniel    101:  */
                    102: xmlElementContentPtr
1.4       daniel    103: xmlCopyElementContent(xmlElementContentPtr cur) {
                    104:     xmlElementContentPtr ret;
                    105: 
                    106:     if (cur == NULL) return(NULL);
1.31      daniel    107:     ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
1.11      daniel    108:     if (ret == NULL) {
                    109:         fprintf(stderr, "xmlCopyElementContent : out of memory\n");
                    110:        return(NULL);
                    111:     }
                    112:     ret->ocur = cur->ocur;
                    113:     if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
                    114:     if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
1.4       daniel    115:     return(ret);
1.1       daniel    116: }
                    117: 
                    118: /**
1.3       daniel    119:  * xmlFreeElementContent:
                    120:  * @cur:  the element content tree to free
1.1       daniel    121:  *
                    122:  * Free an element content structure. This is a recursive call !
                    123:  */
                    124: void
                    125: xmlFreeElementContent(xmlElementContentPtr cur) {
1.4       daniel    126:     if (cur == NULL) return;
                    127:     if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
                    128:     if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
1.31      daniel    129:     if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1.4       daniel    130:     memset(cur, -1, sizeof(xmlElementContent));
1.26      daniel    131:     xmlFree(cur);
1.1       daniel    132: }
                    133: 
1.3       daniel    134: /**
                    135:  * xmlDumpElementContent:
1.8       daniel    136:  * @buf:  An XML buffer
1.3       daniel    137:  * @content:  An element table
                    138:  * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
                    139:  *
                    140:  * This will dump the content of the element table as an XML DTD definition
                    141:  */
                    142: void
1.8       daniel    143: xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1.3       daniel    144:     if (content == NULL) return;
                    145: 
1.8       daniel    146:     if (glob) xmlBufferWriteChar(buf, "(");
1.3       daniel    147:     switch (content->type) {
                    148:         case XML_ELEMENT_CONTENT_PCDATA:
1.8       daniel    149:             xmlBufferWriteChar(buf, "#PCDATA");
1.3       daniel    150:            break;
                    151:        case XML_ELEMENT_CONTENT_ELEMENT:
1.8       daniel    152:            xmlBufferWriteCHAR(buf, content->name);
1.3       daniel    153:            break;
                    154:        case XML_ELEMENT_CONTENT_SEQ:
                    155:            if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
                    156:                (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1.8       daniel    157:                xmlDumpElementContent(buf, content->c1, 1);
1.3       daniel    158:            else
1.8       daniel    159:                xmlDumpElementContent(buf, content->c1, 0);
                    160:             xmlBufferWriteChar(buf, " , ");
1.3       daniel    161:            if (content->c2->type == XML_ELEMENT_CONTENT_OR)
1.8       daniel    162:                xmlDumpElementContent(buf, content->c2, 1);
1.3       daniel    163:            else
1.8       daniel    164:                xmlDumpElementContent(buf, content->c2, 0);
1.3       daniel    165:            break;
                    166:        case XML_ELEMENT_CONTENT_OR:
                    167:            if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
                    168:                (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1.8       daniel    169:                xmlDumpElementContent(buf, content->c1, 1);
1.3       daniel    170:            else
1.8       daniel    171:                xmlDumpElementContent(buf, content->c1, 0);
                    172:             xmlBufferWriteChar(buf, " | ");
1.3       daniel    173:            if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
1.8       daniel    174:                xmlDumpElementContent(buf, content->c2, 1);
1.3       daniel    175:            else
1.8       daniel    176:                xmlDumpElementContent(buf, content->c2, 0);
1.3       daniel    177:            break;
                    178:        default:
                    179:            fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
                    180:                    content->type);
                    181:     }
                    182:     if (glob)
1.8       daniel    183:         xmlBufferWriteChar(buf, ")");
1.3       daniel    184:     switch (content->ocur) {
                    185:         case XML_ELEMENT_CONTENT_ONCE:
                    186:            break;
                    187:         case XML_ELEMENT_CONTENT_OPT:
1.8       daniel    188:            xmlBufferWriteChar(buf, "?");
1.3       daniel    189:            break;
                    190:         case XML_ELEMENT_CONTENT_MULT:
1.8       daniel    191:            xmlBufferWriteChar(buf, "*");
1.3       daniel    192:            break;
                    193:         case XML_ELEMENT_CONTENT_PLUS:
1.8       daniel    194:            xmlBufferWriteChar(buf, "+");
1.3       daniel    195:            break;
                    196:     }
                    197: }
                    198: 
1.19      daniel    199: /**
                    200:  * xmlSprintfElementContent:
                    201:  * @buf:  an output buffer
                    202:  * @content:  An element table
                    203:  * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
                    204:  *
                    205:  * This will dump the content of the element content definition
                    206:  * Intended just for the debug routine
                    207:  */
                    208: void
                    209: xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
                    210:     if (content == NULL) return;
                    211:     if (glob) strcat(buf, "(");
                    212:     switch (content->type) {
                    213:         case XML_ELEMENT_CONTENT_PCDATA:
                    214:             strcat(buf, "#PCDATA");
                    215:            break;
                    216:        case XML_ELEMENT_CONTENT_ELEMENT:
1.23      daniel    217:            strcat(buf, (char *) content->name);
1.19      daniel    218:            break;
                    219:        case XML_ELEMENT_CONTENT_SEQ:
                    220:            if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
                    221:                (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
                    222:                xmlSprintfElementContent(buf, content->c1, 1);
                    223:            else
                    224:                xmlSprintfElementContent(buf, content->c1, 0);
                    225:             strcat(buf, " , ");
                    226:            if (content->c2->type == XML_ELEMENT_CONTENT_OR)
                    227:                xmlSprintfElementContent(buf, content->c2, 1);
                    228:            else
                    229:                xmlSprintfElementContent(buf, content->c2, 0);
                    230:            break;
                    231:        case XML_ELEMENT_CONTENT_OR:
                    232:            if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
                    233:                (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
                    234:                xmlSprintfElementContent(buf, content->c1, 1);
                    235:            else
                    236:                xmlSprintfElementContent(buf, content->c1, 0);
                    237:             strcat(buf, " | ");
                    238:            if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
                    239:                xmlSprintfElementContent(buf, content->c2, 1);
                    240:            else
                    241:                xmlSprintfElementContent(buf, content->c2, 0);
                    242:            break;
                    243:     }
                    244:     if (glob)
                    245:         strcat(buf, ")");
                    246:     switch (content->ocur) {
                    247:         case XML_ELEMENT_CONTENT_ONCE:
                    248:            break;
                    249:         case XML_ELEMENT_CONTENT_OPT:
                    250:            strcat(buf, "?");
                    251:            break;
                    252:         case XML_ELEMENT_CONTENT_MULT:
                    253:            strcat(buf, "*");
                    254:            break;
                    255:         case XML_ELEMENT_CONTENT_PLUS:
                    256:            strcat(buf, "+");
                    257:            break;
                    258:     }
                    259: }
                    260: 
1.1       daniel    261: /****************************************************************
                    262:  *                                                             *
                    263:  *     Registration of DTD declarations                        *
                    264:  *                                                             *
                    265:  ****************************************************************/
                    266: 
1.2       daniel    267: /**
                    268:  * xmlCreateElementTable:
                    269:  *
                    270:  * create and initialize an empty element hash table.
                    271:  *
1.6       daniel    272:  * Returns the xmlElementTablePtr just created or NULL in case of error.
1.2       daniel    273:  */
                    274: xmlElementTablePtr
                    275: xmlCreateElementTable(void) {
                    276:     xmlElementTablePtr ret;
                    277: 
                    278:     ret = (xmlElementTablePtr) 
1.26      daniel    279:          xmlMalloc(sizeof(xmlElementTable));
1.2       daniel    280:     if (ret == NULL) {
1.26      daniel    281:         fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
1.12      daniel    282:                (long)sizeof(xmlElementTable));
1.2       daniel    283:         return(NULL);
                    284:     }
1.4       daniel    285:     ret->max_elements = XML_MIN_ELEMENT_TABLE;
1.2       daniel    286:     ret->nb_elements = 0;
1.15      daniel    287:     ret->table = (xmlElementPtr *) 
1.26      daniel    288:          xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
1.2       daniel    289:     if (ret == NULL) {
1.26      daniel    290:         fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
1.12      daniel    291:                ret->max_elements * (long)sizeof(xmlElement));
1.26      daniel    292:        xmlFree(ret);
1.2       daniel    293:         return(NULL);
                    294:     }
                    295:     return(ret);
                    296: }
                    297: 
1.1       daniel    298: 
                    299: /**
                    300:  * xmlAddElementDecl:
1.32      daniel    301:  * @ctxt:  the validation context
1.6       daniel    302:  * @dtd:  pointer to the DTD
1.1       daniel    303:  * @name:  the entity name
1.6       daniel    304:  * @type:  the element type
                    305:  * @content:  the element content tree or NULL
1.1       daniel    306:  *
                    307:  * Register a new element declaration
                    308:  *
1.6       daniel    309:  * Returns NULL if not, othervise the entity
1.1       daniel    310:  */
                    311: xmlElementPtr
1.31      daniel    312: xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1.36      daniel    313:                   xmlElementTypeVal type, xmlElementContentPtr content) {
1.2       daniel    314:     xmlElementPtr ret, cur;
                    315:     xmlElementTablePtr table;
                    316:     int i;
1.1       daniel    317: 
                    318:     if (dtd == NULL) {
                    319:         fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
                    320:        return(NULL);
                    321:     }
                    322:     if (name == NULL) {
                    323:         fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
                    324:        return(NULL);
                    325:     }
                    326:     switch (type) {
                    327:         case XML_ELEMENT_TYPE_EMPTY:
                    328:            if (content != NULL) {
                    329:                fprintf(stderr,
                    330:                        "xmlAddElementDecl: content != NULL for EMPTY\n");
                    331:                return(NULL);
                    332:            }
                    333:            break;
                    334:        case XML_ELEMENT_TYPE_ANY:
                    335:            if (content != NULL) {
                    336:                fprintf(stderr,
                    337:                        "xmlAddElementDecl: content != NULL for ANY\n");
                    338:                return(NULL);
                    339:            }
                    340:            break;
                    341:        case XML_ELEMENT_TYPE_MIXED:
                    342:            if (content == NULL) {
                    343:                fprintf(stderr,
                    344:                        "xmlAddElementDecl: content == NULL for MIXED\n");
                    345:                return(NULL);
                    346:            }
                    347:            break;
                    348:        case XML_ELEMENT_TYPE_ELEMENT:
                    349:            if (content == NULL) {
                    350:                fprintf(stderr,
                    351:                        "xmlAddElementDecl: content == NULL for ELEMENT\n");
                    352:                return(NULL);
                    353:            }
                    354:            break;
                    355:        default:
                    356:            fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
                    357:            return(NULL);
                    358:     }
                    359: 
                    360:     /*
1.2       daniel    361:      * Create the Element table if needed.
                    362:      */
                    363:     table = dtd->elements;
                    364:     if (table == NULL) 
                    365:         table = dtd->elements = xmlCreateElementTable();
                    366:     if (table == NULL) {
                    367:        fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
                    368:         return(NULL);
                    369:     }
                    370: 
                    371:     /*
1.1       daniel    372:      * Validity Check:
                    373:      * Search the DTD for previous declarations of the ELEMENT
                    374:      */
1.2       daniel    375:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel    376:         cur = table->table[i];
1.2       daniel    377:        if (!xmlStrcmp(cur->name, name)) {
                    378:            /*
                    379:             * The element is already defined in this Dtd.
                    380:             */
1.16      daniel    381:            VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1.2       daniel    382:            return(NULL);
                    383:        }
                    384:     }
1.1       daniel    385: 
                    386:     /*
1.2       daniel    387:      * Grow the table, if needed.
1.1       daniel    388:      */
1.2       daniel    389:     if (table->nb_elements >= table->max_elements) {
                    390:         /*
                    391:         * need more elements.
                    392:         */
                    393:        table->max_elements *= 2;
1.15      daniel    394:        table->table = (xmlElementPtr *) 
1.26      daniel    395:            xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
1.13      daniel    396:        if (table->table == NULL) {
1.2       daniel    397:            fprintf(stderr, "xmlAddElementDecl: out of memory\n");
                    398:            return(NULL);
                    399:        }
1.1       daniel    400:     }
1.26      daniel    401:     ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1.15      daniel    402:     if (ret == NULL) {
                    403:        fprintf(stderr, "xmlAddElementDecl: out of memory\n");
                    404:        return(NULL);
                    405:     }
                    406:     table->table[table->nb_elements] = ret;
1.2       daniel    407: 
                    408:     /*
                    409:      * fill the structure.
                    410:      */
1.1       daniel    411:     ret->type = type;
                    412:     ret->name = xmlStrdup(name);
1.11      daniel    413:     ret->content = xmlCopyElementContent(content);
1.15      daniel    414:     ret->attributes = xmlScanAttributeDecl(dtd, name);
1.2       daniel    415:     table->nb_elements++;
                    416: 
                    417:     return(ret);
                    418: }
                    419: 
                    420: /**
                    421:  * xmlFreeElement:
                    422:  * @elem:  An element
                    423:  *
                    424:  * Deallocate the memory used by an element definition
                    425:  */
                    426: void
                    427: xmlFreeElement(xmlElementPtr elem) {
                    428:     if (elem == NULL) return;
                    429:     xmlFreeElementContent(elem->content);
                    430:     if (elem->name != NULL)
1.31      daniel    431:        xmlFree((xmlChar *) elem->name);
1.2       daniel    432:     memset(elem, -1, sizeof(xmlElement));
1.26      daniel    433:     xmlFree(elem);
1.2       daniel    434: }
1.1       daniel    435: 
1.2       daniel    436: /**
                    437:  * xmlFreeElementTable:
                    438:  * @table:  An element table
                    439:  *
1.4       daniel    440:  * Deallocate the memory used by an element hash table.
1.2       daniel    441:  */
                    442: void
                    443: xmlFreeElementTable(xmlElementTablePtr table) {
                    444:     int i;
                    445: 
                    446:     if (table == NULL) return;
                    447: 
                    448:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel    449:         xmlFreeElement(table->table[i]);
1.2       daniel    450:     }
1.26      daniel    451:     xmlFree(table->table);
                    452:     xmlFree(table);
1.2       daniel    453: }
                    454: 
                    455: /**
                    456:  * xmlCopyElementTable:
                    457:  * @table:  An element table
                    458:  *
                    459:  * Build a copy of an element table.
                    460:  * 
1.6       daniel    461:  * Returns the new xmlElementTablePtr or NULL in case of error.
1.2       daniel    462:  */
                    463: xmlElementTablePtr
                    464: xmlCopyElementTable(xmlElementTablePtr table) {
                    465:     xmlElementTablePtr ret;
                    466:     xmlElementPtr cur, ent;
                    467:     int i;
1.1       daniel    468: 
1.26      daniel    469:     ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
1.2       daniel    470:     if (ret == NULL) {
                    471:         fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
                    472:        return(NULL);
                    473:     }
1.26      daniel    474:     ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
1.15      daniel    475:                                          sizeof(xmlElementPtr));
1.2       daniel    476:     if (ret->table == NULL) {
                    477:         fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
1.26      daniel    478:        xmlFree(ret);
1.2       daniel    479:        return(NULL);
                    480:     }
                    481:     ret->max_elements = table->max_elements;
                    482:     ret->nb_elements = table->nb_elements;
                    483:     for (i = 0;i < ret->nb_elements;i++) {
1.26      daniel    484:        cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1.15      daniel    485:        if (cur == NULL) {
                    486:            fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
1.26      daniel    487:            xmlFree(ret);
                    488:            xmlFree(ret->table);
1.15      daniel    489:            return(NULL);
                    490:        }
                    491:        ret->table[i] = cur;
                    492:        ent = table->table[i];
1.2       daniel    493:        cur->type = ent->type;
                    494:        if (ent->name != NULL)
                    495:            cur->name = xmlStrdup(ent->name);
                    496:        else
                    497:            cur->name = NULL;
                    498:        cur->content = xmlCopyElementContent(ent->content);
1.42      daniel    499:        /* TODO : rebuild the attribute list on the copy */
1.15      daniel    500:        cur->attributes = NULL;
1.2       daniel    501:     }
1.1       daniel    502:     return(ret);
                    503: }
                    504: 
1.2       daniel    505: /**
                    506:  * xmlDumpElementTable:
1.9       daniel    507:  * @buf:  the XML buffer output
1.2       daniel    508:  * @table:  An element table
                    509:  *
                    510:  * This will dump the content of the element table as an XML DTD definition
                    511:  */
                    512: void
1.8       daniel    513: xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1.2       daniel    514:     int i;
                    515:     xmlElementPtr cur;
                    516: 
                    517:     if (table == NULL) return;
                    518: 
                    519:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel    520:         cur = table->table[i];
1.2       daniel    521:         switch (cur->type) {
                    522:            case XML_ELEMENT_TYPE_EMPTY:
1.8       daniel    523:                xmlBufferWriteChar(buf, "<!ELEMENT ");
                    524:                xmlBufferWriteCHAR(buf, cur->name);
                    525:                xmlBufferWriteChar(buf, " EMPTY>\n");
1.2       daniel    526:                break;
                    527:            case XML_ELEMENT_TYPE_ANY:
1.8       daniel    528:                xmlBufferWriteChar(buf, "<!ELEMENT ");
                    529:                xmlBufferWriteCHAR(buf, cur->name);
                    530:                xmlBufferWriteChar(buf, " ANY>\n");
1.2       daniel    531:                break;
                    532:            case XML_ELEMENT_TYPE_MIXED:
1.8       daniel    533:                xmlBufferWriteChar(buf, "<!ELEMENT ");
                    534:                xmlBufferWriteCHAR(buf, cur->name);
                    535:                xmlBufferWriteChar(buf, " ");
                    536:                xmlDumpElementContent(buf, cur->content, 1);
                    537:                xmlBufferWriteChar(buf, ">\n");
1.2       daniel    538:                break;
                    539:            case XML_ELEMENT_TYPE_ELEMENT:
1.8       daniel    540:                xmlBufferWriteChar(buf, "<!ELEMENT ");
                    541:                xmlBufferWriteCHAR(buf, cur->name);
                    542:                xmlBufferWriteChar(buf, " ");
                    543:                xmlDumpElementContent(buf, cur->content, 1);
                    544:                xmlBufferWriteChar(buf, ">\n");
1.2       daniel    545:                break;
                    546:            default:
                    547:                fprintf(stderr,
                    548:                    "xmlDumpElementTable: internal: unknown type %d\n",
                    549:                        cur->type);
                    550:        }
1.4       daniel    551:     }
                    552: }
                    553: 
                    554: /**
                    555:  * xmlCreateEnumeration:
                    556:  * @name:  the enumeration name or NULL
                    557:  *
                    558:  * create and initialize an enumeration attribute node.
                    559:  *
1.6       daniel    560:  * Returns the xmlEnumerationPtr just created or NULL in case
1.4       daniel    561:  *                of error.
                    562:  */
                    563: xmlEnumerationPtr
1.31      daniel    564: xmlCreateEnumeration(xmlChar *name) {
1.4       daniel    565:     xmlEnumerationPtr ret;
                    566: 
1.26      daniel    567:     ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1.4       daniel    568:     if (ret == NULL) {
1.26      daniel    569:         fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
1.12      daniel    570:                (long)sizeof(xmlEnumeration));
1.4       daniel    571:         return(NULL);
                    572:     }
                    573: 
                    574:     if (name != NULL)
                    575:         ret->name = xmlStrdup(name);
                    576:     else
                    577:         ret->name = NULL;
                    578:     ret->next = NULL;
                    579:     return(ret);
                    580: }
                    581: 
                    582: /**
                    583:  * xmlFreeEnumeration:
                    584:  * @cur:  the tree to free.
                    585:  *
                    586:  * free an enumeration attribute node (recursive).
                    587:  */
                    588: void
                    589: xmlFreeEnumeration(xmlEnumerationPtr cur) {
                    590:     if (cur == NULL) return;
                    591: 
                    592:     if (cur->next != NULL) xmlFreeEnumeration(cur->next);
                    593: 
1.31      daniel    594:     if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1.4       daniel    595:     memset(cur, -1, sizeof(xmlEnumeration));
1.26      daniel    596:     xmlFree(cur);
1.4       daniel    597: }
                    598: 
                    599: /**
                    600:  * xmlCopyEnumeration:
                    601:  * @cur:  the tree to copy.
                    602:  *
                    603:  * Copy an enumeration attribute node (recursive).
                    604:  *
1.6       daniel    605:  * Returns the xmlEnumerationPtr just created or NULL in case
1.4       daniel    606:  *                of error.
                    607:  */
                    608: xmlEnumerationPtr
                    609: xmlCopyEnumeration(xmlEnumerationPtr cur) {
                    610:     xmlEnumerationPtr ret;
                    611: 
                    612:     if (cur == NULL) return(NULL);
1.31      daniel    613:     ret = xmlCreateEnumeration((xmlChar *) cur->name);
1.4       daniel    614: 
                    615:     if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
                    616:     else ret->next = NULL;
                    617: 
                    618:     return(ret);
                    619: }
                    620: 
                    621: /**
1.18      daniel    622:  * xmlDumpEnumeration:
                    623:  * @buf:  the XML buffer output
                    624:  * @enum:  An enumeration
                    625:  *
                    626:  * This will dump the content of the enumeration
                    627:  */
                    628: void
                    629: xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
                    630:     if (cur == NULL)  return;
                    631:     
                    632:     xmlBufferWriteCHAR(buf, cur->name);
                    633:     if (cur->next == NULL)
                    634:        xmlBufferWriteChar(buf, ")");
                    635:     else {
                    636:        xmlBufferWriteChar(buf, " | ");
                    637:        xmlDumpEnumeration(buf, cur->next);
                    638:     }
                    639: }
                    640: 
                    641: /**
1.4       daniel    642:  * xmlCreateAttributeTable:
                    643:  *
                    644:  * create and initialize an empty attribute hash table.
                    645:  *
1.6       daniel    646:  * Returns the xmlAttributeTablePtr just created or NULL in case
1.4       daniel    647:  *                of error.
                    648:  */
                    649: xmlAttributeTablePtr
                    650: xmlCreateAttributeTable(void) {
                    651:     xmlAttributeTablePtr ret;
                    652: 
                    653:     ret = (xmlAttributeTablePtr) 
1.26      daniel    654:          xmlMalloc(sizeof(xmlAttributeTable));
1.4       daniel    655:     if (ret == NULL) {
1.26      daniel    656:         fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
1.12      daniel    657:                (long)sizeof(xmlAttributeTable));
1.4       daniel    658:         return(NULL);
                    659:     }
                    660:     ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
                    661:     ret->nb_attributes = 0;
1.15      daniel    662:     ret->table = (xmlAttributePtr *) 
1.26      daniel    663:          xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
1.4       daniel    664:     if (ret == NULL) {
1.26      daniel    665:         fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
1.15      daniel    666:                ret->max_attributes * (long)sizeof(xmlAttributePtr));
1.26      daniel    667:        xmlFree(ret);
1.4       daniel    668:         return(NULL);
                    669:     }
                    670:     return(ret);
                    671: }
                    672: 
1.15      daniel    673: /**
                    674:  * xmlScanAttributeDecl:
                    675:  * @dtd:  pointer to the DTD
                    676:  * @elem:  the element name
                    677:  *
                    678:  * When inserting a new element scan the DtD for existing attributes
                    679:  * for taht element and initialize the Attribute chain
                    680:  *
                    681:  * Returns the pointer to the first attribute decl in the chain,
                    682:  *         possibly NULL.
                    683:  */
                    684: xmlAttributePtr
1.31      daniel    685: xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1.16      daniel    686:     xmlAttributePtr ret = NULL;
1.15      daniel    687:     xmlAttributeTablePtr table;
                    688:     int i;
                    689: 
                    690:     if (dtd == NULL) {
                    691:         fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
                    692:        return(NULL);
                    693:     }
                    694:     if (elem == NULL) {
                    695:         fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
                    696:        return(NULL);
                    697:     }
                    698:     table = dtd->attributes;
                    699:     if (table == NULL) 
                    700:         return(NULL);
                    701: 
                    702:     for (i = 0;i < table->nb_attributes;i++) {
                    703:         if (!xmlStrcmp(table->table[i]->elem, elem)) {
1.16      daniel    704:            table->table[i]->next = ret;
                    705:            ret = table->table[i];
                    706:        }
                    707:     }
                    708:     return(ret);
                    709: }
                    710: 
                    711: /**
                    712:  * xmlScanIDAttributeDecl:
                    713:  * @ctxt:  the validation context
                    714:  * @elem:  the element name
                    715:  *
1.43      daniel    716:  * Verify that the element don't have too many ID attributes
1.16      daniel    717:  * declared.
                    718:  *
                    719:  * Returns the number of ID attributes found.
                    720:  */
                    721: int
                    722: xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
                    723:     xmlAttributePtr cur;
                    724:     int ret = 0;
                    725: 
                    726:     if (elem == NULL) return(0);
                    727:     cur = elem->attributes;
                    728:     while (cur != NULL) {
                    729:         if (cur->type == XML_ATTRIBUTE_ID) {
                    730:            ret ++;
                    731:            if (ret > 1)
                    732:                VERROR(ctxt->userData, 
                    733:               "Element %s has too may ID attributes defined : %s\n",
                    734:                       elem->name, cur->name);
1.15      daniel    735:        }
1.16      daniel    736:        cur = cur->next;
1.15      daniel    737:     }
                    738:     return(ret);
                    739: }
                    740: 
1.4       daniel    741: 
                    742: /**
                    743:  * xmlAddAttributeDecl:
1.16      daniel    744:  * @ctxt:  the validation context
1.6       daniel    745:  * @dtd:  pointer to the DTD
                    746:  * @elem:  the element name
                    747:  * @name:  the attribute name
                    748:  * @type:  the attribute type
                    749:  * @def:  the attribute default type
                    750:  * @defaultValue:  the attribute default value
                    751:  * @tree:  if it's an enumeration, the associated list
1.4       daniel    752:  *
                    753:  * Register a new attribute declaration
                    754:  *
1.6       daniel    755:  * Returns NULL if not, othervise the entity
1.4       daniel    756:  */
                    757: xmlAttributePtr
1.31      daniel    758: xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
                    759:                     const xmlChar *name, xmlAttributeType type, 
                    760:                     xmlAttributeDefault def, const xmlChar *defaultValue,
1.25      daniel    761:                     xmlEnumerationPtr tree) {
1.4       daniel    762:     xmlAttributePtr ret, cur;
                    763:     xmlAttributeTablePtr table;
1.15      daniel    764:     xmlElementPtr elemDef;
1.38      daniel    765:     xmlChar *rname;
                    766:     xmlChar *ns;
1.4       daniel    767:     int i;
                    768: 
                    769:     if (dtd == NULL) {
                    770:         fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
                    771:        return(NULL);
                    772:     }
                    773:     if (name == NULL) {
                    774:         fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
                    775:        return(NULL);
                    776:     }
                    777:     if (elem == NULL) {
                    778:         fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
                    779:        return(NULL);
                    780:     }
1.23      daniel    781:     /*
                    782:      * Check the type and possibly the default value.
                    783:      */
1.4       daniel    784:     switch (type) {
                    785:         case XML_ATTRIBUTE_CDATA:
                    786:            break;
                    787:         case XML_ATTRIBUTE_ID:
                    788:            break;
                    789:         case XML_ATTRIBUTE_IDREF:
                    790:            break;
                    791:         case XML_ATTRIBUTE_IDREFS:
                    792:            break;
                    793:         case XML_ATTRIBUTE_ENTITY:
                    794:            break;
                    795:         case XML_ATTRIBUTE_ENTITIES:
                    796:            break;
                    797:         case XML_ATTRIBUTE_NMTOKEN:
                    798:            break;
                    799:         case XML_ATTRIBUTE_NMTOKENS:
                    800:            break;
                    801:         case XML_ATTRIBUTE_ENUMERATION:
                    802:            break;
                    803:         case XML_ATTRIBUTE_NOTATION:
                    804:            break;
                    805:        default:
                    806:            fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
                    807:            return(NULL);
                    808:     }
1.23      daniel    809:     if ((defaultValue != NULL) && 
                    810:         (!xmlValidateAttributeValue(type, defaultValue))) {
                    811:        VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
                    812:               elem, name, defaultValue);
                    813:        defaultValue = NULL;
                    814:     }
1.4       daniel    815: 
                    816:     /*
                    817:      * Create the Attribute table if needed.
                    818:      */
                    819:     table = dtd->attributes;
                    820:     if (table == NULL) 
                    821:         table = dtd->attributes = xmlCreateAttributeTable();
                    822:     if (table == NULL) {
                    823:        fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
                    824:         return(NULL);
                    825:     }
                    826: 
                    827:     /*
1.38      daniel    828:      * Split the full name into a namespace prefix and the tag name
                    829:      */
                    830:     rname = xmlSplitQName(name, &ns);
                    831: 
                    832:     /*
1.4       daniel    833:      * Validity Check:
                    834:      * Search the DTD for previous declarations of the ATTLIST
                    835:      */
                    836:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel    837:         cur = table->table[i];
1.38      daniel    838:        if ((ns != NULL) && (cur->prefix == NULL)) continue;
                    839:        if ((ns == NULL) && (cur->prefix != NULL)) continue;
                    840:        if ((!xmlStrcmp(cur->name, rname)) && (!xmlStrcmp(cur->elem, elem)) &&
                    841:            ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
1.4       daniel    842:            /*
                    843:             * The attribute is already defined in this Dtd.
                    844:             */
1.23      daniel    845:            VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
                    846:                   elem, name);
1.4       daniel    847:        }
                    848:     }
                    849: 
                    850:     /*
                    851:      * Grow the table, if needed.
                    852:      */
                    853:     if (table->nb_attributes >= table->max_attributes) {
                    854:         /*
                    855:         * need more attributes.
                    856:         */
                    857:        table->max_attributes *= 2;
1.15      daniel    858:        table->table = (xmlAttributePtr *) 
1.26      daniel    859:            xmlRealloc(table->table, table->max_attributes * 
1.15      daniel    860:                    sizeof(xmlAttributePtr));
1.13      daniel    861:        if (table->table == NULL) {
1.4       daniel    862:            fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
                    863:            return(NULL);
                    864:        }
                    865:     }
1.26      daniel    866:     ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15      daniel    867:     if (ret == NULL) {
                    868:        fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
                    869:        return(NULL);
                    870:     }
                    871:     table->table[table->nb_attributes] = ret;
1.4       daniel    872: 
                    873:     /*
                    874:      * fill the structure.
                    875:      */
                    876:     ret->type = type;
1.38      daniel    877:     ret->name = rname;
                    878:     ret->prefix = ns;
1.4       daniel    879:     ret->elem = xmlStrdup(elem);
                    880:     ret->def = def;
                    881:     ret->tree = tree;
                    882:     if (defaultValue != NULL)
                    883:        ret->defaultValue = xmlStrdup(defaultValue);
                    884:     else
                    885:         ret->defaultValue = NULL;
1.15      daniel    886:     elemDef = xmlGetDtdElementDesc(dtd, elem);
                    887:     if (elemDef != NULL) {
1.16      daniel    888:         if ((type == XML_ATTRIBUTE_ID) &&
                    889:            (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
                    890:            VERROR(ctxt->userData, 
                    891:           "Element %s has too may ID attributes defined : %s\n",
                    892:                   elem, name);
1.15      daniel    893:         ret->next = elemDef->attributes;
                    894:         elemDef->attributes = ret;
                    895:     }
1.4       daniel    896:     table->nb_attributes++;
                    897: 
                    898:     return(ret);
                    899: }
                    900: 
                    901: /**
                    902:  * xmlFreeAttribute:
                    903:  * @elem:  An attribute
                    904:  *
                    905:  * Deallocate the memory used by an attribute definition
                    906:  */
                    907: void
                    908: xmlFreeAttribute(xmlAttributePtr attr) {
                    909:     if (attr == NULL) return;
                    910:     if (attr->tree != NULL)
                    911:         xmlFreeEnumeration(attr->tree);
                    912:     if (attr->elem != NULL)
1.31      daniel    913:        xmlFree((xmlChar *) attr->elem);
1.4       daniel    914:     if (attr->name != NULL)
1.31      daniel    915:        xmlFree((xmlChar *) attr->name);
1.4       daniel    916:     if (attr->defaultValue != NULL)
1.31      daniel    917:        xmlFree((xmlChar *) attr->defaultValue);
1.38      daniel    918:     if (attr->prefix != NULL)
                    919:        xmlFree((xmlChar *) attr->prefix);
1.4       daniel    920:     memset(attr, -1, sizeof(xmlAttribute));
1.26      daniel    921:     xmlFree(attr);
1.4       daniel    922: }
                    923: 
                    924: /**
                    925:  * xmlFreeAttributeTable:
                    926:  * @table:  An attribute table
                    927:  *
                    928:  * Deallocate the memory used by an entities hash table.
                    929:  */
                    930: void
                    931: xmlFreeAttributeTable(xmlAttributeTablePtr table) {
                    932:     int i;
                    933: 
                    934:     if (table == NULL) return;
                    935: 
                    936:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel    937:         xmlFreeAttribute(table->table[i]);
1.4       daniel    938:     }
1.26      daniel    939:     xmlFree(table->table);
                    940:     xmlFree(table);
1.4       daniel    941: }
                    942: 
                    943: /**
                    944:  * xmlCopyAttributeTable:
                    945:  * @table:  An attribute table
                    946:  *
                    947:  * Build a copy of an attribute table.
                    948:  * 
1.6       daniel    949:  * Returns the new xmlAttributeTablePtr or NULL in case of error.
1.4       daniel    950:  */
                    951: xmlAttributeTablePtr
                    952: xmlCopyAttributeTable(xmlAttributeTablePtr table) {
                    953:     xmlAttributeTablePtr ret;
                    954:     xmlAttributePtr cur, attr;
                    955:     int i;
                    956: 
1.26      daniel    957:     ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
1.4       daniel    958:     if (ret == NULL) {
                    959:         fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
                    960:        return(NULL);
                    961:     }
1.26      daniel    962:     ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
1.15      daniel    963:                                           sizeof(xmlAttributePtr));
1.4       daniel    964:     if (ret->table == NULL) {
                    965:         fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26      daniel    966:        xmlFree(ret);
1.4       daniel    967:        return(NULL);
                    968:     }
                    969:     ret->max_attributes = table->max_attributes;
                    970:     ret->nb_attributes = table->nb_attributes;
                    971:     for (i = 0;i < ret->nb_attributes;i++) {
1.15      daniel    972:        attr = table->table[i];
1.26      daniel    973:        cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15      daniel    974:        if (cur == NULL) {
                    975:            fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26      daniel    976:            xmlFree(ret);
                    977:            xmlFree(ret->table);
1.15      daniel    978:            return(NULL);
                    979:        }
                    980:        ret->table[i] = cur;
1.4       daniel    981:        cur->type = attr->type;
                    982:        cur->def = attr->def;
                    983:        cur->tree = xmlCopyEnumeration(attr->tree);
                    984:        if (attr->elem != NULL)
                    985:            cur->elem = xmlStrdup(attr->elem);
                    986:        else
                    987:            cur->elem = NULL;
                    988:        if (attr->name != NULL)
                    989:            cur->name = xmlStrdup(attr->name);
                    990:        else
                    991:            cur->name = NULL;
                    992:        if (attr->defaultValue != NULL)
                    993:            cur->defaultValue = xmlStrdup(attr->defaultValue);
                    994:        else
                    995:            cur->defaultValue = NULL;
1.15      daniel    996:        /* NEED to rebuild the next chain !!!!!! */
1.4       daniel    997:     }
                    998:     return(ret);
                    999: }
                   1000: 
                   1001: /**
                   1002:  * xmlDumpAttributeTable:
1.9       daniel   1003:  * @buf:  the XML buffer output
1.4       daniel   1004:  * @table:  An attribute table
                   1005:  *
                   1006:  * This will dump the content of the attribute table as an XML DTD definition
                   1007:  */
                   1008: void
1.8       daniel   1009: xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1.4       daniel   1010:     int i;
                   1011:     xmlAttributePtr cur;
                   1012: 
                   1013:     if (table == NULL) return;
                   1014: 
                   1015:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel   1016:         cur = table->table[i];
1.8       daniel   1017:        xmlBufferWriteChar(buf, "<!ATTLIST ");
                   1018:        xmlBufferWriteCHAR(buf, cur->elem);
                   1019:        xmlBufferWriteChar(buf, " ");
                   1020:        xmlBufferWriteCHAR(buf, cur->name);
1.4       daniel   1021:         switch (cur->type) {
                   1022:             case XML_ATTRIBUTE_CDATA:
1.8       daniel   1023:                xmlBufferWriteChar(buf, " CDATA");
1.4       daniel   1024:                 break;
                   1025:             case XML_ATTRIBUTE_ID:
1.8       daniel   1026:                xmlBufferWriteChar(buf, " ID");
1.4       daniel   1027:                 break;
                   1028:             case XML_ATTRIBUTE_IDREF:
1.8       daniel   1029:                xmlBufferWriteChar(buf, " IDREF");
1.4       daniel   1030:                 break;
                   1031:             case XML_ATTRIBUTE_IDREFS:
1.8       daniel   1032:                xmlBufferWriteChar(buf, " IDREFS");
1.4       daniel   1033:                 break;
                   1034:             case XML_ATTRIBUTE_ENTITY:
1.8       daniel   1035:                xmlBufferWriteChar(buf, " ENTITY");
1.4       daniel   1036:                 break;
                   1037:             case XML_ATTRIBUTE_ENTITIES:
1.8       daniel   1038:                xmlBufferWriteChar(buf, " ENTITIES");
1.4       daniel   1039:                 break;
                   1040:             case XML_ATTRIBUTE_NMTOKEN:
1.8       daniel   1041:                xmlBufferWriteChar(buf, " NMTOKEN");
1.4       daniel   1042:                 break;
                   1043:             case XML_ATTRIBUTE_NMTOKENS:
1.8       daniel   1044:                xmlBufferWriteChar(buf, " NMTOKENS");
1.4       daniel   1045:                 break;
                   1046:             case XML_ATTRIBUTE_ENUMERATION:
1.18      daniel   1047:                 xmlBufferWriteChar(buf, " (");
                   1048:                xmlDumpEnumeration(buf, cur->tree);
1.4       daniel   1049:                 break;
                   1050:             case XML_ATTRIBUTE_NOTATION:
1.18      daniel   1051:                 xmlBufferWriteChar(buf, " NOTATION (");
                   1052:                xmlDumpEnumeration(buf, cur->tree);
1.4       daniel   1053:                 break;
                   1054:            default:
                   1055:                fprintf(stderr,
                   1056:                    "xmlDumpAttributeTable: internal: unknown type %d\n",
                   1057:                        cur->type);
                   1058:        }
                   1059:         switch (cur->def) {
                   1060:             case XML_ATTRIBUTE_NONE:
                   1061:                 break;
                   1062:             case XML_ATTRIBUTE_REQUIRED:
1.8       daniel   1063:                xmlBufferWriteChar(buf, " #REQUIRED");
1.4       daniel   1064:                 break;
                   1065:             case XML_ATTRIBUTE_IMPLIED:
1.8       daniel   1066:                xmlBufferWriteChar(buf, " #IMPLIED");
1.4       daniel   1067:                 break;
                   1068:             case XML_ATTRIBUTE_FIXED:
1.17      daniel   1069:                xmlBufferWriteChar(buf, " #FIXED");
1.4       daniel   1070:                 break;
                   1071:            default:
                   1072:                fprintf(stderr,
                   1073:                    "xmlDumpAttributeTable: internal: unknown default %d\n",
                   1074:                        cur->def);
                   1075:         }
1.17      daniel   1076:        if (cur->defaultValue != NULL) {
                   1077:            xmlBufferWriteChar(buf, " ");
                   1078:            xmlBufferWriteQuotedString(buf, cur->defaultValue);
                   1079:        }
1.8       daniel   1080:         xmlBufferWriteChar(buf, ">\n");
1.5       daniel   1081:     }
                   1082: }
                   1083: 
                   1084: /************************************************************************
                   1085:  *                                                                     *
                   1086:  *                             NOTATIONs                               *
                   1087:  *                                                                     *
                   1088:  ************************************************************************/
                   1089: /**
                   1090:  * xmlCreateNotationTable:
                   1091:  *
                   1092:  * create and initialize an empty notation hash table.
                   1093:  *
1.6       daniel   1094:  * Returns the xmlNotationTablePtr just created or NULL in case
1.5       daniel   1095:  *                of error.
                   1096:  */
                   1097: xmlNotationTablePtr
                   1098: xmlCreateNotationTable(void) {
                   1099:     xmlNotationTablePtr ret;
                   1100: 
                   1101:     ret = (xmlNotationTablePtr) 
1.26      daniel   1102:          xmlMalloc(sizeof(xmlNotationTable));
1.5       daniel   1103:     if (ret == NULL) {
1.26      daniel   1104:         fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12      daniel   1105:                (long)sizeof(xmlNotationTable));
1.5       daniel   1106:         return(NULL);
                   1107:     }
                   1108:     ret->max_notations = XML_MIN_NOTATION_TABLE;
                   1109:     ret->nb_notations = 0;
1.15      daniel   1110:     ret->table = (xmlNotationPtr *) 
1.26      daniel   1111:          xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
1.5       daniel   1112:     if (ret == NULL) {
1.26      daniel   1113:         fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12      daniel   1114:                ret->max_notations * (long)sizeof(xmlNotation));
1.26      daniel   1115:        xmlFree(ret);
1.5       daniel   1116:         return(NULL);
                   1117:     }
                   1118:     return(ret);
                   1119: }
                   1120: 
                   1121: 
                   1122: /**
                   1123:  * xmlAddNotationDecl:
1.6       daniel   1124:  * @dtd:  pointer to the DTD
1.16      daniel   1125:  * @ctxt:  the validation context
1.5       daniel   1126:  * @name:  the entity name
1.6       daniel   1127:  * @PublicID:  the public identifier or NULL
                   1128:  * @SystemID:  the system identifier or NULL
1.5       daniel   1129:  *
                   1130:  * Register a new notation declaration
                   1131:  *
1.6       daniel   1132:  * Returns NULL if not, othervise the entity
1.5       daniel   1133:  */
                   1134: xmlNotationPtr
1.31      daniel   1135: xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
                   1136:                    const xmlChar *PublicID, const xmlChar *SystemID) {
1.5       daniel   1137:     xmlNotationPtr ret, cur;
                   1138:     xmlNotationTablePtr table;
                   1139:     int i;
                   1140: 
                   1141:     if (dtd == NULL) {
                   1142:         fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
                   1143:        return(NULL);
                   1144:     }
                   1145:     if (name == NULL) {
                   1146:         fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
                   1147:        return(NULL);
                   1148:     }
                   1149:     if ((PublicID == NULL) && (SystemID == NULL)) {
                   1150:         fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
                   1151:     }
                   1152: 
                   1153:     /*
                   1154:      * Create the Notation table if needed.
                   1155:      */
                   1156:     table = dtd->notations;
                   1157:     if (table == NULL) 
                   1158:         table = dtd->notations = xmlCreateNotationTable();
                   1159:     if (table == NULL) {
                   1160:        fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
                   1161:         return(NULL);
                   1162:     }
                   1163: 
                   1164:     /*
                   1165:      * Validity Check:
                   1166:      * Search the DTD for previous declarations of the ATTLIST
                   1167:      */
                   1168:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1169:         cur = table->table[i];
1.5       daniel   1170:        if (!xmlStrcmp(cur->name, name)) {
                   1171:            /*
                   1172:             * The notation is already defined in this Dtd.
                   1173:             */
                   1174:            fprintf(stderr,
                   1175:                    "xmlAddNotationDecl: %s already defined\n", name);
                   1176:        }
                   1177:     }
                   1178: 
                   1179:     /*
                   1180:      * Grow the table, if needed.
                   1181:      */
                   1182:     if (table->nb_notations >= table->max_notations) {
                   1183:         /*
                   1184:         * need more notations.
                   1185:         */
                   1186:        table->max_notations *= 2;
1.15      daniel   1187:        table->table = (xmlNotationPtr *) 
1.26      daniel   1188:            xmlRealloc(table->table, table->max_notations *
1.15      daniel   1189:                    sizeof(xmlNotationPtr));
1.13      daniel   1190:        if (table->table == NULL) {
1.5       daniel   1191:            fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
                   1192:            return(NULL);
                   1193:        }
                   1194:     }
1.26      daniel   1195:     ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15      daniel   1196:     if (ret == NULL) {
                   1197:        fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
                   1198:        return(NULL);
                   1199:     }
                   1200:     table->table[table->nb_notations] = ret;
1.5       daniel   1201: 
                   1202:     /*
                   1203:      * fill the structure.
                   1204:      */
                   1205:     ret->name = xmlStrdup(name);
                   1206:     if (SystemID != NULL)
                   1207:         ret->SystemID = xmlStrdup(SystemID);
                   1208:     else
                   1209:         ret->SystemID = NULL;
                   1210:     if (PublicID != NULL)
                   1211:         ret->PublicID = xmlStrdup(PublicID);
                   1212:     else
                   1213:         ret->PublicID = NULL;
                   1214:     table->nb_notations++;
                   1215: 
                   1216:     return(ret);
                   1217: }
                   1218: 
                   1219: /**
                   1220:  * xmlFreeNotation:
                   1221:  * @not:  A notation
                   1222:  *
                   1223:  * Deallocate the memory used by an notation definition
                   1224:  */
                   1225: void
                   1226: xmlFreeNotation(xmlNotationPtr nota) {
                   1227:     if (nota == NULL) return;
                   1228:     if (nota->name != NULL)
1.31      daniel   1229:        xmlFree((xmlChar *) nota->name);
1.5       daniel   1230:     if (nota->PublicID != NULL)
1.31      daniel   1231:        xmlFree((xmlChar *) nota->PublicID);
1.5       daniel   1232:     if (nota->SystemID != NULL)
1.31      daniel   1233:        xmlFree((xmlChar *) nota->SystemID);
1.5       daniel   1234:     memset(nota, -1, sizeof(xmlNotation));
1.26      daniel   1235:     xmlFree(nota);
1.5       daniel   1236: }
                   1237: 
                   1238: /**
                   1239:  * xmlFreeNotationTable:
                   1240:  * @table:  An notation table
                   1241:  *
                   1242:  * Deallocate the memory used by an entities hash table.
                   1243:  */
                   1244: void
                   1245: xmlFreeNotationTable(xmlNotationTablePtr table) {
                   1246:     int i;
                   1247: 
                   1248:     if (table == NULL) return;
                   1249: 
                   1250:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1251:         xmlFreeNotation(table->table[i]);
1.5       daniel   1252:     }
1.26      daniel   1253:     xmlFree(table->table);
                   1254:     xmlFree(table);
1.5       daniel   1255: }
                   1256: 
                   1257: /**
                   1258:  * xmlCopyNotationTable:
                   1259:  * @table:  A notation table
                   1260:  *
                   1261:  * Build a copy of a notation table.
                   1262:  * 
1.6       daniel   1263:  * Returns the new xmlNotationTablePtr or NULL in case of error.
1.5       daniel   1264:  */
                   1265: xmlNotationTablePtr
                   1266: xmlCopyNotationTable(xmlNotationTablePtr table) {
                   1267:     xmlNotationTablePtr ret;
                   1268:     xmlNotationPtr cur, nota;
                   1269:     int i;
                   1270: 
1.26      daniel   1271:     ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
1.5       daniel   1272:     if (ret == NULL) {
                   1273:         fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
                   1274:        return(NULL);
                   1275:     }
1.26      daniel   1276:     ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
1.15      daniel   1277:                                          sizeof(xmlNotationPtr));
1.5       daniel   1278:     if (ret->table == NULL) {
                   1279:         fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26      daniel   1280:        xmlFree(ret);
1.5       daniel   1281:        return(NULL);
                   1282:     }
                   1283:     ret->max_notations = table->max_notations;
                   1284:     ret->nb_notations = table->nb_notations;
                   1285:     for (i = 0;i < ret->nb_notations;i++) {
1.26      daniel   1286:        cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15      daniel   1287:        if (cur == NULL) {
                   1288:            fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26      daniel   1289:            xmlFree(ret);
                   1290:            xmlFree(ret->table);
1.15      daniel   1291:            return(NULL);
                   1292:        }
                   1293:        ret->table[i] = cur;
                   1294:        nota = table->table[i];
1.5       daniel   1295:        if (nota->name != NULL)
                   1296:            cur->name = xmlStrdup(nota->name);
                   1297:        else
                   1298:            cur->name = NULL;
                   1299:        if (nota->PublicID != NULL)
                   1300:            cur->PublicID = xmlStrdup(nota->PublicID);
                   1301:        else
                   1302:            cur->PublicID = NULL;
                   1303:        if (nota->SystemID != NULL)
                   1304:            cur->SystemID = xmlStrdup(nota->SystemID);
                   1305:        else
                   1306:            cur->SystemID = NULL;
                   1307:     }
                   1308:     return(ret);
                   1309: }
                   1310: 
                   1311: /**
                   1312:  * xmlDumpNotationTable:
1.9       daniel   1313:  * @buf:  the XML buffer output
1.5       daniel   1314:  * @table:  A notation table
                   1315:  *
                   1316:  * This will dump the content of the notation table as an XML DTD definition
                   1317:  */
                   1318: void
1.8       daniel   1319: xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
1.5       daniel   1320:     int i;
                   1321:     xmlNotationPtr cur;
                   1322: 
                   1323:     if (table == NULL) return;
                   1324: 
                   1325:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1326:         cur = table->table[i];
1.8       daniel   1327:        xmlBufferWriteChar(buf, "<!NOTATION ");
                   1328:        xmlBufferWriteCHAR(buf, cur->name);
1.5       daniel   1329:        if (cur->PublicID != NULL) {
1.10      daniel   1330:            xmlBufferWriteChar(buf, " PUBLIC ");
                   1331:            xmlBufferWriteQuotedString(buf, cur->PublicID);
1.5       daniel   1332:            if (cur->SystemID != NULL) {
1.8       daniel   1333:                xmlBufferWriteChar(buf, " ");
                   1334:                xmlBufferWriteCHAR(buf, cur->SystemID);
1.5       daniel   1335:            }
                   1336:        } else {
1.8       daniel   1337:            xmlBufferWriteChar(buf, " SYSTEM ");
                   1338:            xmlBufferWriteCHAR(buf, cur->SystemID);
1.5       daniel   1339:        }
1.8       daniel   1340:         xmlBufferWriteChar(buf, " >\n");
1.2       daniel   1341:     }
                   1342: }
1.14      daniel   1343: 
                   1344: /************************************************************************
                   1345:  *                                                                     *
1.27      daniel   1346:  *                             IDs                                     *
1.21      daniel   1347:  *                                                                     *
                   1348:  ************************************************************************/
                   1349: /**
                   1350:  * xmlCreateIDTable:
                   1351:  *
                   1352:  * create and initialize an empty id hash table.
                   1353:  *
                   1354:  * Returns the xmlIDTablePtr just created or NULL in case
                   1355:  *                of error.
                   1356:  */
                   1357: xmlIDTablePtr
                   1358: xmlCreateIDTable(void) {
                   1359:     xmlIDTablePtr ret;
                   1360: 
                   1361:     ret = (xmlIDTablePtr) 
1.26      daniel   1362:          xmlMalloc(sizeof(xmlIDTable));
1.21      daniel   1363:     if (ret == NULL) {
1.26      daniel   1364:         fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21      daniel   1365:                (long)sizeof(xmlIDTable));
                   1366:         return(NULL);
                   1367:     }
                   1368:     ret->max_ids = XML_MIN_NOTATION_TABLE;
                   1369:     ret->nb_ids = 0;
                   1370:     ret->table = (xmlIDPtr *) 
1.26      daniel   1371:          xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
1.21      daniel   1372:     if (ret == NULL) {
1.26      daniel   1373:         fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21      daniel   1374:                ret->max_ids * (long)sizeof(xmlID));
1.26      daniel   1375:        xmlFree(ret);
1.21      daniel   1376:         return(NULL);
                   1377:     }
                   1378:     return(ret);
                   1379: }
                   1380: 
                   1381: 
                   1382: /**
                   1383:  * xmlAddID:
                   1384:  * @ctxt:  the validation context
                   1385:  * @doc:  pointer to the document
                   1386:  * @value:  the value name
                   1387:  * @attr:  the attribute holding the ID
                   1388:  *
                   1389:  * Register a new id declaration
                   1390:  *
                   1391:  * Returns NULL if not, othervise the new xmlIDPtr
                   1392:  */
                   1393: xmlIDPtr 
1.31      daniel   1394: xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
1.21      daniel   1395:          xmlAttrPtr attr) {
                   1396:     xmlIDPtr ret, cur;
                   1397:     xmlIDTablePtr table;
                   1398:     int i;
                   1399: 
                   1400:     if (doc == NULL) {
                   1401:         fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
                   1402:        return(NULL);
                   1403:     }
                   1404:     if (value == NULL) {
                   1405:         fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
                   1406:        return(NULL);
                   1407:     }
                   1408:     if (attr == NULL) {
                   1409:         fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
                   1410:        return(NULL);
                   1411:     }
                   1412: 
                   1413:     /*
                   1414:      * Create the ID table if needed.
                   1415:      */
                   1416:     table = doc->ids;
                   1417:     if (table == NULL) 
                   1418:         table = doc->ids = xmlCreateIDTable();
                   1419:     if (table == NULL) {
                   1420:        fprintf(stderr, "xmlAddID: Table creation failed!\n");
                   1421:         return(NULL);
                   1422:     }
                   1423: 
                   1424:     /*
                   1425:      * Validity Check:
                   1426:      * Search the DTD for previous declarations of the ATTLIST
                   1427:      */
                   1428:     for (i = 0;i < table->nb_ids;i++) {
                   1429:         cur = table->table[i];
                   1430:        if (!xmlStrcmp(cur->value, value)) {
                   1431:            /*
                   1432:             * The id is already defined in this Dtd.
                   1433:             */
                   1434:            VERROR(ctxt->userData, "ID %s already defined\n", value);
                   1435:            return(NULL);
                   1436:        }
                   1437:     }
                   1438: 
                   1439:     /*
                   1440:      * Grow the table, if needed.
                   1441:      */
                   1442:     if (table->nb_ids >= table->max_ids) {
                   1443:         /*
                   1444:         * need more ids.
                   1445:         */
                   1446:        table->max_ids *= 2;
                   1447:        table->table = (xmlIDPtr *) 
1.26      daniel   1448:            xmlRealloc(table->table, table->max_ids *
1.21      daniel   1449:                    sizeof(xmlIDPtr));
                   1450:        if (table->table == NULL) {
                   1451:            fprintf(stderr, "xmlAddID: out of memory\n");
                   1452:            return(NULL);
                   1453:        }
                   1454:     }
1.26      daniel   1455:     ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
1.21      daniel   1456:     if (ret == NULL) {
                   1457:        fprintf(stderr, "xmlAddID: out of memory\n");
                   1458:        return(NULL);
                   1459:     }
                   1460:     table->table[table->nb_ids] = ret;
                   1461: 
                   1462:     /*
                   1463:      * fill the structure.
                   1464:      */
                   1465:     ret->value = xmlStrdup(value);
                   1466:     ret->attr = attr;
                   1467:     table->nb_ids++;
                   1468: 
                   1469:     return(ret);
                   1470: }
                   1471: 
                   1472: /**
                   1473:  * xmlFreeID:
                   1474:  * @not:  A id
                   1475:  *
                   1476:  * Deallocate the memory used by an id definition
                   1477:  */
                   1478: void
                   1479: xmlFreeID(xmlIDPtr id) {
                   1480:     if (id == NULL) return;
                   1481:     if (id->value != NULL)
1.31      daniel   1482:        xmlFree((xmlChar *) id->value);
1.21      daniel   1483:     memset(id, -1, sizeof(xmlID));
1.26      daniel   1484:     xmlFree(id);
1.21      daniel   1485: }
                   1486: 
                   1487: /**
                   1488:  * xmlFreeIDTable:
                   1489:  * @table:  An id table
                   1490:  *
                   1491:  * Deallocate the memory used by an ID hash table.
                   1492:  */
                   1493: void
                   1494: xmlFreeIDTable(xmlIDTablePtr table) {
                   1495:     int i;
                   1496: 
                   1497:     if (table == NULL) return;
                   1498: 
                   1499:     for (i = 0;i < table->nb_ids;i++) {
                   1500:         xmlFreeID(table->table[i]);
                   1501:     }
1.26      daniel   1502:     xmlFree(table->table);
                   1503:     xmlFree(table);
1.21      daniel   1504: }
                   1505: 
                   1506: /**
1.43      daniel   1507:  * xmlIsID:
1.21      daniel   1508:  * @doc:  the document
                   1509:  * @elem:  the element carrying the attribute
                   1510:  * @attr:  the attribute
                   1511:  *
                   1512:  * Determine whether an attribute is of type ID. In case we have Dtd(s)
                   1513:  * then this is simple, otherwise we use an heuristic: name ID (upper
                   1514:  * or lowercase).
                   1515:  *
                   1516:  * Returns 0 or 1 depending on the lookup result
                   1517:  */
                   1518: int
                   1519: xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1.43      daniel   1520:     if (doc == NULL) return(0);
                   1521:     if (attr == NULL) return(0);
1.21      daniel   1522:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
                   1523:         if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
                   1524:             ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
                   1525:            (attr->name[2] == 0)) return(1);
1.43      daniel   1526:     } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
                   1527:         if ((!xmlStrcmp(BAD_CAST "id", attr->name)) ||
                   1528:            (!xmlStrcmp(BAD_CAST "name", attr->name)))
                   1529:            return(1);
                   1530:        return(0);    
1.21      daniel   1531:     } else {
                   1532:        xmlAttributePtr attrDecl;
                   1533: 
1.43      daniel   1534:        if (elem == NULL) return(0);
1.21      daniel   1535:        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   1536:        if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   1537:            attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
                   1538:                                         attr->name);
                   1539: 
1.22      daniel   1540:         if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
1.21      daniel   1541:            return(1);
                   1542:     }
                   1543:     return(0);
                   1544: }
                   1545: 
1.22      daniel   1546: /**
1.43      daniel   1547:  * xmlRemoveID
                   1548:  * @doc:  the document
                   1549:  * @attr:  the attribute
                   1550:  *
                   1551:  * Remove the given attribute from the ID table maintained internally.
                   1552:  *
                   1553:  * Returns -1 if the lookup failed and 0 otherwise
                   1554:  */
                   1555: int
                   1556: xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
                   1557:     xmlIDPtr cur;
                   1558:     xmlIDTablePtr table;
                   1559:     int i;
                   1560: 
                   1561:     if (doc == NULL) return(-1);
                   1562:     if (attr == NULL) return(-1);
                   1563:     table = doc->ids;
                   1564:     if (table == NULL) 
                   1565:         return(-1);
                   1566: 
                   1567:     /*
                   1568:      * Search the ID list.
                   1569:      */
                   1570:     for (i = 0;i < table->nb_ids;i++) {
                   1571:         cur = table->table[i];
                   1572:        if (cur->attr == attr) {
                   1573:            table->nb_ids--;
                   1574:            memmove(&table->table[i], &table->table[i+1],
                   1575:                    (table->nb_ids - i) * sizeof(xmlIDPtr));
                   1576:            return(0);
                   1577:        }
                   1578:     }
                   1579:     return(-1);
                   1580: }
                   1581: 
                   1582: /**
1.22      daniel   1583:  * xmlGetID:
                   1584:  * @doc:  pointer to the document
                   1585:  * @ID:  the ID value
                   1586:  *
                   1587:  * Search the attribute declaring the given ID
                   1588:  *
                   1589:  * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
                   1590:  */
                   1591: xmlAttrPtr 
1.31      daniel   1592: xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
1.22      daniel   1593:     xmlIDPtr cur;
                   1594:     xmlIDTablePtr table;
                   1595:     int i;
                   1596: 
                   1597:     if (doc == NULL) {
                   1598:         fprintf(stderr, "xmlGetID: doc == NULL\n");
                   1599:        return(NULL);
                   1600:     }
                   1601: 
                   1602:     if (ID == NULL) {
                   1603:         fprintf(stderr, "xmlGetID: ID == NULL\n");
                   1604:        return(NULL);
                   1605:     }
                   1606: 
                   1607:     table = doc->ids;
                   1608:     if (table == NULL) 
                   1609:         return(NULL);
                   1610: 
                   1611:     /*
                   1612:      * Search the ID list.
                   1613:      */
                   1614:     for (i = 0;i < table->nb_ids;i++) {
                   1615:         cur = table->table[i];
                   1616:        if (!xmlStrcmp(cur->value, ID)) {
                   1617:            return(cur->attr);
                   1618:        }
                   1619:     }
                   1620:     return(NULL);
                   1621: }
                   1622: 
1.21      daniel   1623: /************************************************************************
                   1624:  *                                                                     *
1.27      daniel   1625:  *                             Refs                                    *
                   1626:  *                                                                     *
                   1627:  ************************************************************************/
                   1628: /**
                   1629:  * xmlCreateRefTable:
                   1630:  *
                   1631:  * create and initialize an empty ref hash table.
                   1632:  *
                   1633:  * Returns the xmlRefTablePtr just created or NULL in case
                   1634:  *                of error.
                   1635:  */
                   1636: xmlRefTablePtr
                   1637: xmlCreateRefTable(void) {
                   1638:     xmlRefTablePtr ret;
                   1639: 
                   1640:     ret = (xmlRefTablePtr) 
                   1641:          xmlMalloc(sizeof(xmlRefTable));
                   1642:     if (ret == NULL) {
                   1643:         fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
                   1644:                (long)sizeof(xmlRefTable));
                   1645:         return(NULL);
                   1646:     }
                   1647:     ret->max_refs = XML_MIN_NOTATION_TABLE;
                   1648:     ret->nb_refs = 0;
                   1649:     ret->table = (xmlRefPtr *) 
                   1650:          xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
                   1651:     if (ret == NULL) {
                   1652:         fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
                   1653:                ret->max_refs * (long)sizeof(xmlRef));
                   1654:        xmlFree(ret);
                   1655:         return(NULL);
                   1656:     }
                   1657:     return(ret);
                   1658: }
                   1659: 
                   1660: 
                   1661: /**
                   1662:  * xmlAddRef:
                   1663:  * @ctxt:  the validation context
                   1664:  * @doc:  pointer to the document
                   1665:  * @value:  the value name
                   1666:  * @attr:  the attribute holding the Ref
                   1667:  *
                   1668:  * Register a new ref declaration
                   1669:  *
                   1670:  * Returns NULL if not, othervise the new xmlRefPtr
                   1671:  */
                   1672: xmlRefPtr 
1.31      daniel   1673: xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
1.27      daniel   1674:          xmlAttrPtr attr) {
1.28      daniel   1675:     xmlRefPtr ret;
1.27      daniel   1676:     xmlRefTablePtr table;
                   1677: 
                   1678:     if (doc == NULL) {
                   1679:         fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
                   1680:        return(NULL);
                   1681:     }
                   1682:     if (value == NULL) {
                   1683:         fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
                   1684:        return(NULL);
                   1685:     }
                   1686:     if (attr == NULL) {
                   1687:         fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
                   1688:        return(NULL);
                   1689:     }
                   1690: 
                   1691:     /*
                   1692:      * Create the Ref table if needed.
                   1693:      */
                   1694:     table = doc->refs;
                   1695:     if (table == NULL) 
                   1696:         table = doc->refs = xmlCreateRefTable();
                   1697:     if (table == NULL) {
                   1698:        fprintf(stderr, "xmlAddRef: Table creation failed!\n");
                   1699:         return(NULL);
                   1700:     }
                   1701: 
                   1702:     /*
                   1703:      * Grow the table, if needed.
                   1704:      */
                   1705:     if (table->nb_refs >= table->max_refs) {
                   1706:         /*
                   1707:         * need more refs.
                   1708:         */
                   1709:        table->max_refs *= 2;
                   1710:        table->table = (xmlRefPtr *) 
                   1711:            xmlRealloc(table->table, table->max_refs *
                   1712:                    sizeof(xmlRefPtr));
                   1713:        if (table->table == NULL) {
                   1714:            fprintf(stderr, "xmlAddRef: out of memory\n");
                   1715:            return(NULL);
                   1716:        }
                   1717:     }
                   1718:     ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
                   1719:     if (ret == NULL) {
                   1720:        fprintf(stderr, "xmlAddRef: out of memory\n");
                   1721:        return(NULL);
                   1722:     }
                   1723:     table->table[table->nb_refs] = ret;
                   1724: 
                   1725:     /*
                   1726:      * fill the structure.
                   1727:      */
                   1728:     ret->value = xmlStrdup(value);
                   1729:     ret->attr = attr;
                   1730:     table->nb_refs++;
                   1731: 
                   1732:     return(ret);
                   1733: }
                   1734: 
                   1735: /**
                   1736:  * xmlFreeRef:
                   1737:  * @not:  A ref
                   1738:  *
                   1739:  * Deallocate the memory used by an ref definition
                   1740:  */
                   1741: void
                   1742: xmlFreeRef(xmlRefPtr ref) {
                   1743:     if (ref == NULL) return;
                   1744:     if (ref->value != NULL)
1.31      daniel   1745:        xmlFree((xmlChar *) ref->value);
1.27      daniel   1746:     memset(ref, -1, sizeof(xmlRef));
                   1747:     xmlFree(ref);
                   1748: }
                   1749: 
                   1750: /**
                   1751:  * xmlFreeRefTable:
                   1752:  * @table:  An ref table
                   1753:  *
                   1754:  * Deallocate the memory used by an Ref hash table.
                   1755:  */
                   1756: void
                   1757: xmlFreeRefTable(xmlRefTablePtr table) {
                   1758:     int i;
                   1759: 
                   1760:     if (table == NULL) return;
                   1761: 
                   1762:     for (i = 0;i < table->nb_refs;i++) {
                   1763:         xmlFreeRef(table->table[i]);
                   1764:     }
                   1765:     xmlFree(table->table);
                   1766:     xmlFree(table);
                   1767: }
                   1768: 
                   1769: /**
1.43      daniel   1770:  * xmlIsRef:
1.27      daniel   1771:  * @doc:  the document
                   1772:  * @elem:  the element carrying the attribute
                   1773:  * @attr:  the attribute
                   1774:  *
                   1775:  * Determine whether an attribute is of type Ref. In case we have Dtd(s)
                   1776:  * then this is simple, otherwise we use an heuristic: name Ref (upper
                   1777:  * or lowercase).
                   1778:  *
                   1779:  * Returns 0 or 1 depending on the lookup result
                   1780:  */
                   1781: int
                   1782: xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
                   1783:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
                   1784:         return(0);
                   1785:        /*******************
                   1786:         if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
                   1787:             ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
                   1788:            (attr->name[2] == 0)) return(1);
                   1789:         *******************/
                   1790:     } else {
                   1791:        xmlAttributePtr attrDecl;
                   1792: 
                   1793:        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   1794:        if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   1795:            attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
                   1796:                                         attr->name);
                   1797: 
                   1798:         if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
                   1799:            return(1);
                   1800:     }
                   1801:     return(0);
                   1802: }
                   1803: 
                   1804: /**
1.43      daniel   1805:  * xmlRemoveRef
                   1806:  * @doc:  the document
                   1807:  * @attr:  the attribute
                   1808:  *
                   1809:  * Remove the given attribute from the Ref table maintained internally.
                   1810:  *
                   1811:  * Returns -1 if the lookup failed and 0 otherwise
                   1812:  */
                   1813: int
                   1814: xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
                   1815:     xmlRefPtr cur;
                   1816:     xmlRefTablePtr table;
                   1817:     int i;
                   1818: 
                   1819:     if (doc == NULL) return(-1);
                   1820:     if (attr == NULL) return(-1);
                   1821:     table = doc->refs;
                   1822:     if (table == NULL) 
                   1823:         return(-1);
                   1824: 
                   1825:     /*
                   1826:      * Search the Ref list.
                   1827:      */
                   1828:     for (i = 0;i < table->nb_refs;i++) {
                   1829:         cur = table->table[i];
                   1830:        if (cur->attr == attr) {
                   1831:            table->nb_refs--;
                   1832:            memmove(&table->table[i], &table->table[i+1],
                   1833:                    (table->nb_refs - i) * sizeof(xmlRefPtr));
                   1834:            return(0);
                   1835:        }
                   1836:     }
                   1837:     return(-1);
                   1838: }
                   1839: 
                   1840: /**
1.27      daniel   1841:  * xmlGetRef:
                   1842:  * @doc:  pointer to the document
                   1843:  * @Ref:  the Ref value
                   1844:  *
1.43      daniel   1845:  * Search the next attribute declaring the given Ref
1.27      daniel   1846:  *
                   1847:  * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
                   1848:  */
                   1849: xmlAttrPtr 
1.31      daniel   1850: xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
1.27      daniel   1851:     xmlRefPtr cur;
                   1852:     xmlRefTablePtr table;
                   1853:     int i;
                   1854: 
                   1855:     if (doc == NULL) {
                   1856:         fprintf(stderr, "xmlGetRef: doc == NULL\n");
                   1857:        return(NULL);
                   1858:     }
                   1859: 
                   1860:     if (Ref == NULL) {
                   1861:         fprintf(stderr, "xmlGetRef: Ref == NULL\n");
                   1862:        return(NULL);
                   1863:     }
                   1864: 
                   1865:     table = doc->refs;
                   1866:     if (table == NULL) 
                   1867:         return(NULL);
                   1868: 
                   1869:     /*
                   1870:      * Search the Ref list.
                   1871:      */
                   1872:     for (i = 0;i < table->nb_refs;i++) {
                   1873:         cur = table->table[i];
                   1874:        if (!xmlStrcmp(cur->value, Ref)) {
                   1875:            return(cur->attr);
                   1876:        }
                   1877:     }
                   1878:     return(NULL);
                   1879: }
                   1880: 
                   1881: /************************************************************************
                   1882:  *                                                                     *
1.14      daniel   1883:  *             Routines for validity checking                          *
                   1884:  *                                                                     *
                   1885:  ************************************************************************/
                   1886: 
                   1887: /**
                   1888:  * xmlGetDtdElementDesc:
                   1889:  * @dtd:  a pointer to the DtD to search
                   1890:  * @name:  the element name
                   1891:  *
                   1892:  * Search the Dtd for the description of this element
                   1893:  *
                   1894:  * returns the xmlElementPtr if found or NULL
                   1895:  */
                   1896: 
                   1897: xmlElementPtr
1.31      daniel   1898: xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
1.14      daniel   1899:     xmlElementTablePtr table;
                   1900:     xmlElementPtr cur;
                   1901:     int i;
                   1902: 
                   1903:     if (dtd == NULL) return(NULL);
                   1904:     if (dtd->elements == NULL) return(NULL);
                   1905:     table = dtd->elements;
                   1906: 
                   1907:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel   1908:         cur = table->table[i];
1.14      daniel   1909:        if (!xmlStrcmp(cur->name, name))
                   1910:            return(cur);
                   1911:     }
                   1912:     return(NULL);
                   1913: }
                   1914: 
                   1915: /**
                   1916:  * xmlGetDtdAttrDesc:
                   1917:  * @dtd:  a pointer to the DtD to search
1.15      daniel   1918:  * @elem:  the element name
1.14      daniel   1919:  * @name:  the attribute name
                   1920:  *
1.15      daniel   1921:  * Search the Dtd for the description of this attribute on
                   1922:  * this element.
1.14      daniel   1923:  *
                   1924:  * returns the xmlAttributePtr if found or NULL
                   1925:  */
                   1926: 
                   1927: xmlAttributePtr
1.31      daniel   1928: xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
1.14      daniel   1929:     xmlAttributeTablePtr table;
                   1930:     xmlAttributePtr cur;
                   1931:     int i;
                   1932: 
                   1933:     if (dtd == NULL) return(NULL);
                   1934:     if (dtd->attributes == NULL) return(NULL);
                   1935:     table = dtd->attributes;
                   1936: 
                   1937:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel   1938:         cur = table->table[i];
                   1939:        if ((!xmlStrcmp(cur->name, name)) &&
                   1940:            (!xmlStrcmp(cur->elem, elem)))
1.14      daniel   1941:            return(cur);
                   1942:     }
                   1943:     return(NULL);
                   1944: }
                   1945: 
                   1946: /**
                   1947:  * xmlGetDtdNotationDesc:
                   1948:  * @dtd:  a pointer to the DtD to search
                   1949:  * @name:  the notation name
                   1950:  *
                   1951:  * Search the Dtd for the description of this notation
                   1952:  *
                   1953:  * returns the xmlNotationPtr if found or NULL
                   1954:  */
                   1955: 
                   1956: xmlNotationPtr
1.31      daniel   1957: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
1.14      daniel   1958:     xmlNotationTablePtr table;
                   1959:     xmlNotationPtr cur;
                   1960:     int i;
                   1961: 
                   1962:     if (dtd == NULL) return(NULL);
                   1963:     if (dtd->notations == NULL) return(NULL);
                   1964:     table = dtd->notations;
                   1965: 
                   1966:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1967:         cur = table->table[i];
1.14      daniel   1968:        if (!xmlStrcmp(cur->name, name))
                   1969:            return(cur);
                   1970:     }
                   1971:     return(NULL);
                   1972: }
                   1973: 
                   1974: /**
1.23      daniel   1975:  * xmlValidateNotationUse:
                   1976:  * @ctxt:  the validation context
                   1977:  * @doc:  the document
                   1978:  * @notationName:  the notation name to check
                   1979:  *
                   1980:  * Validate that the given mame match a notation declaration.
                   1981:  * - [ VC: Notation Declared ]
                   1982:  *
                   1983:  * returns 1 if valid or 0 otherwise
                   1984:  */
                   1985: 
                   1986: int
                   1987: xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31      daniel   1988:                        const xmlChar *notationName) {
1.23      daniel   1989:     xmlNotationPtr notaDecl;
                   1990:     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
                   1991: 
                   1992:     notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
                   1993:     if ((notaDecl == NULL) && (doc->extSubset != NULL))
                   1994:        notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
                   1995: 
                   1996:     if (notaDecl == NULL) {
                   1997:        VERROR(ctxt->userData, "NOTATION %s is not declared\n",
                   1998:               notationName);
                   1999:        return(0);
                   2000:     }
                   2001:     return(1);
                   2002: }
                   2003: 
                   2004: /**
1.18      daniel   2005:  * xmlIsMixedElement
                   2006:  * @doc:  the document
                   2007:  * @name:  the element name
                   2008:  *
                   2009:  * Search in the DtDs whether an element accept Mixed content (or ANY)
                   2010:  * basically if it is supposed to accept text childs
                   2011:  *
                   2012:  * returns 0 if no, 1 if yes, and -1 if no element description is available
                   2013:  */
                   2014: 
                   2015: int
1.31      daniel   2016: xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
1.18      daniel   2017:     xmlElementPtr elemDecl;
                   2018: 
                   2019:     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
                   2020: 
                   2021:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
                   2022:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   2023:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
                   2024:     if (elemDecl == NULL) return(-1);
                   2025:     switch (elemDecl->type) {
                   2026:        case XML_ELEMENT_TYPE_ELEMENT:
                   2027:            return(0);
                   2028:         case XML_ELEMENT_TYPE_EMPTY:
                   2029:            /*
                   2030:             * return 1 for EMPTY since we want VC error to pop up
                   2031:             * on <empty>     </empty> for example
                   2032:             */
                   2033:        case XML_ELEMENT_TYPE_ANY:
                   2034:        case XML_ELEMENT_TYPE_MIXED:
                   2035:            return(1);
                   2036:     }
                   2037:     return(1);
                   2038: }
                   2039: 
                   2040: /**
1.16      daniel   2041:  * xmlValidateNameValue:
                   2042:  * @value:  an Name value
                   2043:  *
                   2044:  * Validate that the given value match Name production
                   2045:  *
                   2046:  * returns 1 if valid or 0 otherwise
                   2047:  */
                   2048: 
                   2049: int
1.31      daniel   2050: xmlValidateNameValue(const xmlChar *value) {
                   2051:     const xmlChar *cur;
1.16      daniel   2052: 
                   2053:     if (value == NULL) return(0);
                   2054:     cur = value;
                   2055:     
                   2056:     if (!IS_LETTER(*cur) && (*cur != '_') &&
                   2057:         (*cur != ':')) {
                   2058:        return(0);
                   2059:     }
                   2060: 
                   2061:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2062:            (*cur == '.') || (*cur == '-') ||
                   2063:           (*cur == '_') || (*cur == ':') || 
                   2064:           (IS_COMBINING(*cur)) ||
                   2065:           (IS_EXTENDER(*cur)))
                   2066:           cur++;
                   2067: 
                   2068:     if (*cur != 0) return(0);
                   2069: 
                   2070:     return(1);
                   2071: }
                   2072: 
                   2073: /**
                   2074:  * xmlValidateNamesValue:
                   2075:  * @value:  an Names value
                   2076:  *
                   2077:  * Validate that the given value match Names production
                   2078:  *
                   2079:  * returns 1 if valid or 0 otherwise
                   2080:  */
                   2081: 
                   2082: int
1.31      daniel   2083: xmlValidateNamesValue(const xmlChar *value) {
                   2084:     const xmlChar *cur;
1.16      daniel   2085: 
                   2086:     if (value == NULL) return(0);
                   2087:     cur = value;
                   2088:     
                   2089:     if (!IS_LETTER(*cur) && (*cur != '_') &&
                   2090:         (*cur != ':')) {
                   2091:        return(0);
                   2092:     }
                   2093: 
                   2094:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2095:            (*cur == '.') || (*cur == '-') ||
                   2096:           (*cur == '_') || (*cur == ':') || 
                   2097:           (IS_COMBINING(*cur)) ||
                   2098:           (IS_EXTENDER(*cur)))
                   2099:           cur++;
                   2100: 
                   2101:     while (IS_BLANK(*cur)) {
                   2102:        while (IS_BLANK(*cur)) cur++;
                   2103: 
                   2104:        if (!IS_LETTER(*cur) && (*cur != '_') &&
                   2105:            (*cur != ':')) {
                   2106:            return(0);
                   2107:        }
                   2108: 
                   2109:        while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2110:               (*cur == '.') || (*cur == '-') ||
                   2111:               (*cur == '_') || (*cur == ':') || 
                   2112:               (IS_COMBINING(*cur)) ||
                   2113:               (IS_EXTENDER(*cur)))
                   2114:               cur++;
                   2115:     }
                   2116: 
                   2117:     if (*cur != 0) return(0);
                   2118: 
                   2119:     return(1);
                   2120: }
                   2121: 
                   2122: /**
                   2123:  * xmlValidateNmtokenValue:
                   2124:  * @value:  an Mntoken value
                   2125:  *
                   2126:  * Validate that the given value match Nmtoken production
                   2127:  *
                   2128:  * [ VC: Name Token ]
                   2129:  * 
                   2130:  * returns 1 if valid or 0 otherwise
                   2131:  */
                   2132: 
                   2133: int
1.31      daniel   2134: xmlValidateNmtokenValue(const xmlChar *value) {
                   2135:     const xmlChar *cur;
1.16      daniel   2136: 
                   2137:     if (value == NULL) return(0);
                   2138:     cur = value;
                   2139:     
                   2140:     if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
                   2141:         (*cur != '.') && (*cur != '-') &&
                   2142:         (*cur != '_') && (*cur != ':') && 
                   2143:         (!IS_COMBINING(*cur)) &&
                   2144:         (!IS_EXTENDER(*cur)))
                   2145:        return(0);
                   2146: 
                   2147:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2148:            (*cur == '.') || (*cur == '-') ||
                   2149:           (*cur == '_') || (*cur == ':') || 
                   2150:           (IS_COMBINING(*cur)) ||
                   2151:           (IS_EXTENDER(*cur)))
                   2152:           cur++;
                   2153: 
                   2154:     if (*cur != 0) return(0);
                   2155: 
                   2156:     return(1);
                   2157: }
                   2158: 
                   2159: /**
                   2160:  * xmlValidateNmtokensValue:
                   2161:  * @value:  an Mntokens value
                   2162:  *
                   2163:  * Validate that the given value match Nmtokens production
                   2164:  *
                   2165:  * [ VC: Name Token ]
                   2166:  * 
                   2167:  * returns 1 if valid or 0 otherwise
                   2168:  */
                   2169: 
                   2170: int
1.31      daniel   2171: xmlValidateNmtokensValue(const xmlChar *value) {
                   2172:     const xmlChar *cur;
1.16      daniel   2173: 
                   2174:     if (value == NULL) return(0);
                   2175:     cur = value;
                   2176:     
                   2177:     if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
                   2178:         (*cur != '.') && (*cur != '-') &&
                   2179:         (*cur != '_') && (*cur != ':') && 
                   2180:         (!IS_COMBINING(*cur)) &&
                   2181:         (!IS_EXTENDER(*cur)))
                   2182:        return(0);
                   2183: 
                   2184:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2185:            (*cur == '.') || (*cur == '-') ||
                   2186:           (*cur == '_') || (*cur == ':') || 
                   2187:           (IS_COMBINING(*cur)) ||
                   2188:           (IS_EXTENDER(*cur)))
                   2189:           cur++;
                   2190: 
                   2191:     while (IS_BLANK(*cur)) {
                   2192:        while (IS_BLANK(*cur)) cur++;
                   2193: 
                   2194:        if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
                   2195:            (*cur != '.') && (*cur != '-') &&
                   2196:            (*cur != '_') && (*cur != ':') && 
                   2197:            (!IS_COMBINING(*cur)) &&
                   2198:            (!IS_EXTENDER(*cur)))
                   2199:            return(0);
                   2200: 
                   2201:        while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2202:               (*cur == '.') || (*cur == '-') ||
                   2203:               (*cur == '_') || (*cur == ':') || 
                   2204:               (IS_COMBINING(*cur)) ||
                   2205:               (IS_EXTENDER(*cur)))
                   2206:               cur++;
                   2207:     }
                   2208: 
                   2209:     if (*cur != 0) return(0);
                   2210: 
                   2211:     return(1);
                   2212: }
                   2213: 
                   2214: /**
                   2215:  * xmlValidateNotationDecl:
1.23      daniel   2216:  * @ctxt:  the validation context
1.16      daniel   2217:  * @doc:  a document instance
                   2218:  * @nota:  a notation definition
                   2219:  *
                   2220:  * Try to validate a single notation definition
                   2221:  * basically it does the following checks as described by the
                   2222:  * XML-1.0 recommendation:
1.18      daniel   2223:  *  - it seems that no validity constraing exist on notation declarations
                   2224:  * But this function get called anyway ...
1.16      daniel   2225:  *
                   2226:  * returns 1 if valid or 0 otherwise
                   2227:  */
                   2228: 
                   2229: int
                   2230: xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
                   2231:                          xmlNotationPtr nota) {
                   2232:     int ret = 1;
                   2233: 
                   2234:     return(ret);
                   2235: }
                   2236: 
                   2237: /**
                   2238:  * xmlValidateAttributeValue:
                   2239:  * @type:  an attribute type
                   2240:  * @value:  an attribute value
                   2241:  *
                   2242:  * Validate that the given attribute value match  the proper production
                   2243:  *
                   2244:  * [ VC: ID ]
                   2245:  * Values of type ID must match the Name production....
                   2246:  *
                   2247:  * [ VC: IDREF ]
                   2248:  * Values of type IDREF must match the Name production, and values
                   2249:  * of type IDREFS must match Names ...
                   2250:  *
                   2251:  * [ VC: Entity Name ]
                   2252:  * Values of type ENTITY must match the Name production, values
                   2253:  * of type ENTITIES must match Names ...
                   2254:  *
                   2255:  * [ VC: Name Token ]
                   2256:  * Values of type NMTOKEN must match the Nmtoken production; values
                   2257:  * of type NMTOKENS must match Nmtokens. 
                   2258:  *
                   2259:  * returns 1 if valid or 0 otherwise
                   2260:  */
                   2261: 
                   2262: int
1.31      daniel   2263: xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
1.16      daniel   2264:     switch (type) {
1.24      daniel   2265:        case XML_ATTRIBUTE_ENTITIES:
1.16      daniel   2266:        case XML_ATTRIBUTE_IDREFS:
                   2267:            return(xmlValidateNamesValue(value));
1.24      daniel   2268:        case XML_ATTRIBUTE_ENTITY:
1.16      daniel   2269:        case XML_ATTRIBUTE_IDREF:
                   2270:        case XML_ATTRIBUTE_ID:
                   2271:        case XML_ATTRIBUTE_NOTATION:
                   2272:            return(xmlValidateNameValue(value));
                   2273:        case XML_ATTRIBUTE_NMTOKENS:
                   2274:        case XML_ATTRIBUTE_ENUMERATION:
                   2275:            return(xmlValidateNmtokensValue(value));
                   2276:        case XML_ATTRIBUTE_NMTOKEN:
                   2277:            return(xmlValidateNmtokenValue(value));
                   2278:         case XML_ATTRIBUTE_CDATA:
                   2279:            break;
                   2280:     }
                   2281:     return(1);
                   2282: }
                   2283: 
                   2284: /**
1.14      daniel   2285:  * xmlValidateAttributeDecl:
1.23      daniel   2286:  * @ctxt:  the validation context
1.14      daniel   2287:  * @doc:  a document instance
                   2288:  * @attr:  an attribute definition
                   2289:  *
                   2290:  * Try to validate a single attribute definition
                   2291:  * basically it does the following checks as described by the
                   2292:  * XML-1.0 recommendation:
                   2293:  *  - [ VC: Attribute Default Legal ]
                   2294:  *  - [ VC: Enumeration ]
                   2295:  *  - [ VC: ID Attribute Default ]
                   2296:  *
                   2297:  * The ID/IDREF uniqueness and matching are done separately
                   2298:  *
                   2299:  * returns 1 if valid or 0 otherwise
                   2300:  */
                   2301: 
                   2302: int
                   2303: xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
                   2304:                          xmlAttributePtr attr) {
1.16      daniel   2305:     int ret = 1;
                   2306:     int val;
1.14      daniel   2307:     CHECK_DTD;
1.16      daniel   2308:     if(attr == NULL) return(1);
                   2309:     
                   2310:     /* Attribute Default Legal */
                   2311:     /* Enumeration */
                   2312:     if (attr->defaultValue != NULL) {
                   2313:        val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
                   2314:        if (val == 0) {
                   2315:            VERROR(ctxt->userData, 
                   2316:               "Syntax of default value for attribute %s on %s is not valid\n",
                   2317:                   attr->name, attr->elem);
                   2318:        }
                   2319:         ret &= val;
                   2320:     }
                   2321: 
                   2322:     /* ID Attribute Default */
                   2323:     if ((attr->type == XML_ATTRIBUTE_ID)&&
                   2324:         (attr->def != XML_ATTRIBUTE_IMPLIED) &&
                   2325:        (attr->def != XML_ATTRIBUTE_REQUIRED)) {
                   2326:        VERROR(ctxt->userData, 
                   2327:           "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
                   2328:               attr->name, attr->elem);
                   2329:        ret = 0;
                   2330:     }
                   2331: 
1.24      daniel   2332:     /* One ID per Element Type */
1.16      daniel   2333:     if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
                   2334:         int nbId = 0;
                   2335: 
                   2336:        /* the trick is taht we parse DtD as their own internal subset */
                   2337:         xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
                   2338:                                                  attr->elem);
                   2339:        if (elem != NULL) {
                   2340:            nbId = xmlScanIDAttributeDecl(NULL, elem);
                   2341:        }
                   2342:        if (nbId >= 1)
                   2343:            VERROR(ctxt->userData, 
                   2344:           "Element %s has ID attribute defined in the external subset : %s\n",
                   2345:                   attr->elem, attr->name);
                   2346:     }
1.14      daniel   2347: 
1.16      daniel   2348:     return(ret);
1.14      daniel   2349: }
                   2350: 
                   2351: /**
                   2352:  * xmlValidateElementDecl:
                   2353:  * @ctxt:  the validation context
                   2354:  * @doc:  a document instance
                   2355:  * @elem:  an element definition
                   2356:  *
                   2357:  * Try to validate a single element definition
                   2358:  * basically it does the following checks as described by the
                   2359:  * XML-1.0 recommendation:
                   2360:  *  - [ VC: One ID per Element Type ]
                   2361:  *  - [ VC: No Duplicate Types ]
                   2362:  *  - [ VC: Unique Element Type Declaration ]
                   2363:  *
                   2364:  * returns 1 if valid or 0 otherwise
                   2365:  */
                   2366: 
                   2367: int
1.16      daniel   2368: xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
                   2369:                        xmlElementPtr elem) {
                   2370:     int ret = 1;
                   2371:     xmlElementPtr tst;
                   2372: 
1.14      daniel   2373:     CHECK_DTD;
1.16      daniel   2374:     
                   2375:     if (elem == NULL) return(1);
1.14      daniel   2376: 
1.16      daniel   2377:     /* No Duplicate Types */
                   2378:     if (elem->type == XML_ELEMENT_TYPE_MIXED) {
                   2379:        xmlElementContentPtr cur, next;
1.31      daniel   2380:         const xmlChar *name;
1.16      daniel   2381: 
                   2382:        cur = elem->content;
                   2383:        while (cur != NULL) {
                   2384:            if (cur->type != XML_ELEMENT_CONTENT_OR) break;
                   2385:            if (cur->c1 == NULL) break;
                   2386:            if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
                   2387:                name = cur->c1->name;
                   2388:                next = cur->c2;
                   2389:                while (next != NULL) {
                   2390:                    if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
                   2391:                        if (!xmlStrcmp(next->name, name)) {
                   2392:                            VERROR(ctxt->userData, 
                   2393:                   "Definition of %s has duplicate references of %s\n",
                   2394:                                   elem->name, name);
                   2395:                            ret = 0;
                   2396:                        }
                   2397:                        break;
                   2398:                    }
                   2399:                    if (next->c1 == NULL) break;
                   2400:                    if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
                   2401:                    if (!xmlStrcmp(next->c1->name, name)) {
                   2402:                        VERROR(ctxt->userData, 
                   2403:               "Definition of %s has duplicate references of %s\n",
                   2404:                               elem->name, name);
                   2405:                        ret = 0;
                   2406:                    }
                   2407:                    next = next->c2;
                   2408:                }
                   2409:            }
                   2410:            cur = cur->c2;
                   2411:        }
                   2412:     }
                   2413: 
                   2414:     /* VC: Unique Element Type Declaration */
                   2415:     tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
                   2416:     if ((tst != NULL ) && (tst != elem)) {
                   2417:        VERROR(ctxt->userData, "Redefinition of element %s\n",
                   2418:               elem->name);
                   2419:        ret = 0;
                   2420:     }
                   2421:     tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
                   2422:     if ((tst != NULL ) && (tst != elem)) {
                   2423:        VERROR(ctxt->userData, "Redefinition of element %s\n",
                   2424:               elem->name);
                   2425:        ret = 0;
                   2426:     }
                   2427: 
                   2428:     /* One ID per Element Type */
                   2429:     if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
                   2430:        ret = 0;
                   2431:     }
                   2432:     return(ret);
1.14      daniel   2433: }
                   2434: 
                   2435: /**
                   2436:  * xmlValidateOneAttribute:
                   2437:  * @ctxt:  the validation context
                   2438:  * @doc:  a document instance
                   2439:  * @elem:  an element instance
                   2440:  * @attr:  an attribute instance
1.32      daniel   2441:  * @value:  the attribute value (without entities processing)
1.14      daniel   2442:  *
                   2443:  * Try to validate a single attribute for an element
                   2444:  * basically it * does the following checks as described by the
                   2445:  * XML-1.0 recommendation:
1.18      daniel   2446:  *  - [ VC: Attribute Value Type ]
                   2447:  *  - [ VC: Fixed Attribute Default ]
1.14      daniel   2448:  *  - [ VC: Entity Name ]
                   2449:  *  - [ VC: Name Token ]
                   2450:  *  - [ VC: ID ]
                   2451:  *  - [ VC: IDREF ]
                   2452:  *  - [ VC: Entity Name ]
1.16      daniel   2453:  *  - [ VC: Notation Attributes ]
1.14      daniel   2454:  *
                   2455:  * The ID/IDREF uniqueness and matching are done separately
                   2456:  *
                   2457:  * returns 1 if valid or 0 otherwise
                   2458:  */
                   2459: 
                   2460: int
1.16      daniel   2461: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31      daniel   2462:                         xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
1.24      daniel   2463:     /* xmlElementPtr elemDecl; */
1.18      daniel   2464:     xmlAttributePtr attrDecl;
                   2465:     int val;
                   2466:     int ret = 1;
                   2467: 
1.14      daniel   2468:     CHECK_DTD;
1.18      daniel   2469:     if ((elem == NULL) || (elem->name == NULL)) return(0);
                   2470:     if ((attr == NULL) || (attr->name == NULL)) return(0);
                   2471: 
                   2472:     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   2473:     if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   2474:        attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
                   2475: 
1.14      daniel   2476: 
1.18      daniel   2477:     /* Validity Constraint: Attribute Value Type */
                   2478:     if (attrDecl == NULL) {
                   2479:        VERROR(ctxt->userData,
                   2480:               "No declaration for attribute %s on element %s\n",
                   2481:               attr->name, elem->name);
                   2482:        return(0);
                   2483:     }
                   2484:     val = xmlValidateAttributeValue(attrDecl->type, value);
                   2485:     if (val == 0) {
                   2486:        VERROR(ctxt->userData, 
                   2487:           "Syntax of value for attribute %s on %s is not valid\n",
                   2488:               attr->name, elem->name);
                   2489:         ret = 0;
1.22      daniel   2490:     }
                   2491: 
                   2492:     /* Validity Constraint: ID uniqueness */
                   2493:     if (attrDecl->type == XML_ATTRIBUTE_ID) {
                   2494:         xmlAddID(ctxt, doc, value, attr);
1.18      daniel   2495:     }
                   2496: 
1.28      daniel   2497:     if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
                   2498:         xmlAddRef(ctxt, doc, value, attr);
                   2499:     }
                   2500: 
1.18      daniel   2501:     /* Validity Constraint: Notation Attributes */
                   2502:     if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
                   2503:         xmlEnumerationPtr tree = attrDecl->tree;
                   2504:         xmlNotationPtr nota;
                   2505: 
                   2506:         /* First check that the given NOTATION was declared */
                   2507:        nota = xmlGetDtdNotationDesc(doc->intSubset, value);
                   2508:        if (nota == NULL)
                   2509:            nota = xmlGetDtdNotationDesc(doc->extSubset, value);
                   2510:        
                   2511:        if (nota == NULL) {
                   2512:            VERROR(ctxt->userData, 
                   2513:        "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
                   2514:                   value, attr->name, elem->name);
                   2515:            ret = 0;
                   2516:         }
                   2517: 
                   2518:        /* Second, verify that it's among the list */
                   2519:        while (tree != NULL) {
                   2520:            if (!xmlStrcmp(tree->name, value)) break;
                   2521:            tree = tree->next;
                   2522:        }
                   2523:        if (tree == NULL) {
                   2524:            VERROR(ctxt->userData, 
                   2525:    "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
                   2526:                   value, attr->name, elem->name);
                   2527:            ret = 0;
                   2528:        }
                   2529:     }
                   2530: 
                   2531:     /* Validity Constraint: Enumeration */
                   2532:     if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
                   2533:         xmlEnumerationPtr tree = attrDecl->tree;
                   2534:        while (tree != NULL) {
                   2535:            if (!xmlStrcmp(tree->name, value)) break;
                   2536:            tree = tree->next;
                   2537:        }
                   2538:        if (tree == NULL) {
                   2539:            VERROR(ctxt->userData, 
                   2540:        "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
                   2541:                   value, attr->name, elem->name);
                   2542:            ret = 0;
                   2543:        }
                   2544:     }
                   2545: 
                   2546:     /* Fixed Attribute Default */
                   2547:     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
                   2548:         (xmlStrcmp(attrDecl->defaultValue, value))) {
                   2549:        VERROR(ctxt->userData, 
                   2550:           "Value for attribute %s on %s must be \"%s\"\n",
                   2551:               attr->name, elem->name, attrDecl->defaultValue);
                   2552:         ret = 0;
                   2553:     }
                   2554: 
1.24      daniel   2555:     /********
1.18      daniel   2556:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
                   2557:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   2558:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
                   2559:     if (elemDecl == NULL) {
                   2560:        return(0);
                   2561:     }
1.24      daniel   2562:      ********/
1.18      daniel   2563:     return(ret);
                   2564: }
                   2565: 
                   2566: int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2567:                                  xmlElementContentPtr cont);
                   2568: 
                   2569: /**
                   2570:  * xmlValidateElementTypeExpr:
                   2571:  * @ctxt:  the validation context
                   2572:  * @child:  pointer to the child list
                   2573:  * @cont:  pointer to the content declaration
                   2574:  *
                   2575:  * Try to validate the content of an element of type element
                   2576:  * but don't handle the occurence factor
                   2577:  *
                   2578:  * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
                   2579:  *         also update child value in-situ.
                   2580:  */
                   2581: 
                   2582: int
                   2583: xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2584:                           xmlElementContentPtr cont) {
                   2585:     xmlNodePtr cur;
                   2586:     int ret = 1;
                   2587: 
                   2588:     if (cont == NULL) return(-1);
                   2589:     while (*child != NULL) {
                   2590:         if ((*child)->type == XML_PI_NODE) {
                   2591:            *child = (*child)->next;
                   2592:            continue;
                   2593:        }
                   2594:         if ((*child)->type == XML_COMMENT_NODE) {
                   2595:            *child = (*child)->next;
                   2596:            continue;
                   2597:        }
                   2598:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2599:            return(-1);
                   2600:        }
                   2601:        break;
                   2602:     }
                   2603:     switch (cont->type) {
                   2604:        case XML_ELEMENT_CONTENT_PCDATA:
1.45      daniel   2605:            if (*child == NULL) return(0);
                   2606:            if ((*child)->type == XML_TEXT_NODE) return(1);
                   2607:            return(0);
1.18      daniel   2608:        case XML_ELEMENT_CONTENT_ELEMENT:
1.20      daniel   2609:            if (*child == NULL) return(0);
1.18      daniel   2610:            ret = (!xmlStrcmp((*child)->name, cont->name));
                   2611:            if (ret == 1)
                   2612:                *child = (*child)->next;
                   2613:            return(ret);
                   2614:        case XML_ELEMENT_CONTENT_OR:
                   2615:            cur = *child;
                   2616:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
                   2617:            if (ret == -1) return(-1);
                   2618:            if (ret == 1) {
                   2619:                 return(1);
                   2620:            }
                   2621:            /* rollback and retry the other path */
                   2622:            *child = cur;
                   2623:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
                   2624:            if (ret == -1) return(-1);
                   2625:            if (ret == 0) {
                   2626:                *child = cur;
                   2627:                return(0);
                   2628:            }
                   2629:            return(1);
                   2630:        case XML_ELEMENT_CONTENT_SEQ:
                   2631:            cur = *child;
                   2632:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
                   2633:            if (ret == -1) return(-1);
                   2634:            if (ret == 0) {
                   2635:                *child = cur;
                   2636:                return(0);
                   2637:            }
                   2638:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
                   2639:            if (ret == -1) return(-1);
                   2640:            if (ret == 0) {
                   2641:                *child = cur;
                   2642:                return(0);
                   2643:            }
                   2644:            return(1);
                   2645:     }
                   2646:     return(ret);
                   2647: }
                   2648: 
                   2649: /**
                   2650:  * xmlValidateElementTypeElement:
                   2651:  * @ctxt:  the validation context
                   2652:  * @child:  pointer to the child list
                   2653:  * @cont:  pointer to the content declaration
                   2654:  *
                   2655:  * Try to validate the content of an element of type element
                   2656:  * yeah, Yet Another Regexp Implementation, and recursive
                   2657:  *
                   2658:  * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
                   2659:  *         also update child and content values in-situ.
                   2660:  */
                   2661: 
                   2662: int
                   2663: xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2664:                              xmlElementContentPtr cont) {
                   2665:     xmlNodePtr cur;
                   2666:     int ret = 1;
                   2667: 
                   2668:     if (cont == NULL) return(-1);
                   2669:     while (*child != NULL) {
                   2670:         if ((*child)->type == XML_PI_NODE) {
                   2671:            *child = (*child)->next;
                   2672:            continue;
                   2673:        }
                   2674:         if ((*child)->type == XML_COMMENT_NODE) {
                   2675:            *child = (*child)->next;
                   2676:            continue;
                   2677:        }
                   2678:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2679:            return(-1);
                   2680:        }
                   2681:        break;
                   2682:     }
                   2683:     cur = *child;
                   2684:     ret = xmlValidateElementTypeExpr(ctxt, child, cont);
                   2685:     if (ret == -1) return(-1);
                   2686:     switch (cont->ocur) {
                   2687:        case XML_ELEMENT_CONTENT_ONCE:
                   2688:            if (ret == 1) {
                   2689:                return(1);
                   2690:            }
                   2691:            *child = cur;
                   2692:            return(0);
                   2693:        case XML_ELEMENT_CONTENT_OPT:
                   2694:            if (ret == 0) {
                   2695:                *child = cur;
                   2696:                return(1);
                   2697:            }
1.19      daniel   2698:            break;
1.18      daniel   2699:        case XML_ELEMENT_CONTENT_MULT:
                   2700:            if (ret == 0) {
                   2701:                *child = cur;
1.19      daniel   2702:                break;
1.18      daniel   2703:            }
                   2704:            /* no break on purpose */
                   2705:        case XML_ELEMENT_CONTENT_PLUS:
                   2706:            if (ret == 0) {
                   2707:                *child = cur;
                   2708:                return(0);
                   2709:            }
                   2710:            do {
                   2711:                cur = *child;
                   2712:                ret = xmlValidateElementTypeExpr(ctxt, child, cont);
                   2713:            } while (ret == 1);
                   2714:            if (ret == -1) return(-1);
                   2715:            *child = cur;
1.19      daniel   2716:            break;
                   2717:     }
                   2718:     while (*child != NULL) {
                   2719:         if ((*child)->type == XML_PI_NODE) {
                   2720:            *child = (*child)->next;
                   2721:            continue;
                   2722:        }
                   2723:         if ((*child)->type == XML_COMMENT_NODE) {
                   2724:            *child = (*child)->next;
                   2725:            continue;
                   2726:        }
                   2727:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2728:            return(-1);
                   2729:        }
                   2730:        break;
                   2731:     }
                   2732:     return(1);
                   2733: }
                   2734: 
                   2735: /**
                   2736:  * xmlSprintfElementChilds:
                   2737:  * @buf:  an output buffer
                   2738:  * @content:  An element
                   2739:  * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
                   2740:  *
                   2741:  * This will dump the list of childs to the buffer
                   2742:  * Intended just for the debug routine
                   2743:  */
                   2744: void
                   2745: xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
                   2746:     xmlNodePtr cur;
                   2747: 
                   2748:     if (node == NULL) return;
                   2749:     if (glob) strcat(buf, "(");
1.46    ! daniel   2750:     cur = node->children;
1.19      daniel   2751:     while (cur != NULL) {
                   2752:         switch (cur->type) {
                   2753:             case XML_ELEMENT_NODE:
1.23      daniel   2754:                 strcat(buf, (char *) cur->name);
1.19      daniel   2755:                 if (cur->next != NULL)
                   2756:                     strcat(buf, " ");
                   2757:                 break;
                   2758:             case XML_TEXT_NODE:
                   2759:             case XML_CDATA_SECTION_NODE:
                   2760:             case XML_ENTITY_REF_NODE:
                   2761:                 strcat(buf, "CDATA");
                   2762:                 if (cur->next != NULL)
                   2763:                     strcat(buf, " ");
                   2764:                 break;
                   2765:             case XML_ATTRIBUTE_NODE:
                   2766:             case XML_DOCUMENT_NODE:
1.35      daniel   2767:            case XML_HTML_DOCUMENT_NODE:
1.19      daniel   2768:             case XML_DOCUMENT_TYPE_NODE:
                   2769:             case XML_DOCUMENT_FRAG_NODE:
                   2770:             case XML_NOTATION_NODE:
                   2771:                 strcat(buf, "???");
                   2772:                 if (cur->next != NULL)
                   2773:                     strcat(buf, " ");
                   2774:                 break;
                   2775:             case XML_ENTITY_NODE:
                   2776:             case XML_PI_NODE:
1.46    ! daniel   2777:             case XML_DTD_NODE:
1.19      daniel   2778:             case XML_COMMENT_NODE:
                   2779:                 break;
                   2780:        }
                   2781:        cur = cur->next;
1.18      daniel   2782:     }
1.19      daniel   2783:     if (glob) strcat(buf, ")");
1.14      daniel   2784: }
                   2785: 
1.19      daniel   2786: 
1.14      daniel   2787: /**
                   2788:  * xmlValidateOneElement:
                   2789:  * @ctxt:  the validation context
                   2790:  * @doc:  a document instance
                   2791:  * @elem:  an element instance
                   2792:  *
                   2793:  * Try to validate a single element and it's attributes,
                   2794:  * basically it does the following checks as described by the
                   2795:  * XML-1.0 recommendation:
                   2796:  *  - [ VC: Element Valid ]
                   2797:  *  - [ VC: Required Attribute ]
                   2798:  * Then call xmlValidateOneAttribute() for each attribute present.
                   2799:  *
                   2800:  * The ID/IDREF checkings are done separately
                   2801:  *
                   2802:  * returns 1 if valid or 0 otherwise
                   2803:  */
                   2804: 
                   2805: int
1.16      daniel   2806: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18      daniel   2807:                       xmlNodePtr elem) {
                   2808:     xmlElementPtr elemDecl;
                   2809:     xmlElementContentPtr cont;
1.42      daniel   2810:     xmlAttributePtr attr;
1.18      daniel   2811:     xmlNodePtr child;
                   2812:     int ret = 1;
1.31      daniel   2813:     const xmlChar *name;
1.18      daniel   2814: 
1.14      daniel   2815:     CHECK_DTD;
                   2816: 
1.39      daniel   2817:     if (elem == NULL) return(0);
                   2818:     if (elem->type == XML_TEXT_NODE) {
1.40      daniel   2819:     }
                   2820:     switch (elem->type) {
                   2821:         case XML_ATTRIBUTE_NODE:
                   2822:            VERROR(ctxt->userData, 
                   2823:                   "Attribute element not expected here\n");
1.39      daniel   2824:            return(0);
1.40      daniel   2825:         case XML_TEXT_NODE:
1.46    ! daniel   2826:            if (elem->children != NULL) {
1.40      daniel   2827:                VERROR(ctxt->userData, "Text element has childs !\n");
                   2828:                return(0);
                   2829:            }
                   2830:            if (elem->properties != NULL) {
                   2831:                VERROR(ctxt->userData, "Text element has attributes !\n");
                   2832:                return(0);
                   2833:            }
                   2834:            if (elem->ns != NULL) {
                   2835:                VERROR(ctxt->userData, "Text element has namespace !\n");
                   2836:                return(0);
                   2837:            }
                   2838:            if (elem->ns != NULL) {
                   2839:                VERROR(ctxt->userData, 
                   2840:                       "Text element carries namespace definitions !\n");
                   2841:                return(0);
                   2842:            }
                   2843:            if (elem->content == NULL) {
                   2844:                VERROR(ctxt->userData, 
                   2845:                       "Text element has no content !\n");
                   2846:                return(0);
                   2847:            }
                   2848:            return(1);
                   2849:         case XML_CDATA_SECTION_NODE:
                   2850:         case XML_ENTITY_REF_NODE:
                   2851:         case XML_PI_NODE:
                   2852:         case XML_COMMENT_NODE:
                   2853:            return(1);
                   2854:         case XML_ENTITY_NODE:
                   2855:            VERROR(ctxt->userData, 
                   2856:                   "Entity element not expected here\n");
1.39      daniel   2857:            return(0);
1.40      daniel   2858:         case XML_NOTATION_NODE:
                   2859:            VERROR(ctxt->userData, 
                   2860:                   "Notation element not expected here\n");
                   2861:            return(0);
                   2862:         case XML_DOCUMENT_NODE:
                   2863:         case XML_DOCUMENT_TYPE_NODE:
                   2864:         case XML_DOCUMENT_FRAG_NODE:
                   2865:            VERROR(ctxt->userData, 
                   2866:                   "Document element not expected here\n");
1.39      daniel   2867:            return(0);
1.40      daniel   2868:         case XML_HTML_DOCUMENT_NODE:
1.39      daniel   2869:            VERROR(ctxt->userData, 
1.40      daniel   2870:                   "\n");
1.39      daniel   2871:            return(0);
1.40      daniel   2872:         case XML_ELEMENT_NODE:
                   2873:            break;
                   2874:        default:
1.39      daniel   2875:            VERROR(ctxt->userData, 
1.40      daniel   2876:                   "unknown element type %d\n", elem->type);
1.39      daniel   2877:            return(0);
                   2878:     }
                   2879:     if (elem->name == NULL) return(0);
1.18      daniel   2880: 
                   2881:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
                   2882:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   2883:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
                   2884:     if (elemDecl == NULL) {
                   2885:        VERROR(ctxt->userData, "No declaration for element %s\n",
                   2886:               elem->name);
                   2887:        return(0);
                   2888:     }
                   2889: 
                   2890:     /* Check taht the element content matches the definition */
                   2891:     switch (elemDecl->type) {
                   2892:         case XML_ELEMENT_TYPE_EMPTY:
1.46    ! daniel   2893:            if (elem->children != NULL) {
1.18      daniel   2894:                VERROR(ctxt->userData,
                   2895:               "Element %s was declared EMPTY this one has content\n",
                   2896:                       elem->name);
                   2897:                ret = 0;
                   2898:            }
                   2899:            break;
                   2900:         case XML_ELEMENT_TYPE_ANY:
                   2901:            /* I don't think anything is required then */
                   2902:            break;
                   2903:         case XML_ELEMENT_TYPE_MIXED:
                   2904:            /* Hum, this start to get messy */
1.46    ! daniel   2905:            child = elem->children;
1.18      daniel   2906:            while (child != NULL) {
                   2907:                if (child->type == XML_ELEMENT_NODE) {
                   2908:                    name = child->name;
                   2909:                    cont = elemDecl->content;
                   2910:                    while (cont != NULL) {
                   2911:                        if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
                   2912:                            if (!xmlStrcmp(cont->name, name)) break;
                   2913:                        } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
                   2914:                           (cont->c1 != NULL) &&
                   2915:                           (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
                   2916:                            if (!xmlStrcmp(cont->c1->name, name)) break;
                   2917:                        } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
                   2918:                            (cont->c1 == NULL) ||
                   2919:                            (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
                   2920:                            /* Internal error !!! */
                   2921:                            fprintf(stderr, "Internal: MIXED struct bad\n");
                   2922:                            break;
                   2923:                        }
                   2924:                        cont = cont->c2;
                   2925:                    }
                   2926:                    if (cont == NULL) {
                   2927:                        VERROR(ctxt->userData,
                   2928:               "Element %s is not declared in %s list of possible childs\n",
                   2929:                               name, elem->name);
                   2930:                        ret = 0;
                   2931:                    }
                   2932:                }
                   2933:                child = child->next;
                   2934:            }
                   2935:            break;
                   2936:         case XML_ELEMENT_TYPE_ELEMENT:
1.46    ! daniel   2937:            child = elem->children;
1.18      daniel   2938:            cont = elemDecl->content;
                   2939:            ret = xmlValidateElementTypeElement(ctxt, &child, cont);
1.19      daniel   2940:            if ((ret == 0) || (child != NULL)) {
                   2941:                char expr[1000];
                   2942:                char list[2000];
                   2943: 
                   2944:                expr[0] = 0;
                   2945:                xmlSprintfElementContent(expr, cont, 1);
                   2946:                list[0] = 0;
                   2947:                xmlSprintfElementChilds(list, elem, 1);
                   2948: 
1.18      daniel   2949:                VERROR(ctxt->userData,
1.19      daniel   2950:           "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
                   2951:                       elem->name, expr, list);
1.18      daniel   2952:                ret = 0;
                   2953:            }
                   2954:            break;
                   2955:     }
                   2956: 
1.42      daniel   2957:     /* [ VC: Required Attribute ] */
                   2958:     attr = elemDecl->attributes;
                   2959:     while (attr != NULL) {
                   2960:        if (attr->def == XML_ATTRIBUTE_REQUIRED) {
                   2961:            xmlAttrPtr attrib;
                   2962:            int qualified = -1;
                   2963:            
                   2964:            attrib = elem->properties;
                   2965:            while (attrib != NULL) {
                   2966:                if (!xmlStrcmp(attrib->name, attr->name)) {
                   2967:                    if (attr->prefix != NULL) {
                   2968:                        xmlNsPtr nameSpace = attrib->ns;
                   2969: 
                   2970:                        if (nameSpace == NULL)
                   2971:                            nameSpace = elem->ns;
                   2972:                        /*
                   2973:                         * qualified names handling is problematic, having a
                   2974:                         * different prefix should be possible but DTDs don't
                   2975:                         * allow to define the URI instead of the prefix :-(
                   2976:                         */
                   2977:                        if (nameSpace == NULL) {
                   2978:                            if (qualified < 0) 
                   2979:                                qualified = 0;
                   2980:                        } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
                   2981:                            if (qualified < 1) 
                   2982:                                qualified = 1;
                   2983:                        } else
                   2984:                            goto found;
                   2985:                    } else {
                   2986:                        /*
                   2987:                         * We should allow applications to define namespaces
                   2988:                         * for their application even if the DTD doesn't 
                   2989:                         * carry one, otherwise, basically we would always
                   2990:                         * break.
                   2991:                         */
                   2992:                        goto found;
                   2993:                    }
                   2994:                }
                   2995:                attrib = attrib->next;
                   2996:            }
                   2997:            if (qualified == -1) {
                   2998:                if (attr->prefix == NULL) {
                   2999:                    VERROR(ctxt->userData,
                   3000:                       "Element %s doesn't carry attribute %s\n",
                   3001:                           elem->name, attr->name);
                   3002:                } else {
                   3003:                    VERROR(ctxt->userData,
                   3004:                       "Element %s doesn't carry attribute %s:%s\n",
                   3005:                           elem->name, attr->prefix,attr->name);
                   3006:                }
                   3007:            } else if (qualified == 0) {
                   3008:                VWARNING(ctxt->userData,
                   3009:                   "Element %s required attribute %s:%s has no prefix\n",
                   3010:                       elem->name, attr->prefix,attr->name);
                   3011:            } else if (qualified == 1) {
                   3012:                VWARNING(ctxt->userData,
                   3013:                   "Element %s required attribute %s:%s has different prefix\n",
                   3014:                       elem->name, attr->prefix,attr->name);
                   3015:            }
                   3016:        }
                   3017: found:     
                   3018:         attr = attr->next;
                   3019:     }
1.18      daniel   3020:     return(ret);
1.14      daniel   3021: }
                   3022: 
                   3023: /**
                   3024:  * xmlValidateRoot:
                   3025:  * @ctxt:  the validation context
                   3026:  * @doc:  a document instance
                   3027:  *
                   3028:  * Try to validate a the root element
                   3029:  * basically it does the following check as described by the
                   3030:  * XML-1.0 recommendation:
                   3031:  *  - [ VC: Root Element Type ]
                   3032:  * it doesn't try to recurse or apply other check to the element
                   3033:  *
                   3034:  * returns 1 if valid or 0 otherwise
                   3035:  */
                   3036: 
                   3037: int
                   3038: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
1.39      daniel   3039:     xmlNodePtr root;
1.14      daniel   3040:     if (doc == NULL) return(0);
                   3041: 
                   3042:     if ((doc->intSubset == NULL) ||
                   3043:        (doc->intSubset->name == NULL)) {
                   3044:        VERROR(ctxt->userData, "Not valid: no DtD found\n");
                   3045:         return(0);
                   3046:     }
1.39      daniel   3047:     root = xmlDocGetRootElement(doc);
                   3048:     if ((root == NULL) || (root->name == NULL)) {
1.14      daniel   3049:        VERROR(ctxt->userData, "Not valid: no root element\n");
                   3050:         return(0);
                   3051:     }
1.39      daniel   3052:     if (xmlStrcmp(doc->intSubset->name, root->name)) {
1.45      daniel   3053:        if ((xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) ||
                   3054:            (xmlStrcmp(root->name, BAD_CAST "html"))) {
                   3055:            VERROR(ctxt->userData,
                   3056:                   "Not valid: root and DtD name do not match '%s' and '%s'\n",
                   3057:                   root->name, doc->intSubset->name);
                   3058:            return(0);
                   3059:        }
1.14      daniel   3060:     }
                   3061:     return(1);
                   3062: }
                   3063: 
                   3064: 
                   3065: /**
                   3066:  * xmlValidateElement:
                   3067:  * @ctxt:  the validation context
                   3068:  * @doc:  a document instance
                   3069:  * @elem:  an element instance
                   3070:  *
                   3071:  * Try to validate the subtree under an element 
                   3072:  *
                   3073:  * returns 1 if valid or 0 otherwise
                   3074:  */
                   3075: 
                   3076: int
1.18      daniel   3077: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
1.27      daniel   3078:     xmlNodePtr child;
                   3079:     xmlAttrPtr attr;
1.31      daniel   3080:     xmlChar *value;
1.27      daniel   3081:     int ret = 1;
                   3082: 
                   3083:     if (elem == NULL) return(0);
1.14      daniel   3084:     CHECK_DTD;
                   3085: 
1.27      daniel   3086:     ret &= xmlValidateOneElement(ctxt, doc, elem);
                   3087:     attr = elem->properties;
                   3088:     while(attr != NULL) {
1.46    ! daniel   3089:         value = xmlNodeListGetString(doc, attr->children, 0);
1.27      daniel   3090:        ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
                   3091:        if (value != NULL)
1.39      daniel   3092:            xmlFree(value);
1.27      daniel   3093:        attr= attr->next;
                   3094:     }
1.46    ! daniel   3095:     child = elem->children;
1.27      daniel   3096:     while (child != NULL) {
                   3097:         ret &= xmlValidateElement(ctxt, doc, child);
                   3098:         child = child->next;
                   3099:     }
                   3100: 
                   3101:     return(ret);
1.14      daniel   3102: }
                   3103: 
                   3104: /**
1.28      daniel   3105:  * xmlValidateDocumentFinal:
                   3106:  * @ctxt:  the validation context
                   3107:  * @doc:  a document instance
                   3108:  *
                   3109:  * Does the final step for the document validation once all the
                   3110:  * incremental validation steps have been completed
                   3111:  *
                   3112:  * basically it does the following checks described by the XML Rec
                   3113:  * 
                   3114:  *
                   3115:  * returns 1 if valid or 0 otherwise
                   3116:  */
                   3117: 
                   3118: int
                   3119: xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
                   3120:     int ret = 1, i;
                   3121:     xmlRefTablePtr table;
                   3122:     xmlAttrPtr id;
                   3123: 
                   3124:     if (doc == NULL) {
                   3125:         fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
                   3126:        return(0);
                   3127:     }
                   3128: 
                   3129:     /*
                   3130:      * Get the refs table
                   3131:      */
                   3132:     table = doc->refs;
                   3133:     if (table != NULL) {
                   3134:         for (i = 0; i < table->nb_refs; i++) {
                   3135:            id = xmlGetID(doc, table->table[i]->value);
                   3136:            if (id == NULL) {
                   3137:                VERROR(ctxt->userData, 
                   3138:                       "IDREF attribute %s reference an unknown ID '%s'\n",
                   3139:                       table->table[i]->attr->name, table->table[i]->value);
                   3140:                ret = 0;
                   3141:            }
                   3142:        }
                   3143:     }
                   3144:     return(ret);
                   3145: }
                   3146: 
                   3147: /**
1.14      daniel   3148:  * xmlValidateDtd:
                   3149:  * @ctxt:  the validation context
                   3150:  * @doc:  a document instance
                   3151:  * @dtd:  a dtd instance
                   3152:  *
1.39      daniel   3153:  * Try to validate the document against the dtd instance
1.14      daniel   3154:  *
                   3155:  * basically it does check all the definitions in the DtD.
                   3156:  *
                   3157:  * returns 1 if valid or 0 otherwise
                   3158:  */
                   3159: 
                   3160: int
                   3161: xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
1.39      daniel   3162:     int ret;
                   3163:     xmlDtdPtr oldExt;
                   3164:     xmlNodePtr root;
                   3165: 
                   3166:     if (dtd == NULL) return(0);
                   3167:     if (doc == NULL) return(0);
                   3168:     oldExt = doc->extSubset;
                   3169:     doc->extSubset = dtd;
                   3170:     ret = xmlValidateRoot(ctxt, doc);
                   3171:     if (ret == 0) {
                   3172:        doc->extSubset = oldExt;
                   3173:        return(ret);
                   3174:     }
                   3175:     root = xmlDocGetRootElement(doc);
                   3176:     ret = xmlValidateElement(ctxt, doc, root);
                   3177:     ret &= xmlValidateDocumentFinal(ctxt, doc);
                   3178:     doc->extSubset = oldExt;
                   3179:     return(ret);
1.14      daniel   3180: }
                   3181: 
                   3182: /**
                   3183:  * xmlValidateDocument:
                   3184:  * @ctxt:  the validation context
                   3185:  * @doc:  a document instance
                   3186:  *
                   3187:  * Try to validate the document instance
                   3188:  *
1.27      daniel   3189:  * basically it does the all the checks described by the XML Rec
1.14      daniel   3190:  * i.e. validates the internal and external subset (if present)
                   3191:  * and validate the document tree.
                   3192:  *
                   3193:  * returns 1 if valid or 0 otherwise
                   3194:  */
                   3195: 
                   3196: int
                   3197: xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
1.27      daniel   3198:     int ret;
1.39      daniel   3199:     xmlNodePtr root;
                   3200: 
                   3201:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
                   3202:        return(0);
                   3203:     if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
                   3204:        (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
                   3205:         doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
                   3206:                                     doc->intSubset->SystemID);
                   3207:         if (doc->extSubset == NULL) {
                   3208:            if (doc->intSubset->SystemID != NULL) {
                   3209:                VERROR(ctxt->userData, 
                   3210:                       "Could not load the external subset '%s'\n",
                   3211:                       doc->intSubset->SystemID);
                   3212:            } else {
                   3213:                VERROR(ctxt->userData, 
                   3214:                       "Could not load the external subset '%s'\n",
                   3215:                       doc->intSubset->ExternalID);
                   3216:            }
                   3217:            return(0);
                   3218:        }
                   3219:     }
1.27      daniel   3220: 
1.14      daniel   3221:     if (!xmlValidateRoot(ctxt, doc)) return(0);
                   3222: 
1.39      daniel   3223:     root = xmlDocGetRootElement(doc);
                   3224:     ret = xmlValidateElement(ctxt, doc, root);
1.28      daniel   3225:     ret &= xmlValidateDocumentFinal(ctxt, doc);
                   3226:     return(ret);
1.14      daniel   3227: }
                   3228: 
1.33      daniel   3229: 
                   3230: /************************************************************************
                   3231:  *                                                                     *
                   3232:  *             Routines for dynamic validation editing                 *
                   3233:  *                                                                     *
                   3234:  ************************************************************************/
                   3235: 
                   3236: /**
1.34      daniel   3237:  * xmlValidGetPotentialChildren:
                   3238:  * @ctree:  an element content tree
                   3239:  * @list:  an array to store the list of child names
                   3240:  * @len:  a pointer to the number of element in the list
                   3241:  * @max:  the size of the array
1.33      daniel   3242:  *
1.34      daniel   3243:  * Build/extend a list of  potential children allowed by the content tree
1.33      daniel   3244:  *
1.34      daniel   3245:  * returns the number of element in the list, or -1 in case of error.
1.33      daniel   3246:  */
                   3247: 
1.34      daniel   3248: int
                   3249: xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
                   3250:                              int *len, int max) {
                   3251:     int i;
                   3252: 
                   3253:     if ((ctree == NULL) || (list == NULL) || (len == NULL))
                   3254:         return(-1);
                   3255:     if (*len >= max) return(*len);
                   3256: 
                   3257:     switch (ctree->type) {
                   3258:        case XML_ELEMENT_CONTENT_PCDATA: 
                   3259:            for (i = 0; i < *len;i++)
1.37      daniel   3260:                if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
                   3261:            list[(*len)++] = BAD_CAST "#PCDATA";
1.34      daniel   3262:            break;
                   3263:        case XML_ELEMENT_CONTENT_ELEMENT: 
                   3264:            for (i = 0; i < *len;i++)
                   3265:                if (!xmlStrcmp(ctree->name, list[i])) return(*len);
                   3266:            list[(*len)++] = ctree->name;
                   3267:            break;
                   3268:        case XML_ELEMENT_CONTENT_SEQ: 
                   3269:            xmlValidGetPotentialChildren(ctree->c1, list, len, max);
                   3270:            xmlValidGetPotentialChildren(ctree->c2, list, len, max);
                   3271:            break;
                   3272:        case XML_ELEMENT_CONTENT_OR:
                   3273:            xmlValidGetPotentialChildren(ctree->c1, list, len, max);
                   3274:            xmlValidGetPotentialChildren(ctree->c2, list, len, max);
                   3275:            break;
                   3276:    }
                   3277:    
                   3278:    return(*len);
1.33      daniel   3279: }
                   3280: 
                   3281: /**
1.34      daniel   3282:  * xmlValidGetValidElements:
                   3283:  * @prev:  an element to insert after
                   3284:  * @next:  an element to insert next
                   3285:  * @list:  an array to store the list of child names
                   3286:  * @max:  the size of the array
1.33      daniel   3287:  *
1.34      daniel   3288:  * This function returns the list of authorized children to insert
                   3289:  * within an existing tree while respecting the validity constraints
                   3290:  * forced by the Dtd. The insertion point is defined using @prev and
                   3291:  * @next in the following ways:
                   3292:  *  to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
                   3293:  *  to insert next 'node': xmlValidGetValidElements(node, node->next, ...
                   3294:  *  to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
                   3295:  *  to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
                   3296:  *  to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
1.33      daniel   3297:  *
1.34      daniel   3298:  * pointers to the element names are inserted at the beginning of the array
                   3299:  * and do not need to be freed.
                   3300:  *
                   3301:  * returns the number of element in the list, or -1 in case of error. If
                   3302:  *    the function returns the value @max the caller is invited to grow the
                   3303:  *    receiving array and retry.
1.33      daniel   3304:  */
                   3305: 
1.34      daniel   3306: int
                   3307: xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
                   3308:                          int max) {
                   3309:     int nb_valid_elements = 0;
                   3310:     const xmlChar *elements[256];
                   3311:     int nb_elements = 0, i;
                   3312:     
                   3313:     xmlNode *ref_node;
                   3314:     xmlNode *parent;
                   3315:     xmlNode *test_node;
                   3316:     
                   3317:     xmlNode *prev_next;
                   3318:     xmlNode *next_prev;
                   3319:     xmlNode *parent_childs;
                   3320:     xmlNode *parent_last;
                   3321:     
                   3322:     xmlElement *element_desc;
                   3323: 
                   3324:     if (prev == NULL && next == NULL)
                   3325:         return(-1);
                   3326: 
                   3327:     if (list == NULL) return(-1);
                   3328:     if (max <= 0) return(-1);
                   3329: 
                   3330:     nb_valid_elements = 0;
                   3331:     ref_node = prev ? prev : next;
                   3332:     parent = ref_node->parent;
                   3333: 
                   3334:     /*
                   3335:      * Retrieves the parent element declaration
                   3336:      */
                   3337:     element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
                   3338:                                          parent->name);
                   3339:     if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
                   3340:         element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
                   3341:                                              parent->name);
                   3342:     if (element_desc == NULL) return(-1);
                   3343:        
                   3344:     /*
                   3345:      * Do a backup of the current tree structure
                   3346:      */
                   3347:     prev_next = prev ? prev->next : NULL;
                   3348:     next_prev = next ? next->prev : NULL;
1.46    ! daniel   3349:     parent_childs = parent->children;
1.34      daniel   3350:     parent_last = parent->last;
                   3351: 
                   3352:     /*
                   3353:      * Creates a dummy node and insert it into the tree
                   3354:      */    
1.37      daniel   3355:     test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
1.34      daniel   3356:     test_node->doc = ref_node->doc;
                   3357:     test_node->parent = parent;
                   3358:     test_node->prev = prev;
                   3359:     test_node->next = next;
                   3360:     
                   3361:     if (prev) prev->next = test_node;
1.46    ! daniel   3362:     else parent->children = test_node;
1.34      daniel   3363:                
                   3364:     if (next) next->prev = test_node;
                   3365:     else parent->last = test_node;
                   3366: 
                   3367:     /*
                   3368:      * Insert each potential child node and check if the parent is
                   3369:      * still valid
                   3370:      */
                   3371:     nb_elements = xmlValidGetPotentialChildren(element_desc->content,
                   3372:                       elements, &nb_elements, 256);
                   3373:     
                   3374:     for (i = 0;i < nb_elements;i++) {
                   3375:        test_node->name = elements[i];
                   3376:        if (xmlValidateOneElement(NULL, parent->doc, parent)) {
                   3377:            int j;
                   3378: 
                   3379:            for (j = 0; j < nb_valid_elements;j++)
                   3380:                if (!xmlStrcmp(elements[i], list[j])) break;
                   3381:            list[nb_valid_elements++] = elements[i];
                   3382:            if (nb_valid_elements >= max) break;
                   3383:        }
1.33      daniel   3384:     }
                   3385: 
1.34      daniel   3386:     /*
                   3387:      * Restore the tree structure
                   3388:      */
                   3389:     if (prev) prev->next = prev_next;
                   3390:     if (next) next->prev = next_prev;
1.46    ! daniel   3391:     parent->children = parent_childs;
1.34      daniel   3392:     parent->last = parent_last;
                   3393:     
                   3394:     return(nb_valid_elements);
1.33      daniel   3395: }

Webmaster