Annotation of XML/valid.c, revision 1.39

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

Webmaster