Annotation of XML/valid.c, revision 1.36

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.4       daniel    763:     int i;
                    764: 
                    765:     if (dtd == NULL) {
                    766:         fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
                    767:        return(NULL);
                    768:     }
                    769:     if (name == NULL) {
                    770:         fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
                    771:        return(NULL);
                    772:     }
                    773:     if (elem == NULL) {
                    774:         fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
                    775:        return(NULL);
                    776:     }
1.23      daniel    777:     /*
                    778:      * Check the type and possibly the default value.
                    779:      */
1.4       daniel    780:     switch (type) {
                    781:         case XML_ATTRIBUTE_CDATA:
                    782:            break;
                    783:         case XML_ATTRIBUTE_ID:
                    784:            break;
                    785:         case XML_ATTRIBUTE_IDREF:
                    786:            break;
                    787:         case XML_ATTRIBUTE_IDREFS:
                    788:            break;
                    789:         case XML_ATTRIBUTE_ENTITY:
                    790:            break;
                    791:         case XML_ATTRIBUTE_ENTITIES:
                    792:            break;
                    793:         case XML_ATTRIBUTE_NMTOKEN:
                    794:            break;
                    795:         case XML_ATTRIBUTE_NMTOKENS:
                    796:            break;
                    797:         case XML_ATTRIBUTE_ENUMERATION:
                    798:            break;
                    799:         case XML_ATTRIBUTE_NOTATION:
                    800:            break;
                    801:        default:
                    802:            fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
                    803:            return(NULL);
                    804:     }
1.23      daniel    805:     if ((defaultValue != NULL) && 
                    806:         (!xmlValidateAttributeValue(type, defaultValue))) {
                    807:        VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
                    808:               elem, name, defaultValue);
                    809:        defaultValue = NULL;
                    810:     }
1.4       daniel    811: 
                    812:     /*
                    813:      * Create the Attribute table if needed.
                    814:      */
                    815:     table = dtd->attributes;
                    816:     if (table == NULL) 
                    817:         table = dtd->attributes = xmlCreateAttributeTable();
                    818:     if (table == NULL) {
                    819:        fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
                    820:         return(NULL);
                    821:     }
                    822: 
                    823:     /*
                    824:      * Validity Check:
                    825:      * Search the DTD for previous declarations of the ATTLIST
                    826:      */
                    827:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel    828:         cur = table->table[i];
1.4       daniel    829:        if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
                    830:            /*
                    831:             * The attribute is already defined in this Dtd.
                    832:             */
1.23      daniel    833:            VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
                    834:                   elem, name);
1.4       daniel    835:        }
                    836:     }
                    837: 
                    838:     /*
                    839:      * Grow the table, if needed.
                    840:      */
                    841:     if (table->nb_attributes >= table->max_attributes) {
                    842:         /*
                    843:         * need more attributes.
                    844:         */
                    845:        table->max_attributes *= 2;
1.15      daniel    846:        table->table = (xmlAttributePtr *) 
1.26      daniel    847:            xmlRealloc(table->table, table->max_attributes * 
1.15      daniel    848:                    sizeof(xmlAttributePtr));
1.13      daniel    849:        if (table->table == NULL) {
1.4       daniel    850:            fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
                    851:            return(NULL);
                    852:        }
                    853:     }
1.26      daniel    854:     ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15      daniel    855:     if (ret == NULL) {
                    856:        fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
                    857:        return(NULL);
                    858:     }
                    859:     table->table[table->nb_attributes] = ret;
1.4       daniel    860: 
                    861:     /*
                    862:      * fill the structure.
                    863:      */
                    864:     ret->type = type;
                    865:     ret->name = xmlStrdup(name);
                    866:     ret->elem = xmlStrdup(elem);
                    867:     ret->def = def;
                    868:     ret->tree = tree;
                    869:     if (defaultValue != NULL)
                    870:        ret->defaultValue = xmlStrdup(defaultValue);
                    871:     else
                    872:         ret->defaultValue = NULL;
1.15      daniel    873:     elemDef = xmlGetDtdElementDesc(dtd, elem);
                    874:     if (elemDef != NULL) {
1.16      daniel    875:         if ((type == XML_ATTRIBUTE_ID) &&
                    876:            (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
                    877:            VERROR(ctxt->userData, 
                    878:           "Element %s has too may ID attributes defined : %s\n",
                    879:                   elem, name);
1.15      daniel    880:         ret->next = elemDef->attributes;
                    881:         elemDef->attributes = ret;
                    882:     }
1.4       daniel    883:     table->nb_attributes++;
                    884: 
                    885:     return(ret);
                    886: }
                    887: 
                    888: /**
                    889:  * xmlFreeAttribute:
                    890:  * @elem:  An attribute
                    891:  *
                    892:  * Deallocate the memory used by an attribute definition
                    893:  */
                    894: void
                    895: xmlFreeAttribute(xmlAttributePtr attr) {
                    896:     if (attr == NULL) return;
                    897:     if (attr->tree != NULL)
                    898:         xmlFreeEnumeration(attr->tree);
                    899:     if (attr->elem != NULL)
1.31      daniel    900:        xmlFree((xmlChar *) attr->elem);
1.4       daniel    901:     if (attr->name != NULL)
1.31      daniel    902:        xmlFree((xmlChar *) attr->name);
1.4       daniel    903:     if (attr->defaultValue != NULL)
1.31      daniel    904:        xmlFree((xmlChar *) attr->defaultValue);
1.4       daniel    905:     memset(attr, -1, sizeof(xmlAttribute));
1.26      daniel    906:     xmlFree(attr);
1.4       daniel    907: }
                    908: 
                    909: /**
                    910:  * xmlFreeAttributeTable:
                    911:  * @table:  An attribute table
                    912:  *
                    913:  * Deallocate the memory used by an entities hash table.
                    914:  */
                    915: void
                    916: xmlFreeAttributeTable(xmlAttributeTablePtr table) {
                    917:     int i;
                    918: 
                    919:     if (table == NULL) return;
                    920: 
                    921:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel    922:         xmlFreeAttribute(table->table[i]);
1.4       daniel    923:     }
1.26      daniel    924:     xmlFree(table->table);
                    925:     xmlFree(table);
1.4       daniel    926: }
                    927: 
                    928: /**
                    929:  * xmlCopyAttributeTable:
                    930:  * @table:  An attribute table
                    931:  *
                    932:  * Build a copy of an attribute table.
                    933:  * 
1.6       daniel    934:  * Returns the new xmlAttributeTablePtr or NULL in case of error.
1.4       daniel    935:  */
                    936: xmlAttributeTablePtr
                    937: xmlCopyAttributeTable(xmlAttributeTablePtr table) {
                    938:     xmlAttributeTablePtr ret;
                    939:     xmlAttributePtr cur, attr;
                    940:     int i;
                    941: 
1.26      daniel    942:     ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
1.4       daniel    943:     if (ret == NULL) {
                    944:         fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
                    945:        return(NULL);
                    946:     }
1.26      daniel    947:     ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
1.15      daniel    948:                                           sizeof(xmlAttributePtr));
1.4       daniel    949:     if (ret->table == NULL) {
                    950:         fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26      daniel    951:        xmlFree(ret);
1.4       daniel    952:        return(NULL);
                    953:     }
                    954:     ret->max_attributes = table->max_attributes;
                    955:     ret->nb_attributes = table->nb_attributes;
                    956:     for (i = 0;i < ret->nb_attributes;i++) {
1.15      daniel    957:        attr = table->table[i];
1.26      daniel    958:        cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15      daniel    959:        if (cur == NULL) {
                    960:            fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26      daniel    961:            xmlFree(ret);
                    962:            xmlFree(ret->table);
1.15      daniel    963:            return(NULL);
                    964:        }
                    965:        ret->table[i] = cur;
1.4       daniel    966:        cur->type = attr->type;
                    967:        cur->def = attr->def;
                    968:        cur->tree = xmlCopyEnumeration(attr->tree);
                    969:        if (attr->elem != NULL)
                    970:            cur->elem = xmlStrdup(attr->elem);
                    971:        else
                    972:            cur->elem = NULL;
                    973:        if (attr->name != NULL)
                    974:            cur->name = xmlStrdup(attr->name);
                    975:        else
                    976:            cur->name = NULL;
                    977:        if (attr->defaultValue != NULL)
                    978:            cur->defaultValue = xmlStrdup(attr->defaultValue);
                    979:        else
                    980:            cur->defaultValue = NULL;
1.15      daniel    981:        /* NEED to rebuild the next chain !!!!!! */
1.4       daniel    982:     }
                    983:     return(ret);
                    984: }
                    985: 
                    986: /**
                    987:  * xmlDumpAttributeTable:
1.9       daniel    988:  * @buf:  the XML buffer output
1.4       daniel    989:  * @table:  An attribute table
                    990:  *
                    991:  * This will dump the content of the attribute table as an XML DTD definition
                    992:  */
                    993: void
1.8       daniel    994: xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1.4       daniel    995:     int i;
                    996:     xmlAttributePtr cur;
                    997: 
                    998:     if (table == NULL) return;
                    999: 
                   1000:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel   1001:         cur = table->table[i];
1.8       daniel   1002:        xmlBufferWriteChar(buf, "<!ATTLIST ");
                   1003:        xmlBufferWriteCHAR(buf, cur->elem);
                   1004:        xmlBufferWriteChar(buf, " ");
                   1005:        xmlBufferWriteCHAR(buf, cur->name);
1.4       daniel   1006:         switch (cur->type) {
                   1007:             case XML_ATTRIBUTE_CDATA:
1.8       daniel   1008:                xmlBufferWriteChar(buf, " CDATA");
1.4       daniel   1009:                 break;
                   1010:             case XML_ATTRIBUTE_ID:
1.8       daniel   1011:                xmlBufferWriteChar(buf, " ID");
1.4       daniel   1012:                 break;
                   1013:             case XML_ATTRIBUTE_IDREF:
1.8       daniel   1014:                xmlBufferWriteChar(buf, " IDREF");
1.4       daniel   1015:                 break;
                   1016:             case XML_ATTRIBUTE_IDREFS:
1.8       daniel   1017:                xmlBufferWriteChar(buf, " IDREFS");
1.4       daniel   1018:                 break;
                   1019:             case XML_ATTRIBUTE_ENTITY:
1.8       daniel   1020:                xmlBufferWriteChar(buf, " ENTITY");
1.4       daniel   1021:                 break;
                   1022:             case XML_ATTRIBUTE_ENTITIES:
1.8       daniel   1023:                xmlBufferWriteChar(buf, " ENTITIES");
1.4       daniel   1024:                 break;
                   1025:             case XML_ATTRIBUTE_NMTOKEN:
1.8       daniel   1026:                xmlBufferWriteChar(buf, " NMTOKEN");
1.4       daniel   1027:                 break;
                   1028:             case XML_ATTRIBUTE_NMTOKENS:
1.8       daniel   1029:                xmlBufferWriteChar(buf, " NMTOKENS");
1.4       daniel   1030:                 break;
                   1031:             case XML_ATTRIBUTE_ENUMERATION:
1.18      daniel   1032:                 xmlBufferWriteChar(buf, " (");
                   1033:                xmlDumpEnumeration(buf, cur->tree);
1.4       daniel   1034:                 break;
                   1035:             case XML_ATTRIBUTE_NOTATION:
1.18      daniel   1036:                 xmlBufferWriteChar(buf, " NOTATION (");
                   1037:                xmlDumpEnumeration(buf, cur->tree);
1.4       daniel   1038:                 break;
                   1039:            default:
                   1040:                fprintf(stderr,
                   1041:                    "xmlDumpAttributeTable: internal: unknown type %d\n",
                   1042:                        cur->type);
                   1043:        }
                   1044:         switch (cur->def) {
                   1045:             case XML_ATTRIBUTE_NONE:
                   1046:                 break;
                   1047:             case XML_ATTRIBUTE_REQUIRED:
1.8       daniel   1048:                xmlBufferWriteChar(buf, " #REQUIRED");
1.4       daniel   1049:                 break;
                   1050:             case XML_ATTRIBUTE_IMPLIED:
1.8       daniel   1051:                xmlBufferWriteChar(buf, " #IMPLIED");
1.4       daniel   1052:                 break;
                   1053:             case XML_ATTRIBUTE_FIXED:
1.17      daniel   1054:                xmlBufferWriteChar(buf, " #FIXED");
1.4       daniel   1055:                 break;
                   1056:            default:
                   1057:                fprintf(stderr,
                   1058:                    "xmlDumpAttributeTable: internal: unknown default %d\n",
                   1059:                        cur->def);
                   1060:         }
1.17      daniel   1061:        if (cur->defaultValue != NULL) {
                   1062:            xmlBufferWriteChar(buf, " ");
                   1063:            xmlBufferWriteQuotedString(buf, cur->defaultValue);
                   1064:        }
1.8       daniel   1065:         xmlBufferWriteChar(buf, ">\n");
1.5       daniel   1066:     }
                   1067: }
                   1068: 
                   1069: /************************************************************************
                   1070:  *                                                                     *
                   1071:  *                             NOTATIONs                               *
                   1072:  *                                                                     *
                   1073:  ************************************************************************/
                   1074: /**
                   1075:  * xmlCreateNotationTable:
                   1076:  *
                   1077:  * create and initialize an empty notation hash table.
                   1078:  *
1.6       daniel   1079:  * Returns the xmlNotationTablePtr just created or NULL in case
1.5       daniel   1080:  *                of error.
                   1081:  */
                   1082: xmlNotationTablePtr
                   1083: xmlCreateNotationTable(void) {
                   1084:     xmlNotationTablePtr ret;
                   1085: 
                   1086:     ret = (xmlNotationTablePtr) 
1.26      daniel   1087:          xmlMalloc(sizeof(xmlNotationTable));
1.5       daniel   1088:     if (ret == NULL) {
1.26      daniel   1089:         fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12      daniel   1090:                (long)sizeof(xmlNotationTable));
1.5       daniel   1091:         return(NULL);
                   1092:     }
                   1093:     ret->max_notations = XML_MIN_NOTATION_TABLE;
                   1094:     ret->nb_notations = 0;
1.15      daniel   1095:     ret->table = (xmlNotationPtr *) 
1.26      daniel   1096:          xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
1.5       daniel   1097:     if (ret == NULL) {
1.26      daniel   1098:         fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12      daniel   1099:                ret->max_notations * (long)sizeof(xmlNotation));
1.26      daniel   1100:        xmlFree(ret);
1.5       daniel   1101:         return(NULL);
                   1102:     }
                   1103:     return(ret);
                   1104: }
                   1105: 
                   1106: 
                   1107: /**
                   1108:  * xmlAddNotationDecl:
1.6       daniel   1109:  * @dtd:  pointer to the DTD
1.16      daniel   1110:  * @ctxt:  the validation context
1.5       daniel   1111:  * @name:  the entity name
1.6       daniel   1112:  * @PublicID:  the public identifier or NULL
                   1113:  * @SystemID:  the system identifier or NULL
1.5       daniel   1114:  *
                   1115:  * Register a new notation declaration
                   1116:  *
1.6       daniel   1117:  * Returns NULL if not, othervise the entity
1.5       daniel   1118:  */
                   1119: xmlNotationPtr
1.31      daniel   1120: xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
                   1121:                    const xmlChar *PublicID, const xmlChar *SystemID) {
1.5       daniel   1122:     xmlNotationPtr ret, cur;
                   1123:     xmlNotationTablePtr table;
                   1124:     int i;
                   1125: 
                   1126:     if (dtd == NULL) {
                   1127:         fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
                   1128:        return(NULL);
                   1129:     }
                   1130:     if (name == NULL) {
                   1131:         fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
                   1132:        return(NULL);
                   1133:     }
                   1134:     if ((PublicID == NULL) && (SystemID == NULL)) {
                   1135:         fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
                   1136:     }
                   1137: 
                   1138:     /*
                   1139:      * Create the Notation table if needed.
                   1140:      */
                   1141:     table = dtd->notations;
                   1142:     if (table == NULL) 
                   1143:         table = dtd->notations = xmlCreateNotationTable();
                   1144:     if (table == NULL) {
                   1145:        fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
                   1146:         return(NULL);
                   1147:     }
                   1148: 
                   1149:     /*
                   1150:      * Validity Check:
                   1151:      * Search the DTD for previous declarations of the ATTLIST
                   1152:      */
                   1153:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1154:         cur = table->table[i];
1.5       daniel   1155:        if (!xmlStrcmp(cur->name, name)) {
                   1156:            /*
                   1157:             * The notation is already defined in this Dtd.
                   1158:             */
                   1159:            fprintf(stderr,
                   1160:                    "xmlAddNotationDecl: %s already defined\n", name);
                   1161:        }
                   1162:     }
                   1163: 
                   1164:     /*
                   1165:      * Grow the table, if needed.
                   1166:      */
                   1167:     if (table->nb_notations >= table->max_notations) {
                   1168:         /*
                   1169:         * need more notations.
                   1170:         */
                   1171:        table->max_notations *= 2;
1.15      daniel   1172:        table->table = (xmlNotationPtr *) 
1.26      daniel   1173:            xmlRealloc(table->table, table->max_notations *
1.15      daniel   1174:                    sizeof(xmlNotationPtr));
1.13      daniel   1175:        if (table->table == NULL) {
1.5       daniel   1176:            fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
                   1177:            return(NULL);
                   1178:        }
                   1179:     }
1.26      daniel   1180:     ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15      daniel   1181:     if (ret == NULL) {
                   1182:        fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
                   1183:        return(NULL);
                   1184:     }
                   1185:     table->table[table->nb_notations] = ret;
1.5       daniel   1186: 
                   1187:     /*
                   1188:      * fill the structure.
                   1189:      */
                   1190:     ret->name = xmlStrdup(name);
                   1191:     if (SystemID != NULL)
                   1192:         ret->SystemID = xmlStrdup(SystemID);
                   1193:     else
                   1194:         ret->SystemID = NULL;
                   1195:     if (PublicID != NULL)
                   1196:         ret->PublicID = xmlStrdup(PublicID);
                   1197:     else
                   1198:         ret->PublicID = NULL;
                   1199:     table->nb_notations++;
                   1200: 
                   1201:     return(ret);
                   1202: }
                   1203: 
                   1204: /**
                   1205:  * xmlFreeNotation:
                   1206:  * @not:  A notation
                   1207:  *
                   1208:  * Deallocate the memory used by an notation definition
                   1209:  */
                   1210: void
                   1211: xmlFreeNotation(xmlNotationPtr nota) {
                   1212:     if (nota == NULL) return;
                   1213:     if (nota->name != NULL)
1.31      daniel   1214:        xmlFree((xmlChar *) nota->name);
1.5       daniel   1215:     if (nota->PublicID != NULL)
1.31      daniel   1216:        xmlFree((xmlChar *) nota->PublicID);
1.5       daniel   1217:     if (nota->SystemID != NULL)
1.31      daniel   1218:        xmlFree((xmlChar *) nota->SystemID);
1.5       daniel   1219:     memset(nota, -1, sizeof(xmlNotation));
1.26      daniel   1220:     xmlFree(nota);
1.5       daniel   1221: }
                   1222: 
                   1223: /**
                   1224:  * xmlFreeNotationTable:
                   1225:  * @table:  An notation table
                   1226:  *
                   1227:  * Deallocate the memory used by an entities hash table.
                   1228:  */
                   1229: void
                   1230: xmlFreeNotationTable(xmlNotationTablePtr table) {
                   1231:     int i;
                   1232: 
                   1233:     if (table == NULL) return;
                   1234: 
                   1235:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1236:         xmlFreeNotation(table->table[i]);
1.5       daniel   1237:     }
1.26      daniel   1238:     xmlFree(table->table);
                   1239:     xmlFree(table);
1.5       daniel   1240: }
                   1241: 
                   1242: /**
                   1243:  * xmlCopyNotationTable:
                   1244:  * @table:  A notation table
                   1245:  *
                   1246:  * Build a copy of a notation table.
                   1247:  * 
1.6       daniel   1248:  * Returns the new xmlNotationTablePtr or NULL in case of error.
1.5       daniel   1249:  */
                   1250: xmlNotationTablePtr
                   1251: xmlCopyNotationTable(xmlNotationTablePtr table) {
                   1252:     xmlNotationTablePtr ret;
                   1253:     xmlNotationPtr cur, nota;
                   1254:     int i;
                   1255: 
1.26      daniel   1256:     ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
1.5       daniel   1257:     if (ret == NULL) {
                   1258:         fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
                   1259:        return(NULL);
                   1260:     }
1.26      daniel   1261:     ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
1.15      daniel   1262:                                          sizeof(xmlNotationPtr));
1.5       daniel   1263:     if (ret->table == NULL) {
                   1264:         fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26      daniel   1265:        xmlFree(ret);
1.5       daniel   1266:        return(NULL);
                   1267:     }
                   1268:     ret->max_notations = table->max_notations;
                   1269:     ret->nb_notations = table->nb_notations;
                   1270:     for (i = 0;i < ret->nb_notations;i++) {
1.26      daniel   1271:        cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15      daniel   1272:        if (cur == NULL) {
                   1273:            fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26      daniel   1274:            xmlFree(ret);
                   1275:            xmlFree(ret->table);
1.15      daniel   1276:            return(NULL);
                   1277:        }
                   1278:        ret->table[i] = cur;
                   1279:        nota = table->table[i];
1.5       daniel   1280:        if (nota->name != NULL)
                   1281:            cur->name = xmlStrdup(nota->name);
                   1282:        else
                   1283:            cur->name = NULL;
                   1284:        if (nota->PublicID != NULL)
                   1285:            cur->PublicID = xmlStrdup(nota->PublicID);
                   1286:        else
                   1287:            cur->PublicID = NULL;
                   1288:        if (nota->SystemID != NULL)
                   1289:            cur->SystemID = xmlStrdup(nota->SystemID);
                   1290:        else
                   1291:            cur->SystemID = NULL;
                   1292:     }
                   1293:     return(ret);
                   1294: }
                   1295: 
                   1296: /**
                   1297:  * xmlDumpNotationTable:
1.9       daniel   1298:  * @buf:  the XML buffer output
1.5       daniel   1299:  * @table:  A notation table
                   1300:  *
                   1301:  * This will dump the content of the notation table as an XML DTD definition
                   1302:  */
                   1303: void
1.8       daniel   1304: xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
1.5       daniel   1305:     int i;
                   1306:     xmlNotationPtr cur;
                   1307: 
                   1308:     if (table == NULL) return;
                   1309: 
                   1310:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1311:         cur = table->table[i];
1.8       daniel   1312:        xmlBufferWriteChar(buf, "<!NOTATION ");
                   1313:        xmlBufferWriteCHAR(buf, cur->name);
1.5       daniel   1314:        if (cur->PublicID != NULL) {
1.10      daniel   1315:            xmlBufferWriteChar(buf, " PUBLIC ");
                   1316:            xmlBufferWriteQuotedString(buf, cur->PublicID);
1.5       daniel   1317:            if (cur->SystemID != NULL) {
1.8       daniel   1318:                xmlBufferWriteChar(buf, " ");
                   1319:                xmlBufferWriteCHAR(buf, cur->SystemID);
1.5       daniel   1320:            }
                   1321:        } else {
1.8       daniel   1322:            xmlBufferWriteChar(buf, " SYSTEM ");
                   1323:            xmlBufferWriteCHAR(buf, cur->SystemID);
1.5       daniel   1324:        }
1.8       daniel   1325:         xmlBufferWriteChar(buf, " >\n");
1.2       daniel   1326:     }
                   1327: }
1.14      daniel   1328: 
                   1329: /************************************************************************
                   1330:  *                                                                     *
1.27      daniel   1331:  *                             IDs                                     *
1.21      daniel   1332:  *                                                                     *
                   1333:  ************************************************************************/
                   1334: /**
                   1335:  * xmlCreateIDTable:
                   1336:  *
                   1337:  * create and initialize an empty id hash table.
                   1338:  *
                   1339:  * Returns the xmlIDTablePtr just created or NULL in case
                   1340:  *                of error.
                   1341:  */
                   1342: xmlIDTablePtr
                   1343: xmlCreateIDTable(void) {
                   1344:     xmlIDTablePtr ret;
                   1345: 
                   1346:     ret = (xmlIDTablePtr) 
1.26      daniel   1347:          xmlMalloc(sizeof(xmlIDTable));
1.21      daniel   1348:     if (ret == NULL) {
1.26      daniel   1349:         fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21      daniel   1350:                (long)sizeof(xmlIDTable));
                   1351:         return(NULL);
                   1352:     }
                   1353:     ret->max_ids = XML_MIN_NOTATION_TABLE;
                   1354:     ret->nb_ids = 0;
                   1355:     ret->table = (xmlIDPtr *) 
1.26      daniel   1356:          xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
1.21      daniel   1357:     if (ret == NULL) {
1.26      daniel   1358:         fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21      daniel   1359:                ret->max_ids * (long)sizeof(xmlID));
1.26      daniel   1360:        xmlFree(ret);
1.21      daniel   1361:         return(NULL);
                   1362:     }
                   1363:     return(ret);
                   1364: }
                   1365: 
                   1366: 
                   1367: /**
                   1368:  * xmlAddID:
                   1369:  * @ctxt:  the validation context
                   1370:  * @doc:  pointer to the document
                   1371:  * @value:  the value name
                   1372:  * @attr:  the attribute holding the ID
                   1373:  *
                   1374:  * Register a new id declaration
                   1375:  *
                   1376:  * Returns NULL if not, othervise the new xmlIDPtr
                   1377:  */
                   1378: xmlIDPtr 
1.31      daniel   1379: xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
1.21      daniel   1380:          xmlAttrPtr attr) {
                   1381:     xmlIDPtr ret, cur;
                   1382:     xmlIDTablePtr table;
                   1383:     int i;
                   1384: 
                   1385:     if (doc == NULL) {
                   1386:         fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
                   1387:        return(NULL);
                   1388:     }
                   1389:     if (value == NULL) {
                   1390:         fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
                   1391:        return(NULL);
                   1392:     }
                   1393:     if (attr == NULL) {
                   1394:         fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
                   1395:        return(NULL);
                   1396:     }
                   1397: 
                   1398:     /*
                   1399:      * Create the ID table if needed.
                   1400:      */
                   1401:     table = doc->ids;
                   1402:     if (table == NULL) 
                   1403:         table = doc->ids = xmlCreateIDTable();
                   1404:     if (table == NULL) {
                   1405:        fprintf(stderr, "xmlAddID: Table creation failed!\n");
                   1406:         return(NULL);
                   1407:     }
                   1408: 
                   1409:     /*
                   1410:      * Validity Check:
                   1411:      * Search the DTD for previous declarations of the ATTLIST
                   1412:      */
                   1413:     for (i = 0;i < table->nb_ids;i++) {
                   1414:         cur = table->table[i];
                   1415:        if (!xmlStrcmp(cur->value, value)) {
                   1416:            /*
                   1417:             * The id is already defined in this Dtd.
                   1418:             */
                   1419:            VERROR(ctxt->userData, "ID %s already defined\n", value);
                   1420:            return(NULL);
                   1421:        }
                   1422:     }
                   1423: 
                   1424:     /*
                   1425:      * Grow the table, if needed.
                   1426:      */
                   1427:     if (table->nb_ids >= table->max_ids) {
                   1428:         /*
                   1429:         * need more ids.
                   1430:         */
                   1431:        table->max_ids *= 2;
                   1432:        table->table = (xmlIDPtr *) 
1.26      daniel   1433:            xmlRealloc(table->table, table->max_ids *
1.21      daniel   1434:                    sizeof(xmlIDPtr));
                   1435:        if (table->table == NULL) {
                   1436:            fprintf(stderr, "xmlAddID: out of memory\n");
                   1437:            return(NULL);
                   1438:        }
                   1439:     }
1.26      daniel   1440:     ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
1.21      daniel   1441:     if (ret == NULL) {
                   1442:        fprintf(stderr, "xmlAddID: out of memory\n");
                   1443:        return(NULL);
                   1444:     }
                   1445:     table->table[table->nb_ids] = ret;
                   1446: 
                   1447:     /*
                   1448:      * fill the structure.
                   1449:      */
                   1450:     ret->value = xmlStrdup(value);
                   1451:     ret->attr = attr;
                   1452:     table->nb_ids++;
                   1453: 
                   1454:     return(ret);
                   1455: }
                   1456: 
                   1457: /**
                   1458:  * xmlFreeID:
                   1459:  * @not:  A id
                   1460:  *
                   1461:  * Deallocate the memory used by an id definition
                   1462:  */
                   1463: void
                   1464: xmlFreeID(xmlIDPtr id) {
                   1465:     if (id == NULL) return;
                   1466:     if (id->value != NULL)
1.31      daniel   1467:        xmlFree((xmlChar *) id->value);
1.21      daniel   1468:     memset(id, -1, sizeof(xmlID));
1.26      daniel   1469:     xmlFree(id);
1.21      daniel   1470: }
                   1471: 
                   1472: /**
                   1473:  * xmlFreeIDTable:
                   1474:  * @table:  An id table
                   1475:  *
                   1476:  * Deallocate the memory used by an ID hash table.
                   1477:  */
                   1478: void
                   1479: xmlFreeIDTable(xmlIDTablePtr table) {
                   1480:     int i;
                   1481: 
                   1482:     if (table == NULL) return;
                   1483: 
                   1484:     for (i = 0;i < table->nb_ids;i++) {
                   1485:         xmlFreeID(table->table[i]);
                   1486:     }
1.26      daniel   1487:     xmlFree(table->table);
                   1488:     xmlFree(table);
1.21      daniel   1489: }
                   1490: 
                   1491: /**
                   1492:  * xmlIsID
                   1493:  * @doc:  the document
                   1494:  * @elem:  the element carrying the attribute
                   1495:  * @attr:  the attribute
                   1496:  *
                   1497:  * Determine whether an attribute is of type ID. In case we have Dtd(s)
                   1498:  * then this is simple, otherwise we use an heuristic: name ID (upper
                   1499:  * or lowercase).
                   1500:  *
                   1501:  * Returns 0 or 1 depending on the lookup result
                   1502:  */
                   1503: int
                   1504: xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
                   1505:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
                   1506:         if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
                   1507:             ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
                   1508:            (attr->name[2] == 0)) return(1);
                   1509:     } else {
                   1510:        xmlAttributePtr attrDecl;
                   1511: 
                   1512:        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   1513:        if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   1514:            attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
                   1515:                                         attr->name);
                   1516: 
1.22      daniel   1517:         if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
1.21      daniel   1518:            return(1);
                   1519:     }
                   1520:     return(0);
                   1521: }
                   1522: 
1.22      daniel   1523: /**
                   1524:  * xmlGetID:
                   1525:  * @doc:  pointer to the document
                   1526:  * @ID:  the ID value
                   1527:  *
                   1528:  * Search the attribute declaring the given ID
                   1529:  *
                   1530:  * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
                   1531:  */
                   1532: xmlAttrPtr 
1.31      daniel   1533: xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
1.22      daniel   1534:     xmlIDPtr cur;
                   1535:     xmlIDTablePtr table;
                   1536:     int i;
                   1537: 
                   1538:     if (doc == NULL) {
                   1539:         fprintf(stderr, "xmlGetID: doc == NULL\n");
                   1540:        return(NULL);
                   1541:     }
                   1542: 
                   1543:     if (ID == NULL) {
                   1544:         fprintf(stderr, "xmlGetID: ID == NULL\n");
                   1545:        return(NULL);
                   1546:     }
                   1547: 
                   1548:     table = doc->ids;
                   1549:     if (table == NULL) 
                   1550:         return(NULL);
                   1551: 
                   1552:     /*
                   1553:      * Search the ID list.
                   1554:      */
                   1555:     for (i = 0;i < table->nb_ids;i++) {
                   1556:         cur = table->table[i];
                   1557:        if (!xmlStrcmp(cur->value, ID)) {
                   1558:            return(cur->attr);
                   1559:        }
                   1560:     }
                   1561:     return(NULL);
                   1562: }
                   1563: 
1.21      daniel   1564: /************************************************************************
                   1565:  *                                                                     *
1.27      daniel   1566:  *                             Refs                                    *
                   1567:  *                                                                     *
                   1568:  ************************************************************************/
                   1569: /**
                   1570:  * xmlCreateRefTable:
                   1571:  *
                   1572:  * create and initialize an empty ref hash table.
                   1573:  *
                   1574:  * Returns the xmlRefTablePtr just created or NULL in case
                   1575:  *                of error.
                   1576:  */
                   1577: xmlRefTablePtr
                   1578: xmlCreateRefTable(void) {
                   1579:     xmlRefTablePtr ret;
                   1580: 
                   1581:     ret = (xmlRefTablePtr) 
                   1582:          xmlMalloc(sizeof(xmlRefTable));
                   1583:     if (ret == NULL) {
                   1584:         fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
                   1585:                (long)sizeof(xmlRefTable));
                   1586:         return(NULL);
                   1587:     }
                   1588:     ret->max_refs = XML_MIN_NOTATION_TABLE;
                   1589:     ret->nb_refs = 0;
                   1590:     ret->table = (xmlRefPtr *) 
                   1591:          xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
                   1592:     if (ret == NULL) {
                   1593:         fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
                   1594:                ret->max_refs * (long)sizeof(xmlRef));
                   1595:        xmlFree(ret);
                   1596:         return(NULL);
                   1597:     }
                   1598:     return(ret);
                   1599: }
                   1600: 
                   1601: 
                   1602: /**
                   1603:  * xmlAddRef:
                   1604:  * @ctxt:  the validation context
                   1605:  * @doc:  pointer to the document
                   1606:  * @value:  the value name
                   1607:  * @attr:  the attribute holding the Ref
                   1608:  *
                   1609:  * Register a new ref declaration
                   1610:  *
                   1611:  * Returns NULL if not, othervise the new xmlRefPtr
                   1612:  */
                   1613: xmlRefPtr 
1.31      daniel   1614: xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
1.27      daniel   1615:          xmlAttrPtr attr) {
1.28      daniel   1616:     xmlRefPtr ret;
1.27      daniel   1617:     xmlRefTablePtr table;
                   1618: 
                   1619:     if (doc == NULL) {
                   1620:         fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
                   1621:        return(NULL);
                   1622:     }
                   1623:     if (value == NULL) {
                   1624:         fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
                   1625:        return(NULL);
                   1626:     }
                   1627:     if (attr == NULL) {
                   1628:         fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
                   1629:        return(NULL);
                   1630:     }
                   1631: 
                   1632:     /*
                   1633:      * Create the Ref table if needed.
                   1634:      */
                   1635:     table = doc->refs;
                   1636:     if (table == NULL) 
                   1637:         table = doc->refs = xmlCreateRefTable();
                   1638:     if (table == NULL) {
                   1639:        fprintf(stderr, "xmlAddRef: Table creation failed!\n");
                   1640:         return(NULL);
                   1641:     }
                   1642: 
                   1643:     /*
                   1644:      * Grow the table, if needed.
                   1645:      */
                   1646:     if (table->nb_refs >= table->max_refs) {
                   1647:         /*
                   1648:         * need more refs.
                   1649:         */
                   1650:        table->max_refs *= 2;
                   1651:        table->table = (xmlRefPtr *) 
                   1652:            xmlRealloc(table->table, table->max_refs *
                   1653:                    sizeof(xmlRefPtr));
                   1654:        if (table->table == NULL) {
                   1655:            fprintf(stderr, "xmlAddRef: out of memory\n");
                   1656:            return(NULL);
                   1657:        }
                   1658:     }
                   1659:     ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
                   1660:     if (ret == NULL) {
                   1661:        fprintf(stderr, "xmlAddRef: out of memory\n");
                   1662:        return(NULL);
                   1663:     }
                   1664:     table->table[table->nb_refs] = ret;
                   1665: 
                   1666:     /*
                   1667:      * fill the structure.
                   1668:      */
                   1669:     ret->value = xmlStrdup(value);
                   1670:     ret->attr = attr;
                   1671:     table->nb_refs++;
                   1672: 
                   1673:     return(ret);
                   1674: }
                   1675: 
                   1676: /**
                   1677:  * xmlFreeRef:
                   1678:  * @not:  A ref
                   1679:  *
                   1680:  * Deallocate the memory used by an ref definition
                   1681:  */
                   1682: void
                   1683: xmlFreeRef(xmlRefPtr ref) {
                   1684:     if (ref == NULL) return;
                   1685:     if (ref->value != NULL)
1.31      daniel   1686:        xmlFree((xmlChar *) ref->value);
1.27      daniel   1687:     memset(ref, -1, sizeof(xmlRef));
                   1688:     xmlFree(ref);
                   1689: }
                   1690: 
                   1691: /**
                   1692:  * xmlFreeRefTable:
                   1693:  * @table:  An ref table
                   1694:  *
                   1695:  * Deallocate the memory used by an Ref hash table.
                   1696:  */
                   1697: void
                   1698: xmlFreeRefTable(xmlRefTablePtr table) {
                   1699:     int i;
                   1700: 
                   1701:     if (table == NULL) return;
                   1702: 
                   1703:     for (i = 0;i < table->nb_refs;i++) {
                   1704:         xmlFreeRef(table->table[i]);
                   1705:     }
                   1706:     xmlFree(table->table);
                   1707:     xmlFree(table);
                   1708: }
                   1709: 
                   1710: /**
                   1711:  * xmlIsRef
                   1712:  * @doc:  the document
                   1713:  * @elem:  the element carrying the attribute
                   1714:  * @attr:  the attribute
                   1715:  *
                   1716:  * Determine whether an attribute is of type Ref. In case we have Dtd(s)
                   1717:  * then this is simple, otherwise we use an heuristic: name Ref (upper
                   1718:  * or lowercase).
                   1719:  *
                   1720:  * Returns 0 or 1 depending on the lookup result
                   1721:  */
                   1722: int
                   1723: xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
                   1724:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
                   1725:         return(0);
                   1726:        /*******************
                   1727:         if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
                   1728:             ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
                   1729:            (attr->name[2] == 0)) return(1);
                   1730:         *******************/
                   1731:     } else {
                   1732:        xmlAttributePtr attrDecl;
                   1733: 
                   1734:        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   1735:        if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   1736:            attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
                   1737:                                         attr->name);
                   1738: 
                   1739:         if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
                   1740:            return(1);
                   1741:     }
                   1742:     return(0);
                   1743: }
                   1744: 
                   1745: /**
                   1746:  * xmlGetRef:
                   1747:  * @doc:  pointer to the document
                   1748:  * @Ref:  the Ref value
                   1749:  *
                   1750:  * Search the attribute declaring the given Ref
                   1751:  *
                   1752:  * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
                   1753:  */
                   1754: xmlAttrPtr 
1.31      daniel   1755: xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
1.27      daniel   1756:     xmlRefPtr cur;
                   1757:     xmlRefTablePtr table;
                   1758:     int i;
                   1759: 
                   1760:     if (doc == NULL) {
                   1761:         fprintf(stderr, "xmlGetRef: doc == NULL\n");
                   1762:        return(NULL);
                   1763:     }
                   1764: 
                   1765:     if (Ref == NULL) {
                   1766:         fprintf(stderr, "xmlGetRef: Ref == NULL\n");
                   1767:        return(NULL);
                   1768:     }
                   1769: 
                   1770:     table = doc->refs;
                   1771:     if (table == NULL) 
                   1772:         return(NULL);
                   1773: 
                   1774:     /*
                   1775:      * Search the Ref list.
                   1776:      */
                   1777:     for (i = 0;i < table->nb_refs;i++) {
                   1778:         cur = table->table[i];
                   1779:        if (!xmlStrcmp(cur->value, Ref)) {
                   1780:            return(cur->attr);
                   1781:        }
                   1782:     }
                   1783:     return(NULL);
                   1784: }
                   1785: 
                   1786: /************************************************************************
                   1787:  *                                                                     *
1.14      daniel   1788:  *             Routines for validity checking                          *
                   1789:  *                                                                     *
                   1790:  ************************************************************************/
                   1791: 
                   1792: /**
                   1793:  * xmlGetDtdElementDesc:
                   1794:  * @dtd:  a pointer to the DtD to search
                   1795:  * @name:  the element name
                   1796:  *
                   1797:  * Search the Dtd for the description of this element
                   1798:  *
                   1799:  * returns the xmlElementPtr if found or NULL
                   1800:  */
                   1801: 
                   1802: xmlElementPtr
1.31      daniel   1803: xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
1.14      daniel   1804:     xmlElementTablePtr table;
                   1805:     xmlElementPtr cur;
                   1806:     int i;
                   1807: 
                   1808:     if (dtd == NULL) return(NULL);
                   1809:     if (dtd->elements == NULL) return(NULL);
                   1810:     table = dtd->elements;
                   1811: 
                   1812:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel   1813:         cur = table->table[i];
1.14      daniel   1814:        if (!xmlStrcmp(cur->name, name))
                   1815:            return(cur);
                   1816:     }
                   1817:     return(NULL);
                   1818: }
                   1819: 
                   1820: /**
                   1821:  * xmlGetDtdAttrDesc:
                   1822:  * @dtd:  a pointer to the DtD to search
1.15      daniel   1823:  * @elem:  the element name
1.14      daniel   1824:  * @name:  the attribute name
                   1825:  *
1.15      daniel   1826:  * Search the Dtd for the description of this attribute on
                   1827:  * this element.
1.14      daniel   1828:  *
                   1829:  * returns the xmlAttributePtr if found or NULL
                   1830:  */
                   1831: 
                   1832: xmlAttributePtr
1.31      daniel   1833: xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
1.14      daniel   1834:     xmlAttributeTablePtr table;
                   1835:     xmlAttributePtr cur;
                   1836:     int i;
                   1837: 
                   1838:     if (dtd == NULL) return(NULL);
                   1839:     if (dtd->attributes == NULL) return(NULL);
                   1840:     table = dtd->attributes;
                   1841: 
                   1842:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel   1843:         cur = table->table[i];
                   1844:        if ((!xmlStrcmp(cur->name, name)) &&
                   1845:            (!xmlStrcmp(cur->elem, elem)))
1.14      daniel   1846:            return(cur);
                   1847:     }
                   1848:     return(NULL);
                   1849: }
                   1850: 
                   1851: /**
                   1852:  * xmlGetDtdNotationDesc:
                   1853:  * @dtd:  a pointer to the DtD to search
                   1854:  * @name:  the notation name
                   1855:  *
                   1856:  * Search the Dtd for the description of this notation
                   1857:  *
                   1858:  * returns the xmlNotationPtr if found or NULL
                   1859:  */
                   1860: 
                   1861: xmlNotationPtr
1.31      daniel   1862: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
1.14      daniel   1863:     xmlNotationTablePtr table;
                   1864:     xmlNotationPtr cur;
                   1865:     int i;
                   1866: 
                   1867:     if (dtd == NULL) return(NULL);
                   1868:     if (dtd->notations == NULL) return(NULL);
                   1869:     table = dtd->notations;
                   1870: 
                   1871:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1872:         cur = table->table[i];
1.14      daniel   1873:        if (!xmlStrcmp(cur->name, name))
                   1874:            return(cur);
                   1875:     }
                   1876:     return(NULL);
                   1877: }
                   1878: 
                   1879: /**
1.23      daniel   1880:  * xmlValidateNotationUse:
                   1881:  * @ctxt:  the validation context
                   1882:  * @doc:  the document
                   1883:  * @notationName:  the notation name to check
                   1884:  *
                   1885:  * Validate that the given mame match a notation declaration.
                   1886:  * - [ VC: Notation Declared ]
                   1887:  *
                   1888:  * returns 1 if valid or 0 otherwise
                   1889:  */
                   1890: 
                   1891: int
                   1892: xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31      daniel   1893:                        const xmlChar *notationName) {
1.23      daniel   1894:     xmlNotationPtr notaDecl;
                   1895:     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
                   1896: 
                   1897:     notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
                   1898:     if ((notaDecl == NULL) && (doc->extSubset != NULL))
                   1899:        notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
                   1900: 
                   1901:     if (notaDecl == NULL) {
                   1902:        VERROR(ctxt->userData, "NOTATION %s is not declared\n",
                   1903:               notationName);
                   1904:        return(0);
                   1905:     }
                   1906:     return(1);
                   1907: }
                   1908: 
                   1909: /**
1.18      daniel   1910:  * xmlIsMixedElement
                   1911:  * @doc:  the document
                   1912:  * @name:  the element name
                   1913:  *
                   1914:  * Search in the DtDs whether an element accept Mixed content (or ANY)
                   1915:  * basically if it is supposed to accept text childs
                   1916:  *
                   1917:  * returns 0 if no, 1 if yes, and -1 if no element description is available
                   1918:  */
                   1919: 
                   1920: int
1.31      daniel   1921: xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
1.18      daniel   1922:     xmlElementPtr elemDecl;
                   1923: 
                   1924:     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
                   1925: 
                   1926:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
                   1927:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   1928:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
                   1929:     if (elemDecl == NULL) return(-1);
                   1930:     switch (elemDecl->type) {
                   1931:        case XML_ELEMENT_TYPE_ELEMENT:
                   1932:            return(0);
                   1933:         case XML_ELEMENT_TYPE_EMPTY:
                   1934:            /*
                   1935:             * return 1 for EMPTY since we want VC error to pop up
                   1936:             * on <empty>     </empty> for example
                   1937:             */
                   1938:        case XML_ELEMENT_TYPE_ANY:
                   1939:        case XML_ELEMENT_TYPE_MIXED:
                   1940:            return(1);
                   1941:     }
                   1942:     return(1);
                   1943: }
                   1944: 
                   1945: /**
1.16      daniel   1946:  * xmlValidateNameValue:
                   1947:  * @value:  an Name value
                   1948:  *
                   1949:  * Validate that the given value match Name production
                   1950:  *
                   1951:  * returns 1 if valid or 0 otherwise
                   1952:  */
                   1953: 
                   1954: int
1.31      daniel   1955: xmlValidateNameValue(const xmlChar *value) {
                   1956:     const xmlChar *cur;
1.16      daniel   1957: 
                   1958:     if (value == NULL) return(0);
                   1959:     cur = value;
                   1960:     
                   1961:     if (!IS_LETTER(*cur) && (*cur != '_') &&
                   1962:         (*cur != ':')) {
                   1963:        return(0);
                   1964:     }
                   1965: 
                   1966:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   1967:            (*cur == '.') || (*cur == '-') ||
                   1968:           (*cur == '_') || (*cur == ':') || 
                   1969:           (IS_COMBINING(*cur)) ||
                   1970:           (IS_EXTENDER(*cur)))
                   1971:           cur++;
                   1972: 
                   1973:     if (*cur != 0) return(0);
                   1974: 
                   1975:     return(1);
                   1976: }
                   1977: 
                   1978: /**
                   1979:  * xmlValidateNamesValue:
                   1980:  * @value:  an Names value
                   1981:  *
                   1982:  * Validate that the given value match Names production
                   1983:  *
                   1984:  * returns 1 if valid or 0 otherwise
                   1985:  */
                   1986: 
                   1987: int
1.31      daniel   1988: xmlValidateNamesValue(const xmlChar *value) {
                   1989:     const xmlChar *cur;
1.16      daniel   1990: 
                   1991:     if (value == NULL) return(0);
                   1992:     cur = value;
                   1993:     
                   1994:     if (!IS_LETTER(*cur) && (*cur != '_') &&
                   1995:         (*cur != ':')) {
                   1996:        return(0);
                   1997:     }
                   1998: 
                   1999:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2000:            (*cur == '.') || (*cur == '-') ||
                   2001:           (*cur == '_') || (*cur == ':') || 
                   2002:           (IS_COMBINING(*cur)) ||
                   2003:           (IS_EXTENDER(*cur)))
                   2004:           cur++;
                   2005: 
                   2006:     while (IS_BLANK(*cur)) {
                   2007:        while (IS_BLANK(*cur)) cur++;
                   2008: 
                   2009:        if (!IS_LETTER(*cur) && (*cur != '_') &&
                   2010:            (*cur != ':')) {
                   2011:            return(0);
                   2012:        }
                   2013: 
                   2014:        while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2015:               (*cur == '.') || (*cur == '-') ||
                   2016:               (*cur == '_') || (*cur == ':') || 
                   2017:               (IS_COMBINING(*cur)) ||
                   2018:               (IS_EXTENDER(*cur)))
                   2019:               cur++;
                   2020:     }
                   2021: 
                   2022:     if (*cur != 0) return(0);
                   2023: 
                   2024:     return(1);
                   2025: }
                   2026: 
                   2027: /**
                   2028:  * xmlValidateNmtokenValue:
                   2029:  * @value:  an Mntoken value
                   2030:  *
                   2031:  * Validate that the given value match Nmtoken production
                   2032:  *
                   2033:  * [ VC: Name Token ]
                   2034:  * 
                   2035:  * returns 1 if valid or 0 otherwise
                   2036:  */
                   2037: 
                   2038: int
1.31      daniel   2039: xmlValidateNmtokenValue(const xmlChar *value) {
                   2040:     const xmlChar *cur;
1.16      daniel   2041: 
                   2042:     if (value == NULL) return(0);
                   2043:     cur = value;
                   2044:     
                   2045:     if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
                   2046:         (*cur != '.') && (*cur != '-') &&
                   2047:         (*cur != '_') && (*cur != ':') && 
                   2048:         (!IS_COMBINING(*cur)) &&
                   2049:         (!IS_EXTENDER(*cur)))
                   2050:        return(0);
                   2051: 
                   2052:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2053:            (*cur == '.') || (*cur == '-') ||
                   2054:           (*cur == '_') || (*cur == ':') || 
                   2055:           (IS_COMBINING(*cur)) ||
                   2056:           (IS_EXTENDER(*cur)))
                   2057:           cur++;
                   2058: 
                   2059:     if (*cur != 0) return(0);
                   2060: 
                   2061:     return(1);
                   2062: }
                   2063: 
                   2064: /**
                   2065:  * xmlValidateNmtokensValue:
                   2066:  * @value:  an Mntokens value
                   2067:  *
                   2068:  * Validate that the given value match Nmtokens production
                   2069:  *
                   2070:  * [ VC: Name Token ]
                   2071:  * 
                   2072:  * returns 1 if valid or 0 otherwise
                   2073:  */
                   2074: 
                   2075: int
1.31      daniel   2076: xmlValidateNmtokensValue(const xmlChar *value) {
                   2077:     const xmlChar *cur;
1.16      daniel   2078: 
                   2079:     if (value == NULL) return(0);
                   2080:     cur = value;
                   2081:     
                   2082:     if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
                   2083:         (*cur != '.') && (*cur != '-') &&
                   2084:         (*cur != '_') && (*cur != ':') && 
                   2085:         (!IS_COMBINING(*cur)) &&
                   2086:         (!IS_EXTENDER(*cur)))
                   2087:        return(0);
                   2088: 
                   2089:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2090:            (*cur == '.') || (*cur == '-') ||
                   2091:           (*cur == '_') || (*cur == ':') || 
                   2092:           (IS_COMBINING(*cur)) ||
                   2093:           (IS_EXTENDER(*cur)))
                   2094:           cur++;
                   2095: 
                   2096:     while (IS_BLANK(*cur)) {
                   2097:        while (IS_BLANK(*cur)) cur++;
                   2098: 
                   2099:        if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
                   2100:            (*cur != '.') && (*cur != '-') &&
                   2101:            (*cur != '_') && (*cur != ':') && 
                   2102:            (!IS_COMBINING(*cur)) &&
                   2103:            (!IS_EXTENDER(*cur)))
                   2104:            return(0);
                   2105: 
                   2106:        while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2107:               (*cur == '.') || (*cur == '-') ||
                   2108:               (*cur == '_') || (*cur == ':') || 
                   2109:               (IS_COMBINING(*cur)) ||
                   2110:               (IS_EXTENDER(*cur)))
                   2111:               cur++;
                   2112:     }
                   2113: 
                   2114:     if (*cur != 0) return(0);
                   2115: 
                   2116:     return(1);
                   2117: }
                   2118: 
                   2119: /**
                   2120:  * xmlValidateNotationDecl:
1.23      daniel   2121:  * @ctxt:  the validation context
1.16      daniel   2122:  * @doc:  a document instance
                   2123:  * @nota:  a notation definition
                   2124:  *
                   2125:  * Try to validate a single notation definition
                   2126:  * basically it does the following checks as described by the
                   2127:  * XML-1.0 recommendation:
1.18      daniel   2128:  *  - it seems that no validity constraing exist on notation declarations
                   2129:  * But this function get called anyway ...
1.16      daniel   2130:  *
                   2131:  * returns 1 if valid or 0 otherwise
                   2132:  */
                   2133: 
                   2134: int
                   2135: xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
                   2136:                          xmlNotationPtr nota) {
                   2137:     int ret = 1;
                   2138: 
                   2139:     return(ret);
                   2140: }
                   2141: 
                   2142: /**
                   2143:  * xmlValidateAttributeValue:
                   2144:  * @type:  an attribute type
                   2145:  * @value:  an attribute value
                   2146:  *
                   2147:  * Validate that the given attribute value match  the proper production
                   2148:  *
                   2149:  * [ VC: ID ]
                   2150:  * Values of type ID must match the Name production....
                   2151:  *
                   2152:  * [ VC: IDREF ]
                   2153:  * Values of type IDREF must match the Name production, and values
                   2154:  * of type IDREFS must match Names ...
                   2155:  *
                   2156:  * [ VC: Entity Name ]
                   2157:  * Values of type ENTITY must match the Name production, values
                   2158:  * of type ENTITIES must match Names ...
                   2159:  *
                   2160:  * [ VC: Name Token ]
                   2161:  * Values of type NMTOKEN must match the Nmtoken production; values
                   2162:  * of type NMTOKENS must match Nmtokens. 
                   2163:  *
                   2164:  * returns 1 if valid or 0 otherwise
                   2165:  */
                   2166: 
                   2167: int
1.31      daniel   2168: xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
1.16      daniel   2169:     switch (type) {
1.24      daniel   2170:        case XML_ATTRIBUTE_ENTITIES:
1.16      daniel   2171:        case XML_ATTRIBUTE_IDREFS:
                   2172:            return(xmlValidateNamesValue(value));
1.24      daniel   2173:        case XML_ATTRIBUTE_ENTITY:
1.16      daniel   2174:        case XML_ATTRIBUTE_IDREF:
                   2175:        case XML_ATTRIBUTE_ID:
                   2176:        case XML_ATTRIBUTE_NOTATION:
                   2177:            return(xmlValidateNameValue(value));
                   2178:        case XML_ATTRIBUTE_NMTOKENS:
                   2179:        case XML_ATTRIBUTE_ENUMERATION:
                   2180:            return(xmlValidateNmtokensValue(value));
                   2181:        case XML_ATTRIBUTE_NMTOKEN:
                   2182:            return(xmlValidateNmtokenValue(value));
                   2183:         case XML_ATTRIBUTE_CDATA:
                   2184:            break;
                   2185:     }
                   2186:     return(1);
                   2187: }
                   2188: 
                   2189: /**
1.14      daniel   2190:  * xmlValidateAttributeDecl:
1.23      daniel   2191:  * @ctxt:  the validation context
1.14      daniel   2192:  * @doc:  a document instance
                   2193:  * @attr:  an attribute definition
                   2194:  *
                   2195:  * Try to validate a single attribute definition
                   2196:  * basically it does the following checks as described by the
                   2197:  * XML-1.0 recommendation:
                   2198:  *  - [ VC: Attribute Default Legal ]
                   2199:  *  - [ VC: Enumeration ]
                   2200:  *  - [ VC: ID Attribute Default ]
                   2201:  *
                   2202:  * The ID/IDREF uniqueness and matching are done separately
                   2203:  *
                   2204:  * returns 1 if valid or 0 otherwise
                   2205:  */
                   2206: 
                   2207: int
                   2208: xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
                   2209:                          xmlAttributePtr attr) {
1.16      daniel   2210:     int ret = 1;
                   2211:     int val;
1.14      daniel   2212:     CHECK_DTD;
1.16      daniel   2213:     if(attr == NULL) return(1);
                   2214:     
                   2215:     /* Attribute Default Legal */
                   2216:     /* Enumeration */
                   2217:     if (attr->defaultValue != NULL) {
                   2218:        val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
                   2219:        if (val == 0) {
                   2220:            VERROR(ctxt->userData, 
                   2221:               "Syntax of default value for attribute %s on %s is not valid\n",
                   2222:                   attr->name, attr->elem);
                   2223:        }
                   2224:         ret &= val;
                   2225:     }
                   2226: 
                   2227:     /* ID Attribute Default */
                   2228:     if ((attr->type == XML_ATTRIBUTE_ID)&&
                   2229:         (attr->def != XML_ATTRIBUTE_IMPLIED) &&
                   2230:        (attr->def != XML_ATTRIBUTE_REQUIRED)) {
                   2231:        VERROR(ctxt->userData, 
                   2232:           "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
                   2233:               attr->name, attr->elem);
                   2234:        ret = 0;
                   2235:     }
                   2236: 
1.24      daniel   2237:     /* One ID per Element Type */
1.16      daniel   2238:     if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
                   2239:         int nbId = 0;
                   2240: 
                   2241:        /* the trick is taht we parse DtD as their own internal subset */
                   2242:         xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
                   2243:                                                  attr->elem);
                   2244:        if (elem != NULL) {
                   2245:            nbId = xmlScanIDAttributeDecl(NULL, elem);
                   2246:        }
                   2247:        if (nbId >= 1)
                   2248:            VERROR(ctxt->userData, 
                   2249:           "Element %s has ID attribute defined in the external subset : %s\n",
                   2250:                   attr->elem, attr->name);
                   2251:     }
1.14      daniel   2252: 
1.16      daniel   2253:     return(ret);
1.14      daniel   2254: }
                   2255: 
                   2256: /**
                   2257:  * xmlValidateElementDecl:
                   2258:  * @ctxt:  the validation context
                   2259:  * @doc:  a document instance
                   2260:  * @elem:  an element definition
                   2261:  *
                   2262:  * Try to validate a single element definition
                   2263:  * basically it does the following checks as described by the
                   2264:  * XML-1.0 recommendation:
                   2265:  *  - [ VC: One ID per Element Type ]
                   2266:  *  - [ VC: No Duplicate Types ]
                   2267:  *  - [ VC: Unique Element Type Declaration ]
                   2268:  *
                   2269:  * returns 1 if valid or 0 otherwise
                   2270:  */
                   2271: 
                   2272: int
1.16      daniel   2273: xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
                   2274:                        xmlElementPtr elem) {
                   2275:     int ret = 1;
                   2276:     xmlElementPtr tst;
                   2277: 
1.14      daniel   2278:     CHECK_DTD;
1.16      daniel   2279:     
                   2280:     if (elem == NULL) return(1);
1.14      daniel   2281: 
1.16      daniel   2282:     /* No Duplicate Types */
                   2283:     if (elem->type == XML_ELEMENT_TYPE_MIXED) {
                   2284:        xmlElementContentPtr cur, next;
1.31      daniel   2285:         const xmlChar *name;
1.16      daniel   2286: 
                   2287:        cur = elem->content;
                   2288:        while (cur != NULL) {
                   2289:            if (cur->type != XML_ELEMENT_CONTENT_OR) break;
                   2290:            if (cur->c1 == NULL) break;
                   2291:            if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
                   2292:                name = cur->c1->name;
                   2293:                next = cur->c2;
                   2294:                while (next != NULL) {
                   2295:                    if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
                   2296:                        if (!xmlStrcmp(next->name, name)) {
                   2297:                            VERROR(ctxt->userData, 
                   2298:                   "Definition of %s has duplicate references of %s\n",
                   2299:                                   elem->name, name);
                   2300:                            ret = 0;
                   2301:                        }
                   2302:                        break;
                   2303:                    }
                   2304:                    if (next->c1 == NULL) break;
                   2305:                    if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
                   2306:                    if (!xmlStrcmp(next->c1->name, name)) {
                   2307:                        VERROR(ctxt->userData, 
                   2308:               "Definition of %s has duplicate references of %s\n",
                   2309:                               elem->name, name);
                   2310:                        ret = 0;
                   2311:                    }
                   2312:                    next = next->c2;
                   2313:                }
                   2314:            }
                   2315:            cur = cur->c2;
                   2316:        }
                   2317:     }
                   2318: 
                   2319:     /* VC: Unique Element Type Declaration */
                   2320:     tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
                   2321:     if ((tst != NULL ) && (tst != elem)) {
                   2322:        VERROR(ctxt->userData, "Redefinition of element %s\n",
                   2323:               elem->name);
                   2324:        ret = 0;
                   2325:     }
                   2326:     tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
                   2327:     if ((tst != NULL ) && (tst != elem)) {
                   2328:        VERROR(ctxt->userData, "Redefinition of element %s\n",
                   2329:               elem->name);
                   2330:        ret = 0;
                   2331:     }
                   2332: 
                   2333:     /* One ID per Element Type */
                   2334:     if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
                   2335:        ret = 0;
                   2336:     }
                   2337:     return(ret);
1.14      daniel   2338: }
                   2339: 
                   2340: /**
                   2341:  * xmlValidateOneAttribute:
                   2342:  * @ctxt:  the validation context
                   2343:  * @doc:  a document instance
                   2344:  * @elem:  an element instance
                   2345:  * @attr:  an attribute instance
1.32      daniel   2346:  * @value:  the attribute value (without entities processing)
1.14      daniel   2347:  *
                   2348:  * Try to validate a single attribute for an element
                   2349:  * basically it * does the following checks as described by the
                   2350:  * XML-1.0 recommendation:
1.18      daniel   2351:  *  - [ VC: Attribute Value Type ]
                   2352:  *  - [ VC: Fixed Attribute Default ]
1.14      daniel   2353:  *  - [ VC: Entity Name ]
                   2354:  *  - [ VC: Name Token ]
                   2355:  *  - [ VC: ID ]
                   2356:  *  - [ VC: IDREF ]
                   2357:  *  - [ VC: Entity Name ]
1.16      daniel   2358:  *  - [ VC: Notation Attributes ]
1.14      daniel   2359:  *
                   2360:  * The ID/IDREF uniqueness and matching are done separately
                   2361:  *
                   2362:  * returns 1 if valid or 0 otherwise
                   2363:  */
                   2364: 
                   2365: int
1.16      daniel   2366: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31      daniel   2367:                         xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
1.24      daniel   2368:     /* xmlElementPtr elemDecl; */
1.18      daniel   2369:     xmlAttributePtr attrDecl;
                   2370:     int val;
                   2371:     int ret = 1;
                   2372: 
1.14      daniel   2373:     CHECK_DTD;
1.18      daniel   2374:     if ((elem == NULL) || (elem->name == NULL)) return(0);
                   2375:     if ((attr == NULL) || (attr->name == NULL)) return(0);
                   2376: 
                   2377:     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   2378:     if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   2379:        attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
                   2380: 
1.14      daniel   2381: 
1.18      daniel   2382:     /* Validity Constraint: Attribute Value Type */
                   2383:     if (attrDecl == NULL) {
                   2384:        VERROR(ctxt->userData,
                   2385:               "No declaration for attribute %s on element %s\n",
                   2386:               attr->name, elem->name);
                   2387:        return(0);
                   2388:     }
                   2389:     val = xmlValidateAttributeValue(attrDecl->type, value);
                   2390:     if (val == 0) {
                   2391:        VERROR(ctxt->userData, 
                   2392:           "Syntax of value for attribute %s on %s is not valid\n",
                   2393:               attr->name, elem->name);
                   2394:         ret = 0;
1.22      daniel   2395:     }
                   2396: 
                   2397:     /* Validity Constraint: ID uniqueness */
                   2398:     if (attrDecl->type == XML_ATTRIBUTE_ID) {
                   2399:         xmlAddID(ctxt, doc, value, attr);
1.18      daniel   2400:     }
                   2401: 
1.28      daniel   2402:     if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
                   2403:         xmlAddRef(ctxt, doc, value, attr);
                   2404:     }
                   2405: 
1.18      daniel   2406:     /* Validity Constraint: Notation Attributes */
                   2407:     if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
                   2408:         xmlEnumerationPtr tree = attrDecl->tree;
                   2409:         xmlNotationPtr nota;
                   2410: 
                   2411:         /* First check that the given NOTATION was declared */
                   2412:        nota = xmlGetDtdNotationDesc(doc->intSubset, value);
                   2413:        if (nota == NULL)
                   2414:            nota = xmlGetDtdNotationDesc(doc->extSubset, value);
                   2415:        
                   2416:        if (nota == NULL) {
                   2417:            VERROR(ctxt->userData, 
                   2418:        "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
                   2419:                   value, attr->name, elem->name);
                   2420:            ret = 0;
                   2421:         }
                   2422: 
                   2423:        /* Second, verify that it's among the list */
                   2424:        while (tree != NULL) {
                   2425:            if (!xmlStrcmp(tree->name, value)) break;
                   2426:            tree = tree->next;
                   2427:        }
                   2428:        if (tree == NULL) {
                   2429:            VERROR(ctxt->userData, 
                   2430:    "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
                   2431:                   value, attr->name, elem->name);
                   2432:            ret = 0;
                   2433:        }
                   2434:     }
                   2435: 
                   2436:     /* Validity Constraint: Enumeration */
                   2437:     if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
                   2438:         xmlEnumerationPtr tree = attrDecl->tree;
                   2439:        while (tree != NULL) {
                   2440:            if (!xmlStrcmp(tree->name, value)) break;
                   2441:            tree = tree->next;
                   2442:        }
                   2443:        if (tree == NULL) {
                   2444:            VERROR(ctxt->userData, 
                   2445:        "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
                   2446:                   value, attr->name, elem->name);
                   2447:            ret = 0;
                   2448:        }
                   2449:     }
                   2450: 
                   2451:     /* Fixed Attribute Default */
                   2452:     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
                   2453:         (xmlStrcmp(attrDecl->defaultValue, value))) {
                   2454:        VERROR(ctxt->userData, 
                   2455:           "Value for attribute %s on %s must be \"%s\"\n",
                   2456:               attr->name, elem->name, attrDecl->defaultValue);
                   2457:         ret = 0;
                   2458:     }
                   2459: 
1.24      daniel   2460:     /********
1.18      daniel   2461:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
                   2462:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   2463:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
                   2464:     if (elemDecl == NULL) {
                   2465:        return(0);
                   2466:     }
1.24      daniel   2467:      ********/
1.18      daniel   2468:     return(ret);
                   2469: }
                   2470: 
                   2471: int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2472:                                  xmlElementContentPtr cont);
                   2473: 
                   2474: /**
                   2475:  * xmlValidateElementTypeExpr:
                   2476:  * @ctxt:  the validation context
                   2477:  * @child:  pointer to the child list
                   2478:  * @cont:  pointer to the content declaration
                   2479:  *
                   2480:  * Try to validate the content of an element of type element
                   2481:  * but don't handle the occurence factor
                   2482:  *
                   2483:  * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
                   2484:  *         also update child value in-situ.
                   2485:  */
                   2486: 
                   2487: int
                   2488: xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2489:                           xmlElementContentPtr cont) {
                   2490:     xmlNodePtr cur;
                   2491:     int ret = 1;
                   2492: 
                   2493:     if (cont == NULL) return(-1);
                   2494:     while (*child != NULL) {
                   2495:         if ((*child)->type == XML_PI_NODE) {
                   2496:            *child = (*child)->next;
                   2497:            continue;
                   2498:        }
                   2499:         if ((*child)->type == XML_COMMENT_NODE) {
                   2500:            *child = (*child)->next;
                   2501:            continue;
                   2502:        }
                   2503:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2504:            return(-1);
                   2505:        }
                   2506:        break;
                   2507:     }
                   2508:     switch (cont->type) {
                   2509:        case XML_ELEMENT_CONTENT_PCDATA:
                   2510:            /* Internal error !!! */
                   2511:            fprintf(stderr, "Internal: MIXED struct bad\n");
                   2512:            return(-1);
                   2513:        case XML_ELEMENT_CONTENT_ELEMENT:
1.20      daniel   2514:            if (*child == NULL) return(0);
1.18      daniel   2515:            ret = (!xmlStrcmp((*child)->name, cont->name));
                   2516:            if (ret == 1)
                   2517:                *child = (*child)->next;
                   2518:            return(ret);
                   2519:        case XML_ELEMENT_CONTENT_OR:
                   2520:            cur = *child;
                   2521:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
                   2522:            if (ret == -1) return(-1);
                   2523:            if (ret == 1) {
                   2524:                 return(1);
                   2525:            }
                   2526:            /* rollback and retry the other path */
                   2527:            *child = cur;
                   2528:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
                   2529:            if (ret == -1) return(-1);
                   2530:            if (ret == 0) {
                   2531:                *child = cur;
                   2532:                return(0);
                   2533:            }
                   2534:            return(1);
                   2535:        case XML_ELEMENT_CONTENT_SEQ:
                   2536:            cur = *child;
                   2537:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
                   2538:            if (ret == -1) return(-1);
                   2539:            if (ret == 0) {
                   2540:                *child = cur;
                   2541:                return(0);
                   2542:            }
                   2543:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
                   2544:            if (ret == -1) return(-1);
                   2545:            if (ret == 0) {
                   2546:                *child = cur;
                   2547:                return(0);
                   2548:            }
                   2549:            return(1);
                   2550:     }
                   2551:     return(ret);
                   2552: }
                   2553: 
                   2554: /**
                   2555:  * xmlValidateElementTypeElement:
                   2556:  * @ctxt:  the validation context
                   2557:  * @child:  pointer to the child list
                   2558:  * @cont:  pointer to the content declaration
                   2559:  *
                   2560:  * Try to validate the content of an element of type element
                   2561:  * yeah, Yet Another Regexp Implementation, and recursive
                   2562:  *
                   2563:  * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
                   2564:  *         also update child and content values in-situ.
                   2565:  */
                   2566: 
                   2567: int
                   2568: xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2569:                              xmlElementContentPtr cont) {
                   2570:     xmlNodePtr cur;
                   2571:     int ret = 1;
                   2572: 
                   2573:     if (cont == NULL) return(-1);
                   2574:     while (*child != NULL) {
                   2575:         if ((*child)->type == XML_PI_NODE) {
                   2576:            *child = (*child)->next;
                   2577:            continue;
                   2578:        }
                   2579:         if ((*child)->type == XML_COMMENT_NODE) {
                   2580:            *child = (*child)->next;
                   2581:            continue;
                   2582:        }
                   2583:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2584:            return(-1);
                   2585:        }
                   2586:        break;
                   2587:     }
                   2588:     cur = *child;
                   2589:     ret = xmlValidateElementTypeExpr(ctxt, child, cont);
                   2590:     if (ret == -1) return(-1);
                   2591:     switch (cont->ocur) {
                   2592:        case XML_ELEMENT_CONTENT_ONCE:
                   2593:            if (ret == 1) {
                   2594:                return(1);
                   2595:            }
                   2596:            *child = cur;
                   2597:            return(0);
                   2598:        case XML_ELEMENT_CONTENT_OPT:
                   2599:            if (ret == 0) {
                   2600:                *child = cur;
                   2601:                return(1);
                   2602:            }
1.19      daniel   2603:            break;
1.18      daniel   2604:        case XML_ELEMENT_CONTENT_MULT:
                   2605:            if (ret == 0) {
                   2606:                *child = cur;
1.19      daniel   2607:                break;
1.18      daniel   2608:            }
                   2609:            /* no break on purpose */
                   2610:        case XML_ELEMENT_CONTENT_PLUS:
                   2611:            if (ret == 0) {
                   2612:                *child = cur;
                   2613:                return(0);
                   2614:            }
                   2615:            do {
                   2616:                cur = *child;
                   2617:                ret = xmlValidateElementTypeExpr(ctxt, child, cont);
                   2618:            } while (ret == 1);
                   2619:            if (ret == -1) return(-1);
                   2620:            *child = cur;
1.19      daniel   2621:            break;
                   2622:     }
                   2623:     while (*child != NULL) {
                   2624:         if ((*child)->type == XML_PI_NODE) {
                   2625:            *child = (*child)->next;
                   2626:            continue;
                   2627:        }
                   2628:         if ((*child)->type == XML_COMMENT_NODE) {
                   2629:            *child = (*child)->next;
                   2630:            continue;
                   2631:        }
                   2632:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2633:            return(-1);
                   2634:        }
                   2635:        break;
                   2636:     }
                   2637:     return(1);
                   2638: }
                   2639: 
                   2640: /**
                   2641:  * xmlSprintfElementChilds:
                   2642:  * @buf:  an output buffer
                   2643:  * @content:  An element
                   2644:  * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
                   2645:  *
                   2646:  * This will dump the list of childs to the buffer
                   2647:  * Intended just for the debug routine
                   2648:  */
                   2649: void
                   2650: xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
                   2651:     xmlNodePtr cur;
                   2652: 
                   2653:     if (node == NULL) return;
                   2654:     if (glob) strcat(buf, "(");
                   2655:     cur = node->childs;
                   2656:     while (cur != NULL) {
                   2657:         switch (cur->type) {
                   2658:             case XML_ELEMENT_NODE:
1.23      daniel   2659:                 strcat(buf, (char *) cur->name);
1.19      daniel   2660:                 if (cur->next != NULL)
                   2661:                     strcat(buf, " ");
                   2662:                 break;
                   2663:             case XML_TEXT_NODE:
                   2664:             case XML_CDATA_SECTION_NODE:
                   2665:             case XML_ENTITY_REF_NODE:
                   2666:                 strcat(buf, "CDATA");
                   2667:                 if (cur->next != NULL)
                   2668:                     strcat(buf, " ");
                   2669:                 break;
                   2670:             case XML_ATTRIBUTE_NODE:
                   2671:             case XML_DOCUMENT_NODE:
1.35      daniel   2672:            case XML_HTML_DOCUMENT_NODE:
1.19      daniel   2673:             case XML_DOCUMENT_TYPE_NODE:
                   2674:             case XML_DOCUMENT_FRAG_NODE:
                   2675:             case XML_NOTATION_NODE:
                   2676:                 strcat(buf, "???");
                   2677:                 if (cur->next != NULL)
                   2678:                     strcat(buf, " ");
                   2679:                 break;
                   2680:             case XML_ENTITY_NODE:
                   2681:             case XML_PI_NODE:
                   2682:             case XML_COMMENT_NODE:
                   2683:                 break;
                   2684:        }
                   2685:        cur = cur->next;
1.18      daniel   2686:     }
1.19      daniel   2687:     if (glob) strcat(buf, ")");
1.14      daniel   2688: }
                   2689: 
1.19      daniel   2690: 
1.14      daniel   2691: /**
                   2692:  * xmlValidateOneElement:
                   2693:  * @ctxt:  the validation context
                   2694:  * @doc:  a document instance
                   2695:  * @elem:  an element instance
                   2696:  *
                   2697:  * Try to validate a single element and it's attributes,
                   2698:  * basically it does the following checks as described by the
                   2699:  * XML-1.0 recommendation:
                   2700:  *  - [ VC: Element Valid ]
                   2701:  *  - [ VC: Required Attribute ]
                   2702:  * Then call xmlValidateOneAttribute() for each attribute present.
                   2703:  *
                   2704:  * The ID/IDREF checkings are done separately
                   2705:  *
                   2706:  * returns 1 if valid or 0 otherwise
                   2707:  */
                   2708: 
                   2709: int
1.16      daniel   2710: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18      daniel   2711:                       xmlNodePtr elem) {
                   2712:     xmlElementPtr elemDecl;
                   2713:     xmlElementContentPtr cont;
                   2714:     xmlNodePtr child;
                   2715:     int ret = 1;
1.31      daniel   2716:     const xmlChar *name;
1.18      daniel   2717: 
1.14      daniel   2718:     CHECK_DTD;
                   2719: 
1.18      daniel   2720:     if ((elem == NULL) || (elem->name == NULL)) return(0);
                   2721: 
                   2722:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
                   2723:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   2724:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
                   2725:     if (elemDecl == NULL) {
                   2726:        VERROR(ctxt->userData, "No declaration for element %s\n",
                   2727:               elem->name);
                   2728:        return(0);
                   2729:     }
                   2730: 
                   2731:     /* Check taht the element content matches the definition */
                   2732:     switch (elemDecl->type) {
                   2733:         case XML_ELEMENT_TYPE_EMPTY:
                   2734:            if (elem->childs != NULL) {
                   2735:                VERROR(ctxt->userData,
                   2736:               "Element %s was declared EMPTY this one has content\n",
                   2737:                       elem->name);
                   2738:                ret = 0;
                   2739:            }
                   2740:            break;
                   2741:         case XML_ELEMENT_TYPE_ANY:
                   2742:            /* I don't think anything is required then */
                   2743:            break;
                   2744:         case XML_ELEMENT_TYPE_MIXED:
                   2745:            /* Hum, this start to get messy */
                   2746:            child = elem->childs;
                   2747:            while (child != NULL) {
                   2748:                if (child->type == XML_ELEMENT_NODE) {
                   2749:                    name = child->name;
                   2750:                    cont = elemDecl->content;
                   2751:                    while (cont != NULL) {
                   2752:                        if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
                   2753:                            if (!xmlStrcmp(cont->name, name)) break;
                   2754:                        } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
                   2755:                           (cont->c1 != NULL) &&
                   2756:                           (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
                   2757:                            if (!xmlStrcmp(cont->c1->name, name)) break;
                   2758:                        } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
                   2759:                            (cont->c1 == NULL) ||
                   2760:                            (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
                   2761:                            /* Internal error !!! */
                   2762:                            fprintf(stderr, "Internal: MIXED struct bad\n");
                   2763:                            break;
                   2764:                        }
                   2765:                        cont = cont->c2;
                   2766:                    }
                   2767:                    if (cont == NULL) {
                   2768:                        VERROR(ctxt->userData,
                   2769:               "Element %s is not declared in %s list of possible childs\n",
                   2770:                               name, elem->name);
                   2771:                        ret = 0;
                   2772:                    }
                   2773:                }
                   2774:                child = child->next;
                   2775:            }
                   2776:            break;
                   2777:         case XML_ELEMENT_TYPE_ELEMENT:
                   2778:            child = elem->childs;
                   2779:            cont = elemDecl->content;
                   2780:            ret = xmlValidateElementTypeElement(ctxt, &child, cont);
1.19      daniel   2781:            if ((ret == 0) || (child != NULL)) {
                   2782:                char expr[1000];
                   2783:                char list[2000];
                   2784: 
                   2785:                expr[0] = 0;
                   2786:                xmlSprintfElementContent(expr, cont, 1);
                   2787:                list[0] = 0;
                   2788:                xmlSprintfElementChilds(list, elem, 1);
                   2789: 
1.18      daniel   2790:                VERROR(ctxt->userData,
1.19      daniel   2791:           "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
                   2792:                       elem->name, expr, list);
1.18      daniel   2793:                ret = 0;
                   2794:            }
                   2795:            break;
                   2796:     }
                   2797: 
1.24      daniel   2798:     /* TODO - [ VC: Required Attribute ] */
1.18      daniel   2799:     return(ret);
1.14      daniel   2800: }
                   2801: 
                   2802: /**
                   2803:  * xmlValidateRoot:
                   2804:  * @ctxt:  the validation context
                   2805:  * @doc:  a document instance
                   2806:  *
                   2807:  * Try to validate a the root element
                   2808:  * basically it does the following check as described by the
                   2809:  * XML-1.0 recommendation:
                   2810:  *  - [ VC: Root Element Type ]
                   2811:  * it doesn't try to recurse or apply other check to the element
                   2812:  *
                   2813:  * returns 1 if valid or 0 otherwise
                   2814:  */
                   2815: 
                   2816: int
                   2817: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
                   2818:     if (doc == NULL) return(0);
                   2819: 
                   2820:     if ((doc->intSubset == NULL) ||
                   2821:        (doc->intSubset->name == NULL)) {
                   2822:        VERROR(ctxt->userData, "Not valid: no DtD found\n");
                   2823:         return(0);
                   2824:     }
                   2825:     if ((doc->root == NULL) || (doc->root->name == NULL)) {
                   2826:        VERROR(ctxt->userData, "Not valid: no root element\n");
                   2827:         return(0);
                   2828:     }
                   2829:     if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
                   2830:        VERROR(ctxt->userData,
                   2831:               "Not valid: root and DtD name do not match %s and %s\n",
                   2832:               doc->root->name, doc->intSubset->name);
                   2833:        return(0);
                   2834:     }
                   2835:     return(1);
                   2836: }
                   2837: 
                   2838: 
                   2839: /**
                   2840:  * xmlValidateElement:
                   2841:  * @ctxt:  the validation context
                   2842:  * @doc:  a document instance
                   2843:  * @elem:  an element instance
                   2844:  *
                   2845:  * Try to validate the subtree under an element 
                   2846:  *
                   2847:  * returns 1 if valid or 0 otherwise
                   2848:  */
                   2849: 
                   2850: int
1.18      daniel   2851: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
1.27      daniel   2852:     xmlNodePtr child;
                   2853:     xmlAttrPtr attr;
1.31      daniel   2854:     xmlChar *value;
1.27      daniel   2855:     int ret = 1;
                   2856: 
                   2857:     if (elem == NULL) return(0);
1.14      daniel   2858:     CHECK_DTD;
                   2859: 
1.27      daniel   2860:     ret &= xmlValidateOneElement(ctxt, doc, elem);
                   2861:     attr = elem->properties;
                   2862:     while(attr != NULL) {
                   2863:         value = xmlNodeListGetString(doc, attr->val, 0);
                   2864:        ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
                   2865:        if (value != NULL)
                   2866:            free(value);
                   2867:        attr= attr->next;
                   2868:     }
                   2869:     child = elem->childs;
                   2870:     while (child != NULL) {
                   2871:         ret &= xmlValidateElement(ctxt, doc, child);
                   2872:         child = child->next;
                   2873:     }
                   2874: 
                   2875:     return(ret);
1.14      daniel   2876: }
                   2877: 
                   2878: /**
1.28      daniel   2879:  * xmlValidateDocumentFinal:
                   2880:  * @ctxt:  the validation context
                   2881:  * @doc:  a document instance
                   2882:  *
                   2883:  * Does the final step for the document validation once all the
                   2884:  * incremental validation steps have been completed
                   2885:  *
                   2886:  * basically it does the following checks described by the XML Rec
                   2887:  * 
                   2888:  *
                   2889:  * returns 1 if valid or 0 otherwise
                   2890:  */
                   2891: 
                   2892: int
                   2893: xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
                   2894:     int ret = 1, i;
                   2895:     xmlRefTablePtr table;
                   2896:     xmlAttrPtr id;
                   2897: 
                   2898:     if (doc == NULL) {
                   2899:         fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
                   2900:        return(0);
                   2901:     }
                   2902: 
                   2903:     /*
                   2904:      * Get the refs table
                   2905:      */
                   2906:     table = doc->refs;
                   2907:     if (table != NULL) {
                   2908:         for (i = 0; i < table->nb_refs; i++) {
                   2909:            id = xmlGetID(doc, table->table[i]->value);
                   2910:            if (id == NULL) {
                   2911:                VERROR(ctxt->userData, 
                   2912:                       "IDREF attribute %s reference an unknown ID '%s'\n",
                   2913:                       table->table[i]->attr->name, table->table[i]->value);
                   2914:                ret = 0;
                   2915:            }
                   2916:        }
                   2917:     }
                   2918:     return(ret);
                   2919: }
                   2920: 
                   2921: /**
1.14      daniel   2922:  * xmlValidateDtd:
                   2923:  * @ctxt:  the validation context
                   2924:  * @doc:  a document instance
                   2925:  * @dtd:  a dtd instance
                   2926:  *
                   2927:  * Try to validate the dtd instance
                   2928:  *
                   2929:  * basically it does check all the definitions in the DtD.
                   2930:  *
                   2931:  * returns 1 if valid or 0 otherwise
                   2932:  */
                   2933: 
                   2934: int
                   2935: xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
1.27      daniel   2936:     /* TODO xmlValidateDtd */
1.14      daniel   2937:     return(1);
                   2938: }
                   2939: 
                   2940: /**
                   2941:  * xmlValidateDocument:
                   2942:  * @ctxt:  the validation context
                   2943:  * @doc:  a document instance
                   2944:  *
                   2945:  * Try to validate the document instance
                   2946:  *
1.27      daniel   2947:  * basically it does the all the checks described by the XML Rec
1.14      daniel   2948:  * i.e. validates the internal and external subset (if present)
                   2949:  * and validate the document tree.
                   2950:  *
                   2951:  * returns 1 if valid or 0 otherwise
                   2952:  */
                   2953: 
                   2954: int
                   2955: xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
1.27      daniel   2956:     int ret;
                   2957: 
1.14      daniel   2958:     if (!xmlValidateRoot(ctxt, doc)) return(0);
                   2959: 
1.27      daniel   2960:     ret = xmlValidateElement(ctxt, doc, doc->root);
1.28      daniel   2961:     ret &= xmlValidateDocumentFinal(ctxt, doc);
                   2962:     return(ret);
1.14      daniel   2963: }
                   2964: 
1.33      daniel   2965: 
                   2966: /************************************************************************
                   2967:  *                                                                     *
                   2968:  *             Routines for dynamic validation editing                 *
                   2969:  *                                                                     *
                   2970:  ************************************************************************/
                   2971: 
                   2972: /**
1.34      daniel   2973:  * xmlValidGetPotentialChildren:
                   2974:  * @ctree:  an element content tree
                   2975:  * @list:  an array to store the list of child names
                   2976:  * @len:  a pointer to the number of element in the list
                   2977:  * @max:  the size of the array
1.33      daniel   2978:  *
1.34      daniel   2979:  * Build/extend a list of  potential children allowed by the content tree
1.33      daniel   2980:  *
1.34      daniel   2981:  * returns the number of element in the list, or -1 in case of error.
1.33      daniel   2982:  */
                   2983: 
1.34      daniel   2984: int
                   2985: xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
                   2986:                              int *len, int max) {
                   2987:     int i;
                   2988: 
                   2989:     if ((ctree == NULL) || (list == NULL) || (len == NULL))
                   2990:         return(-1);
                   2991:     if (*len >= max) return(*len);
                   2992: 
                   2993:     switch (ctree->type) {
                   2994:        case XML_ELEMENT_CONTENT_PCDATA: 
                   2995:            for (i = 0; i < *len;i++)
                   2996:                if (!xmlStrcmp("#PCDATA", list[i])) return(*len);
                   2997:            list[(*len)++] = "#PCDATA";
                   2998:            break;
                   2999:        case XML_ELEMENT_CONTENT_ELEMENT: 
                   3000:            for (i = 0; i < *len;i++)
                   3001:                if (!xmlStrcmp(ctree->name, list[i])) return(*len);
                   3002:            list[(*len)++] = ctree->name;
                   3003:            break;
                   3004:        case XML_ELEMENT_CONTENT_SEQ: 
                   3005:            xmlValidGetPotentialChildren(ctree->c1, list, len, max);
                   3006:            xmlValidGetPotentialChildren(ctree->c2, list, len, max);
                   3007:            break;
                   3008:        case XML_ELEMENT_CONTENT_OR:
                   3009:            xmlValidGetPotentialChildren(ctree->c1, list, len, max);
                   3010:            xmlValidGetPotentialChildren(ctree->c2, list, len, max);
                   3011:            break;
                   3012:    }
                   3013:    
                   3014:    return(*len);
1.33      daniel   3015: }
                   3016: 
                   3017: /**
1.34      daniel   3018:  * xmlValidGetValidElements:
                   3019:  * @prev:  an element to insert after
                   3020:  * @next:  an element to insert next
                   3021:  * @list:  an array to store the list of child names
                   3022:  * @max:  the size of the array
1.33      daniel   3023:  *
1.34      daniel   3024:  * This function returns the list of authorized children to insert
                   3025:  * within an existing tree while respecting the validity constraints
                   3026:  * forced by the Dtd. The insertion point is defined using @prev and
                   3027:  * @next in the following ways:
                   3028:  *  to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
                   3029:  *  to insert next 'node': xmlValidGetValidElements(node, node->next, ...
                   3030:  *  to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
                   3031:  *  to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
                   3032:  *  to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
1.33      daniel   3033:  *
1.34      daniel   3034:  * pointers to the element names are inserted at the beginning of the array
                   3035:  * and do not need to be freed.
                   3036:  *
                   3037:  * returns the number of element in the list, or -1 in case of error. If
                   3038:  *    the function returns the value @max the caller is invited to grow the
                   3039:  *    receiving array and retry.
1.33      daniel   3040:  */
                   3041: 
1.34      daniel   3042: int
                   3043: xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
                   3044:                          int max) {
                   3045:     int nb_valid_elements = 0;
                   3046:     const xmlChar *elements[256];
                   3047:     int nb_elements = 0, i;
                   3048:     
                   3049:     xmlNode *ref_node;
                   3050:     xmlNode *parent;
                   3051:     xmlNode *test_node;
                   3052:     
                   3053:     xmlNode *prev_next;
                   3054:     xmlNode *next_prev;
                   3055:     xmlNode *parent_childs;
                   3056:     xmlNode *parent_last;
                   3057:     
                   3058:     xmlElement *element_desc;
                   3059: 
                   3060:     if (prev == NULL && next == NULL)
                   3061:         return(-1);
                   3062: 
                   3063:     if (list == NULL) return(-1);
                   3064:     if (max <= 0) return(-1);
                   3065: 
                   3066:     nb_valid_elements = 0;
                   3067:     ref_node = prev ? prev : next;
                   3068:     parent = ref_node->parent;
                   3069: 
                   3070:     /*
                   3071:      * Retrieves the parent element declaration
                   3072:      */
                   3073:     element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
                   3074:                                          parent->name);
                   3075:     if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
                   3076:         element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
                   3077:                                              parent->name);
                   3078:     if (element_desc == NULL) return(-1);
                   3079:        
                   3080:     /*
                   3081:      * Do a backup of the current tree structure
                   3082:      */
                   3083:     prev_next = prev ? prev->next : NULL;
                   3084:     next_prev = next ? next->prev : NULL;
                   3085:     parent_childs = parent->childs;
                   3086:     parent_last = parent->last;
                   3087: 
                   3088:     /*
                   3089:      * Creates a dummy node and insert it into the tree
                   3090:      */    
                   3091:     test_node = xmlNewNode (NULL, "<!dummy?>");
                   3092:     test_node->doc = ref_node->doc;
                   3093:     test_node->parent = parent;
                   3094:     test_node->prev = prev;
                   3095:     test_node->next = next;
                   3096:     
                   3097:     if (prev) prev->next = test_node;
                   3098:     else parent->childs = test_node;
                   3099:                
                   3100:     if (next) next->prev = test_node;
                   3101:     else parent->last = test_node;
                   3102: 
                   3103:     /*
                   3104:      * Insert each potential child node and check if the parent is
                   3105:      * still valid
                   3106:      */
                   3107:     nb_elements = xmlValidGetPotentialChildren(element_desc->content,
                   3108:                       elements, &nb_elements, 256);
                   3109:     
                   3110:     for (i = 0;i < nb_elements;i++) {
                   3111:        test_node->name = elements[i];
                   3112:        if (xmlValidateOneElement(NULL, parent->doc, parent)) {
                   3113:            int j;
                   3114: 
                   3115:            for (j = 0; j < nb_valid_elements;j++)
                   3116:                if (!xmlStrcmp(elements[i], list[j])) break;
                   3117:            list[nb_valid_elements++] = elements[i];
                   3118:            if (nb_valid_elements >= max) break;
                   3119:        }
1.33      daniel   3120:     }
                   3121: 
1.34      daniel   3122:     /*
                   3123:      * Restore the tree structure
                   3124:      */
                   3125:     if (prev) prev->next = prev_next;
                   3126:     if (next) next->prev = next_prev;
                   3127:     parent->childs = parent_childs;
                   3128:     parent->last = parent_last;
                   3129:     
                   3130:     return(nb_valid_elements);
1.33      daniel   3131: }

Webmaster