Annotation of XML/valid.c, revision 1.30

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.15      daniel     39: xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name);
                     40: xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem);
                     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.25      daniel     58: xmlNewElementContent(CHAR *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);
                    106:     ret = xmlNewElementContent((CHAR *) 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.26      daniel    128:     if (cur->name != NULL) xmlFree((CHAR *) 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.6       daniel    300:  * @dtd:  pointer to the DTD
1.1       daniel    301:  * @name:  the entity name
1.6       daniel    302:  * @type:  the element type
                    303:  * @content:  the element content tree or NULL
1.1       daniel    304:  *
                    305:  * Register a new element declaration
                    306:  *
1.6       daniel    307:  * Returns NULL if not, othervise the entity
1.1       daniel    308:  */
                    309: xmlElementPtr
1.16      daniel    310: xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
1.25      daniel    311:                   xmlElementContentType type, xmlElementContentPtr content) {
1.2       daniel    312:     xmlElementPtr ret, cur;
                    313:     xmlElementTablePtr table;
                    314:     int i;
1.1       daniel    315: 
                    316:     if (dtd == NULL) {
                    317:         fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
                    318:        return(NULL);
                    319:     }
                    320:     if (name == NULL) {
                    321:         fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
                    322:        return(NULL);
                    323:     }
                    324:     switch (type) {
                    325:         case XML_ELEMENT_TYPE_EMPTY:
                    326:            if (content != NULL) {
                    327:                fprintf(stderr,
                    328:                        "xmlAddElementDecl: content != NULL for EMPTY\n");
                    329:                return(NULL);
                    330:            }
                    331:            break;
                    332:        case XML_ELEMENT_TYPE_ANY:
                    333:            if (content != NULL) {
                    334:                fprintf(stderr,
                    335:                        "xmlAddElementDecl: content != NULL for ANY\n");
                    336:                return(NULL);
                    337:            }
                    338:            break;
                    339:        case XML_ELEMENT_TYPE_MIXED:
                    340:            if (content == NULL) {
                    341:                fprintf(stderr,
                    342:                        "xmlAddElementDecl: content == NULL for MIXED\n");
                    343:                return(NULL);
                    344:            }
                    345:            break;
                    346:        case XML_ELEMENT_TYPE_ELEMENT:
                    347:            if (content == NULL) {
                    348:                fprintf(stderr,
                    349:                        "xmlAddElementDecl: content == NULL for ELEMENT\n");
                    350:                return(NULL);
                    351:            }
                    352:            break;
                    353:        default:
                    354:            fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
                    355:            return(NULL);
                    356:     }
                    357: 
                    358:     /*
1.2       daniel    359:      * Create the Element table if needed.
                    360:      */
                    361:     table = dtd->elements;
                    362:     if (table == NULL) 
                    363:         table = dtd->elements = xmlCreateElementTable();
                    364:     if (table == NULL) {
                    365:        fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
                    366:         return(NULL);
                    367:     }
                    368: 
                    369:     /*
1.1       daniel    370:      * Validity Check:
                    371:      * Search the DTD for previous declarations of the ELEMENT
                    372:      */
1.2       daniel    373:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel    374:         cur = table->table[i];
1.2       daniel    375:        if (!xmlStrcmp(cur->name, name)) {
                    376:            /*
                    377:             * The element is already defined in this Dtd.
                    378:             */
1.16      daniel    379:            VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1.2       daniel    380:            return(NULL);
                    381:        }
                    382:     }
1.1       daniel    383: 
                    384:     /*
1.2       daniel    385:      * Grow the table, if needed.
1.1       daniel    386:      */
1.2       daniel    387:     if (table->nb_elements >= table->max_elements) {
                    388:         /*
                    389:         * need more elements.
                    390:         */
                    391:        table->max_elements *= 2;
1.15      daniel    392:        table->table = (xmlElementPtr *) 
1.26      daniel    393:            xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
1.13      daniel    394:        if (table->table == NULL) {
1.2       daniel    395:            fprintf(stderr, "xmlAddElementDecl: out of memory\n");
                    396:            return(NULL);
                    397:        }
1.1       daniel    398:     }
1.26      daniel    399:     ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1.15      daniel    400:     if (ret == NULL) {
                    401:        fprintf(stderr, "xmlAddElementDecl: out of memory\n");
                    402:        return(NULL);
                    403:     }
                    404:     table->table[table->nb_elements] = ret;
1.2       daniel    405: 
                    406:     /*
                    407:      * fill the structure.
                    408:      */
1.1       daniel    409:     ret->type = type;
                    410:     ret->name = xmlStrdup(name);
1.11      daniel    411:     ret->content = xmlCopyElementContent(content);
1.15      daniel    412:     ret->attributes = xmlScanAttributeDecl(dtd, name);
1.2       daniel    413:     table->nb_elements++;
                    414: 
                    415:     return(ret);
                    416: }
                    417: 
                    418: /**
                    419:  * xmlFreeElement:
                    420:  * @elem:  An element
                    421:  *
                    422:  * Deallocate the memory used by an element definition
                    423:  */
                    424: void
                    425: xmlFreeElement(xmlElementPtr elem) {
                    426:     if (elem == NULL) return;
                    427:     xmlFreeElementContent(elem->content);
                    428:     if (elem->name != NULL)
1.26      daniel    429:        xmlFree((CHAR *) elem->name);
1.2       daniel    430:     memset(elem, -1, sizeof(xmlElement));
1.26      daniel    431:     xmlFree(elem);
1.2       daniel    432: }
1.1       daniel    433: 
1.2       daniel    434: /**
                    435:  * xmlFreeElementTable:
                    436:  * @table:  An element table
                    437:  *
1.4       daniel    438:  * Deallocate the memory used by an element hash table.
1.2       daniel    439:  */
                    440: void
                    441: xmlFreeElementTable(xmlElementTablePtr table) {
                    442:     int i;
                    443: 
                    444:     if (table == NULL) return;
                    445: 
                    446:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel    447:         xmlFreeElement(table->table[i]);
1.2       daniel    448:     }
1.26      daniel    449:     xmlFree(table->table);
                    450:     xmlFree(table);
1.2       daniel    451: }
                    452: 
                    453: /**
                    454:  * xmlCopyElementTable:
                    455:  * @table:  An element table
                    456:  *
                    457:  * Build a copy of an element table.
                    458:  * 
1.6       daniel    459:  * Returns the new xmlElementTablePtr or NULL in case of error.
1.2       daniel    460:  */
                    461: xmlElementTablePtr
                    462: xmlCopyElementTable(xmlElementTablePtr table) {
                    463:     xmlElementTablePtr ret;
                    464:     xmlElementPtr cur, ent;
                    465:     int i;
1.1       daniel    466: 
1.26      daniel    467:     ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
1.2       daniel    468:     if (ret == NULL) {
                    469:         fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
                    470:        return(NULL);
                    471:     }
1.26      daniel    472:     ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
1.15      daniel    473:                                          sizeof(xmlElementPtr));
1.2       daniel    474:     if (ret->table == NULL) {
                    475:         fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
1.26      daniel    476:        xmlFree(ret);
1.2       daniel    477:        return(NULL);
                    478:     }
                    479:     ret->max_elements = table->max_elements;
                    480:     ret->nb_elements = table->nb_elements;
                    481:     for (i = 0;i < ret->nb_elements;i++) {
1.26      daniel    482:        cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1.15      daniel    483:        if (cur == NULL) {
                    484:            fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
1.26      daniel    485:            xmlFree(ret);
                    486:            xmlFree(ret->table);
1.15      daniel    487:            return(NULL);
                    488:        }
                    489:        ret->table[i] = cur;
                    490:        ent = table->table[i];
1.2       daniel    491:        cur->type = ent->type;
                    492:        if (ent->name != NULL)
                    493:            cur->name = xmlStrdup(ent->name);
                    494:        else
                    495:            cur->name = NULL;
                    496:        cur->content = xmlCopyElementContent(ent->content);
1.15      daniel    497:        cur->attributes = NULL;
1.2       daniel    498:     }
1.1       daniel    499:     return(ret);
                    500: }
                    501: 
1.2       daniel    502: /**
                    503:  * xmlDumpElementTable:
1.9       daniel    504:  * @buf:  the XML buffer output
1.2       daniel    505:  * @table:  An element table
                    506:  *
                    507:  * This will dump the content of the element table as an XML DTD definition
                    508:  */
                    509: void
1.8       daniel    510: xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1.2       daniel    511:     int i;
                    512:     xmlElementPtr cur;
                    513: 
                    514:     if (table == NULL) return;
                    515: 
                    516:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel    517:         cur = table->table[i];
1.2       daniel    518:         switch (cur->type) {
                    519:            case XML_ELEMENT_TYPE_EMPTY:
1.8       daniel    520:                xmlBufferWriteChar(buf, "<!ELEMENT ");
                    521:                xmlBufferWriteCHAR(buf, cur->name);
                    522:                xmlBufferWriteChar(buf, " EMPTY>\n");
1.2       daniel    523:                break;
                    524:            case XML_ELEMENT_TYPE_ANY:
1.8       daniel    525:                xmlBufferWriteChar(buf, "<!ELEMENT ");
                    526:                xmlBufferWriteCHAR(buf, cur->name);
                    527:                xmlBufferWriteChar(buf, " ANY>\n");
1.2       daniel    528:                break;
                    529:            case XML_ELEMENT_TYPE_MIXED:
1.8       daniel    530:                xmlBufferWriteChar(buf, "<!ELEMENT ");
                    531:                xmlBufferWriteCHAR(buf, cur->name);
                    532:                xmlBufferWriteChar(buf, " ");
                    533:                xmlDumpElementContent(buf, cur->content, 1);
                    534:                xmlBufferWriteChar(buf, ">\n");
1.2       daniel    535:                break;
                    536:            case XML_ELEMENT_TYPE_ELEMENT:
1.8       daniel    537:                xmlBufferWriteChar(buf, "<!ELEMENT ");
                    538:                xmlBufferWriteCHAR(buf, cur->name);
                    539:                xmlBufferWriteChar(buf, " ");
                    540:                xmlDumpElementContent(buf, cur->content, 1);
                    541:                xmlBufferWriteChar(buf, ">\n");
1.2       daniel    542:                break;
                    543:            default:
                    544:                fprintf(stderr,
                    545:                    "xmlDumpElementTable: internal: unknown type %d\n",
                    546:                        cur->type);
                    547:        }
1.4       daniel    548:     }
                    549: }
                    550: 
                    551: /**
                    552:  * xmlCreateEnumeration:
                    553:  * @name:  the enumeration name or NULL
                    554:  *
                    555:  * create and initialize an enumeration attribute node.
                    556:  *
1.6       daniel    557:  * Returns the xmlEnumerationPtr just created or NULL in case
1.4       daniel    558:  *                of error.
                    559:  */
                    560: xmlEnumerationPtr
                    561: xmlCreateEnumeration(CHAR *name) {
                    562:     xmlEnumerationPtr ret;
                    563: 
1.26      daniel    564:     ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1.4       daniel    565:     if (ret == NULL) {
1.26      daniel    566:         fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
1.12      daniel    567:                (long)sizeof(xmlEnumeration));
1.4       daniel    568:         return(NULL);
                    569:     }
                    570: 
                    571:     if (name != NULL)
                    572:         ret->name = xmlStrdup(name);
                    573:     else
                    574:         ret->name = NULL;
                    575:     ret->next = NULL;
                    576:     return(ret);
                    577: }
                    578: 
                    579: /**
                    580:  * xmlFreeEnumeration:
                    581:  * @cur:  the tree to free.
                    582:  *
                    583:  * free an enumeration attribute node (recursive).
                    584:  */
                    585: void
                    586: xmlFreeEnumeration(xmlEnumerationPtr cur) {
                    587:     if (cur == NULL) return;
                    588: 
                    589:     if (cur->next != NULL) xmlFreeEnumeration(cur->next);
                    590: 
1.26      daniel    591:     if (cur->name != NULL) xmlFree((CHAR *) cur->name);
1.4       daniel    592:     memset(cur, -1, sizeof(xmlEnumeration));
1.26      daniel    593:     xmlFree(cur);
1.4       daniel    594: }
                    595: 
                    596: /**
                    597:  * xmlCopyEnumeration:
                    598:  * @cur:  the tree to copy.
                    599:  *
                    600:  * Copy an enumeration attribute node (recursive).
                    601:  *
1.6       daniel    602:  * Returns the xmlEnumerationPtr just created or NULL in case
1.4       daniel    603:  *                of error.
                    604:  */
                    605: xmlEnumerationPtr
                    606: xmlCopyEnumeration(xmlEnumerationPtr cur) {
                    607:     xmlEnumerationPtr ret;
                    608: 
                    609:     if (cur == NULL) return(NULL);
                    610:     ret = xmlCreateEnumeration((CHAR *) cur->name);
                    611: 
                    612:     if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
                    613:     else ret->next = NULL;
                    614: 
                    615:     return(ret);
                    616: }
                    617: 
                    618: /**
1.18      daniel    619:  * xmlDumpEnumeration:
                    620:  * @buf:  the XML buffer output
                    621:  * @enum:  An enumeration
                    622:  *
                    623:  * This will dump the content of the enumeration
                    624:  */
                    625: void
                    626: xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
                    627:     if (cur == NULL)  return;
                    628:     
                    629:     xmlBufferWriteCHAR(buf, cur->name);
                    630:     if (cur->next == NULL)
                    631:        xmlBufferWriteChar(buf, ")");
                    632:     else {
                    633:        xmlBufferWriteChar(buf, " | ");
                    634:        xmlDumpEnumeration(buf, cur->next);
                    635:     }
                    636: }
                    637: 
                    638: /**
1.4       daniel    639:  * xmlCreateAttributeTable:
                    640:  *
                    641:  * create and initialize an empty attribute hash table.
                    642:  *
1.6       daniel    643:  * Returns the xmlAttributeTablePtr just created or NULL in case
1.4       daniel    644:  *                of error.
                    645:  */
                    646: xmlAttributeTablePtr
                    647: xmlCreateAttributeTable(void) {
                    648:     xmlAttributeTablePtr ret;
                    649: 
                    650:     ret = (xmlAttributeTablePtr) 
1.26      daniel    651:          xmlMalloc(sizeof(xmlAttributeTable));
1.4       daniel    652:     if (ret == NULL) {
1.26      daniel    653:         fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
1.12      daniel    654:                (long)sizeof(xmlAttributeTable));
1.4       daniel    655:         return(NULL);
                    656:     }
                    657:     ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
                    658:     ret->nb_attributes = 0;
1.15      daniel    659:     ret->table = (xmlAttributePtr *) 
1.26      daniel    660:          xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
1.4       daniel    661:     if (ret == NULL) {
1.26      daniel    662:         fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
1.15      daniel    663:                ret->max_attributes * (long)sizeof(xmlAttributePtr));
1.26      daniel    664:        xmlFree(ret);
1.4       daniel    665:         return(NULL);
                    666:     }
                    667:     return(ret);
                    668: }
                    669: 
1.15      daniel    670: /**
                    671:  * xmlScanAttributeDecl:
                    672:  * @dtd:  pointer to the DTD
                    673:  * @elem:  the element name
                    674:  *
                    675:  * When inserting a new element scan the DtD for existing attributes
                    676:  * for taht element and initialize the Attribute chain
                    677:  *
                    678:  * Returns the pointer to the first attribute decl in the chain,
                    679:  *         possibly NULL.
                    680:  */
                    681: xmlAttributePtr
                    682: xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem) {
1.16      daniel    683:     xmlAttributePtr ret = NULL;
1.15      daniel    684:     xmlAttributeTablePtr table;
                    685:     int i;
                    686: 
                    687:     if (dtd == NULL) {
                    688:         fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
                    689:        return(NULL);
                    690:     }
                    691:     if (elem == NULL) {
                    692:         fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
                    693:        return(NULL);
                    694:     }
                    695:     table = dtd->attributes;
                    696:     if (table == NULL) 
                    697:         return(NULL);
                    698: 
                    699:     for (i = 0;i < table->nb_attributes;i++) {
                    700:         if (!xmlStrcmp(table->table[i]->elem, elem)) {
1.16      daniel    701:            table->table[i]->next = ret;
                    702:            ret = table->table[i];
                    703:        }
                    704:     }
                    705:     return(ret);
                    706: }
                    707: 
                    708: /**
                    709:  * xmlScanIDAttributeDecl:
                    710:  * @ctxt:  the validation context
                    711:  * @elem:  the element name
                    712:  *
                    713:  * Veryfy that the element don't have too many ID attributes
                    714:  * declared.
                    715:  *
                    716:  * Returns the number of ID attributes found.
                    717:  */
                    718: int
                    719: xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
                    720:     xmlAttributePtr cur;
                    721:     int ret = 0;
                    722: 
                    723:     if (elem == NULL) return(0);
                    724:     cur = elem->attributes;
                    725:     while (cur != NULL) {
                    726:         if (cur->type == XML_ATTRIBUTE_ID) {
                    727:            ret ++;
                    728:            if (ret > 1)
                    729:                VERROR(ctxt->userData, 
                    730:               "Element %s has too may ID attributes defined : %s\n",
                    731:                       elem->name, cur->name);
1.15      daniel    732:        }
1.16      daniel    733:        cur = cur->next;
1.15      daniel    734:     }
                    735:     return(ret);
                    736: }
                    737: 
1.4       daniel    738: 
                    739: /**
                    740:  * xmlAddAttributeDecl:
1.16      daniel    741:  * @ctxt:  the validation context
1.6       daniel    742:  * @dtd:  pointer to the DTD
                    743:  * @elem:  the element name
                    744:  * @name:  the attribute name
                    745:  * @type:  the attribute type
                    746:  * @def:  the attribute default type
                    747:  * @defaultValue:  the attribute default value
                    748:  * @tree:  if it's an enumeration, the associated list
1.4       daniel    749:  *
                    750:  * Register a new attribute declaration
                    751:  *
1.6       daniel    752:  * Returns NULL if not, othervise the entity
1.4       daniel    753:  */
                    754: xmlAttributePtr
1.16      daniel    755: xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *elem,
1.25      daniel    756:                     const CHAR *name, xmlAttributeType type, 
                    757:                     xmlAttributeDefault def, const CHAR *defaultValue,
                    758:                     xmlEnumerationPtr tree) {
1.4       daniel    759:     xmlAttributePtr ret, cur;
                    760:     xmlAttributeTablePtr table;
1.15      daniel    761:     xmlElementPtr elemDef;
1.4       daniel    762:     int i;
                    763: 
                    764:     if (dtd == NULL) {
                    765:         fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
                    766:        return(NULL);
                    767:     }
                    768:     if (name == NULL) {
                    769:         fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
                    770:        return(NULL);
                    771:     }
                    772:     if (elem == NULL) {
                    773:         fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
                    774:        return(NULL);
                    775:     }
1.23      daniel    776:     /*
                    777:      * Check the type and possibly the default value.
                    778:      */
1.4       daniel    779:     switch (type) {
                    780:         case XML_ATTRIBUTE_CDATA:
                    781:            break;
                    782:         case XML_ATTRIBUTE_ID:
                    783:            break;
                    784:         case XML_ATTRIBUTE_IDREF:
                    785:            break;
                    786:         case XML_ATTRIBUTE_IDREFS:
                    787:            break;
                    788:         case XML_ATTRIBUTE_ENTITY:
                    789:            break;
                    790:         case XML_ATTRIBUTE_ENTITIES:
                    791:            break;
                    792:         case XML_ATTRIBUTE_NMTOKEN:
                    793:            break;
                    794:         case XML_ATTRIBUTE_NMTOKENS:
                    795:            break;
                    796:         case XML_ATTRIBUTE_ENUMERATION:
                    797:            break;
                    798:         case XML_ATTRIBUTE_NOTATION:
                    799:            break;
                    800:        default:
                    801:            fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
                    802:            return(NULL);
                    803:     }
1.23      daniel    804:     if ((defaultValue != NULL) && 
                    805:         (!xmlValidateAttributeValue(type, defaultValue))) {
                    806:        VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
                    807:               elem, name, defaultValue);
                    808:        defaultValue = NULL;
                    809:     }
1.4       daniel    810: 
                    811:     /*
                    812:      * Create the Attribute table if needed.
                    813:      */
                    814:     table = dtd->attributes;
                    815:     if (table == NULL) 
                    816:         table = dtd->attributes = xmlCreateAttributeTable();
                    817:     if (table == NULL) {
                    818:        fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
                    819:         return(NULL);
                    820:     }
                    821: 
                    822:     /*
                    823:      * Validity Check:
                    824:      * Search the DTD for previous declarations of the ATTLIST
                    825:      */
                    826:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel    827:         cur = table->table[i];
1.4       daniel    828:        if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
                    829:            /*
                    830:             * The attribute is already defined in this Dtd.
                    831:             */
1.23      daniel    832:            VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
                    833:                   elem, name);
1.4       daniel    834:        }
                    835:     }
                    836: 
                    837:     /*
                    838:      * Grow the table, if needed.
                    839:      */
                    840:     if (table->nb_attributes >= table->max_attributes) {
                    841:         /*
                    842:         * need more attributes.
                    843:         */
                    844:        table->max_attributes *= 2;
1.15      daniel    845:        table->table = (xmlAttributePtr *) 
1.26      daniel    846:            xmlRealloc(table->table, table->max_attributes * 
1.15      daniel    847:                    sizeof(xmlAttributePtr));
1.13      daniel    848:        if (table->table == NULL) {
1.4       daniel    849:            fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
                    850:            return(NULL);
                    851:        }
                    852:     }
1.26      daniel    853:     ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15      daniel    854:     if (ret == NULL) {
                    855:        fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
                    856:        return(NULL);
                    857:     }
                    858:     table->table[table->nb_attributes] = ret;
1.4       daniel    859: 
                    860:     /*
                    861:      * fill the structure.
                    862:      */
                    863:     ret->type = type;
                    864:     ret->name = xmlStrdup(name);
                    865:     ret->elem = xmlStrdup(elem);
                    866:     ret->def = def;
                    867:     ret->tree = tree;
                    868:     if (defaultValue != NULL)
                    869:        ret->defaultValue = xmlStrdup(defaultValue);
                    870:     else
                    871:         ret->defaultValue = NULL;
1.15      daniel    872:     elemDef = xmlGetDtdElementDesc(dtd, elem);
                    873:     if (elemDef != NULL) {
1.16      daniel    874:         if ((type == XML_ATTRIBUTE_ID) &&
                    875:            (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
                    876:            VERROR(ctxt->userData, 
                    877:           "Element %s has too may ID attributes defined : %s\n",
                    878:                   elem, name);
1.15      daniel    879:         ret->next = elemDef->attributes;
                    880:         elemDef->attributes = ret;
                    881:     }
1.4       daniel    882:     table->nb_attributes++;
                    883: 
                    884:     return(ret);
                    885: }
                    886: 
                    887: /**
                    888:  * xmlFreeAttribute:
                    889:  * @elem:  An attribute
                    890:  *
                    891:  * Deallocate the memory used by an attribute definition
                    892:  */
                    893: void
                    894: xmlFreeAttribute(xmlAttributePtr attr) {
                    895:     if (attr == NULL) return;
                    896:     if (attr->tree != NULL)
                    897:         xmlFreeEnumeration(attr->tree);
                    898:     if (attr->elem != NULL)
1.26      daniel    899:        xmlFree((CHAR *) attr->elem);
1.4       daniel    900:     if (attr->name != NULL)
1.26      daniel    901:        xmlFree((CHAR *) attr->name);
1.4       daniel    902:     if (attr->defaultValue != NULL)
1.26      daniel    903:        xmlFree((CHAR *) attr->defaultValue);
1.4       daniel    904:     memset(attr, -1, sizeof(xmlAttribute));
1.26      daniel    905:     xmlFree(attr);
1.4       daniel    906: }
                    907: 
                    908: /**
                    909:  * xmlFreeAttributeTable:
                    910:  * @table:  An attribute table
                    911:  *
                    912:  * Deallocate the memory used by an entities hash table.
                    913:  */
                    914: void
                    915: xmlFreeAttributeTable(xmlAttributeTablePtr table) {
                    916:     int i;
                    917: 
                    918:     if (table == NULL) return;
                    919: 
                    920:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel    921:         xmlFreeAttribute(table->table[i]);
1.4       daniel    922:     }
1.26      daniel    923:     xmlFree(table->table);
                    924:     xmlFree(table);
1.4       daniel    925: }
                    926: 
                    927: /**
                    928:  * xmlCopyAttributeTable:
                    929:  * @table:  An attribute table
                    930:  *
                    931:  * Build a copy of an attribute table.
                    932:  * 
1.6       daniel    933:  * Returns the new xmlAttributeTablePtr or NULL in case of error.
1.4       daniel    934:  */
                    935: xmlAttributeTablePtr
                    936: xmlCopyAttributeTable(xmlAttributeTablePtr table) {
                    937:     xmlAttributeTablePtr ret;
                    938:     xmlAttributePtr cur, attr;
                    939:     int i;
                    940: 
1.26      daniel    941:     ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
1.4       daniel    942:     if (ret == NULL) {
                    943:         fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
                    944:        return(NULL);
                    945:     }
1.26      daniel    946:     ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
1.15      daniel    947:                                           sizeof(xmlAttributePtr));
1.4       daniel    948:     if (ret->table == NULL) {
                    949:         fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26      daniel    950:        xmlFree(ret);
1.4       daniel    951:        return(NULL);
                    952:     }
                    953:     ret->max_attributes = table->max_attributes;
                    954:     ret->nb_attributes = table->nb_attributes;
                    955:     for (i = 0;i < ret->nb_attributes;i++) {
1.15      daniel    956:        attr = table->table[i];
1.26      daniel    957:        cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15      daniel    958:        if (cur == NULL) {
                    959:            fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26      daniel    960:            xmlFree(ret);
                    961:            xmlFree(ret->table);
1.15      daniel    962:            return(NULL);
                    963:        }
                    964:        ret->table[i] = cur;
1.4       daniel    965:        cur->type = attr->type;
                    966:        cur->def = attr->def;
                    967:        cur->tree = xmlCopyEnumeration(attr->tree);
                    968:        if (attr->elem != NULL)
                    969:            cur->elem = xmlStrdup(attr->elem);
                    970:        else
                    971:            cur->elem = NULL;
                    972:        if (attr->name != NULL)
                    973:            cur->name = xmlStrdup(attr->name);
                    974:        else
                    975:            cur->name = NULL;
                    976:        if (attr->defaultValue != NULL)
                    977:            cur->defaultValue = xmlStrdup(attr->defaultValue);
                    978:        else
                    979:            cur->defaultValue = NULL;
1.15      daniel    980:        /* NEED to rebuild the next chain !!!!!! */
1.4       daniel    981:     }
                    982:     return(ret);
                    983: }
                    984: 
                    985: /**
                    986:  * xmlDumpAttributeTable:
1.9       daniel    987:  * @buf:  the XML buffer output
1.4       daniel    988:  * @table:  An attribute table
                    989:  *
                    990:  * This will dump the content of the attribute table as an XML DTD definition
                    991:  */
                    992: void
1.8       daniel    993: xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1.4       daniel    994:     int i;
                    995:     xmlAttributePtr cur;
                    996: 
                    997:     if (table == NULL) return;
                    998: 
                    999:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel   1000:         cur = table->table[i];
1.8       daniel   1001:        xmlBufferWriteChar(buf, "<!ATTLIST ");
                   1002:        xmlBufferWriteCHAR(buf, cur->elem);
                   1003:        xmlBufferWriteChar(buf, " ");
                   1004:        xmlBufferWriteCHAR(buf, cur->name);
1.4       daniel   1005:         switch (cur->type) {
                   1006:             case XML_ATTRIBUTE_CDATA:
1.8       daniel   1007:                xmlBufferWriteChar(buf, " CDATA");
1.4       daniel   1008:                 break;
                   1009:             case XML_ATTRIBUTE_ID:
1.8       daniel   1010:                xmlBufferWriteChar(buf, " ID");
1.4       daniel   1011:                 break;
                   1012:             case XML_ATTRIBUTE_IDREF:
1.8       daniel   1013:                xmlBufferWriteChar(buf, " IDREF");
1.4       daniel   1014:                 break;
                   1015:             case XML_ATTRIBUTE_IDREFS:
1.8       daniel   1016:                xmlBufferWriteChar(buf, " IDREFS");
1.4       daniel   1017:                 break;
                   1018:             case XML_ATTRIBUTE_ENTITY:
1.8       daniel   1019:                xmlBufferWriteChar(buf, " ENTITY");
1.4       daniel   1020:                 break;
                   1021:             case XML_ATTRIBUTE_ENTITIES:
1.8       daniel   1022:                xmlBufferWriteChar(buf, " ENTITIES");
1.4       daniel   1023:                 break;
                   1024:             case XML_ATTRIBUTE_NMTOKEN:
1.8       daniel   1025:                xmlBufferWriteChar(buf, " NMTOKEN");
1.4       daniel   1026:                 break;
                   1027:             case XML_ATTRIBUTE_NMTOKENS:
1.8       daniel   1028:                xmlBufferWriteChar(buf, " NMTOKENS");
1.4       daniel   1029:                 break;
                   1030:             case XML_ATTRIBUTE_ENUMERATION:
1.18      daniel   1031:                 xmlBufferWriteChar(buf, " (");
                   1032:                xmlDumpEnumeration(buf, cur->tree);
1.4       daniel   1033:                 break;
                   1034:             case XML_ATTRIBUTE_NOTATION:
1.18      daniel   1035:                 xmlBufferWriteChar(buf, " NOTATION (");
                   1036:                xmlDumpEnumeration(buf, cur->tree);
1.4       daniel   1037:                 break;
                   1038:            default:
                   1039:                fprintf(stderr,
                   1040:                    "xmlDumpAttributeTable: internal: unknown type %d\n",
                   1041:                        cur->type);
                   1042:        }
                   1043:         switch (cur->def) {
                   1044:             case XML_ATTRIBUTE_NONE:
                   1045:                 break;
                   1046:             case XML_ATTRIBUTE_REQUIRED:
1.8       daniel   1047:                xmlBufferWriteChar(buf, " #REQUIRED");
1.4       daniel   1048:                 break;
                   1049:             case XML_ATTRIBUTE_IMPLIED:
1.8       daniel   1050:                xmlBufferWriteChar(buf, " #IMPLIED");
1.4       daniel   1051:                 break;
                   1052:             case XML_ATTRIBUTE_FIXED:
1.17      daniel   1053:                xmlBufferWriteChar(buf, " #FIXED");
1.4       daniel   1054:                 break;
                   1055:            default:
                   1056:                fprintf(stderr,
                   1057:                    "xmlDumpAttributeTable: internal: unknown default %d\n",
                   1058:                        cur->def);
                   1059:         }
1.17      daniel   1060:        if (cur->defaultValue != NULL) {
                   1061:            xmlBufferWriteChar(buf, " ");
                   1062:            xmlBufferWriteQuotedString(buf, cur->defaultValue);
                   1063:        }
1.8       daniel   1064:         xmlBufferWriteChar(buf, ">\n");
1.5       daniel   1065:     }
                   1066: }
                   1067: 
                   1068: /************************************************************************
                   1069:  *                                                                     *
                   1070:  *                             NOTATIONs                               *
                   1071:  *                                                                     *
                   1072:  ************************************************************************/
                   1073: /**
                   1074:  * xmlCreateNotationTable:
                   1075:  *
                   1076:  * create and initialize an empty notation hash table.
                   1077:  *
1.6       daniel   1078:  * Returns the xmlNotationTablePtr just created or NULL in case
1.5       daniel   1079:  *                of error.
                   1080:  */
                   1081: xmlNotationTablePtr
                   1082: xmlCreateNotationTable(void) {
                   1083:     xmlNotationTablePtr ret;
                   1084: 
                   1085:     ret = (xmlNotationTablePtr) 
1.26      daniel   1086:          xmlMalloc(sizeof(xmlNotationTable));
1.5       daniel   1087:     if (ret == NULL) {
1.26      daniel   1088:         fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12      daniel   1089:                (long)sizeof(xmlNotationTable));
1.5       daniel   1090:         return(NULL);
                   1091:     }
                   1092:     ret->max_notations = XML_MIN_NOTATION_TABLE;
                   1093:     ret->nb_notations = 0;
1.15      daniel   1094:     ret->table = (xmlNotationPtr *) 
1.26      daniel   1095:          xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
1.5       daniel   1096:     if (ret == NULL) {
1.26      daniel   1097:         fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12      daniel   1098:                ret->max_notations * (long)sizeof(xmlNotation));
1.26      daniel   1099:        xmlFree(ret);
1.5       daniel   1100:         return(NULL);
                   1101:     }
                   1102:     return(ret);
                   1103: }
                   1104: 
                   1105: 
                   1106: /**
                   1107:  * xmlAddNotationDecl:
1.6       daniel   1108:  * @dtd:  pointer to the DTD
1.16      daniel   1109:  * @ctxt:  the validation context
1.5       daniel   1110:  * @name:  the entity name
1.6       daniel   1111:  * @PublicID:  the public identifier or NULL
                   1112:  * @SystemID:  the system identifier or NULL
1.5       daniel   1113:  *
                   1114:  * Register a new notation declaration
                   1115:  *
1.6       daniel   1116:  * Returns NULL if not, othervise the entity
1.5       daniel   1117:  */
                   1118: xmlNotationPtr
1.16      daniel   1119: xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
                   1120:                    const CHAR *PublicID, const CHAR *SystemID) {
1.5       daniel   1121:     xmlNotationPtr ret, cur;
                   1122:     xmlNotationTablePtr table;
                   1123:     int i;
                   1124: 
                   1125:     if (dtd == NULL) {
                   1126:         fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
                   1127:        return(NULL);
                   1128:     }
                   1129:     if (name == NULL) {
                   1130:         fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
                   1131:        return(NULL);
                   1132:     }
                   1133:     if ((PublicID == NULL) && (SystemID == NULL)) {
                   1134:         fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
                   1135:     }
                   1136: 
                   1137:     /*
                   1138:      * Create the Notation table if needed.
                   1139:      */
                   1140:     table = dtd->notations;
                   1141:     if (table == NULL) 
                   1142:         table = dtd->notations = xmlCreateNotationTable();
                   1143:     if (table == NULL) {
                   1144:        fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
                   1145:         return(NULL);
                   1146:     }
                   1147: 
                   1148:     /*
                   1149:      * Validity Check:
                   1150:      * Search the DTD for previous declarations of the ATTLIST
                   1151:      */
                   1152:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1153:         cur = table->table[i];
1.5       daniel   1154:        if (!xmlStrcmp(cur->name, name)) {
                   1155:            /*
                   1156:             * The notation is already defined in this Dtd.
                   1157:             */
                   1158:            fprintf(stderr,
                   1159:                    "xmlAddNotationDecl: %s already defined\n", name);
                   1160:        }
                   1161:     }
                   1162: 
                   1163:     /*
                   1164:      * Grow the table, if needed.
                   1165:      */
                   1166:     if (table->nb_notations >= table->max_notations) {
                   1167:         /*
                   1168:         * need more notations.
                   1169:         */
                   1170:        table->max_notations *= 2;
1.15      daniel   1171:        table->table = (xmlNotationPtr *) 
1.26      daniel   1172:            xmlRealloc(table->table, table->max_notations *
1.15      daniel   1173:                    sizeof(xmlNotationPtr));
1.13      daniel   1174:        if (table->table == NULL) {
1.5       daniel   1175:            fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
                   1176:            return(NULL);
                   1177:        }
                   1178:     }
1.26      daniel   1179:     ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15      daniel   1180:     if (ret == NULL) {
                   1181:        fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
                   1182:        return(NULL);
                   1183:     }
                   1184:     table->table[table->nb_notations] = ret;
1.5       daniel   1185: 
                   1186:     /*
                   1187:      * fill the structure.
                   1188:      */
                   1189:     ret->name = xmlStrdup(name);
                   1190:     if (SystemID != NULL)
                   1191:         ret->SystemID = xmlStrdup(SystemID);
                   1192:     else
                   1193:         ret->SystemID = NULL;
                   1194:     if (PublicID != NULL)
                   1195:         ret->PublicID = xmlStrdup(PublicID);
                   1196:     else
                   1197:         ret->PublicID = NULL;
                   1198:     table->nb_notations++;
                   1199: 
                   1200:     return(ret);
                   1201: }
                   1202: 
                   1203: /**
                   1204:  * xmlFreeNotation:
                   1205:  * @not:  A notation
                   1206:  *
                   1207:  * Deallocate the memory used by an notation definition
                   1208:  */
                   1209: void
                   1210: xmlFreeNotation(xmlNotationPtr nota) {
                   1211:     if (nota == NULL) return;
                   1212:     if (nota->name != NULL)
1.26      daniel   1213:        xmlFree((CHAR *) nota->name);
1.5       daniel   1214:     if (nota->PublicID != NULL)
1.26      daniel   1215:        xmlFree((CHAR *) nota->PublicID);
1.5       daniel   1216:     if (nota->SystemID != NULL)
1.26      daniel   1217:        xmlFree((CHAR *) nota->SystemID);
1.5       daniel   1218:     memset(nota, -1, sizeof(xmlNotation));
1.26      daniel   1219:     xmlFree(nota);
1.5       daniel   1220: }
                   1221: 
                   1222: /**
                   1223:  * xmlFreeNotationTable:
                   1224:  * @table:  An notation table
                   1225:  *
                   1226:  * Deallocate the memory used by an entities hash table.
                   1227:  */
                   1228: void
                   1229: xmlFreeNotationTable(xmlNotationTablePtr table) {
                   1230:     int i;
                   1231: 
                   1232:     if (table == NULL) return;
                   1233: 
                   1234:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1235:         xmlFreeNotation(table->table[i]);
1.5       daniel   1236:     }
1.26      daniel   1237:     xmlFree(table->table);
                   1238:     xmlFree(table);
1.5       daniel   1239: }
                   1240: 
                   1241: /**
                   1242:  * xmlCopyNotationTable:
                   1243:  * @table:  A notation table
                   1244:  *
                   1245:  * Build a copy of a notation table.
                   1246:  * 
1.6       daniel   1247:  * Returns the new xmlNotationTablePtr or NULL in case of error.
1.5       daniel   1248:  */
                   1249: xmlNotationTablePtr
                   1250: xmlCopyNotationTable(xmlNotationTablePtr table) {
                   1251:     xmlNotationTablePtr ret;
                   1252:     xmlNotationPtr cur, nota;
                   1253:     int i;
                   1254: 
1.26      daniel   1255:     ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
1.5       daniel   1256:     if (ret == NULL) {
                   1257:         fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
                   1258:        return(NULL);
                   1259:     }
1.26      daniel   1260:     ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
1.15      daniel   1261:                                          sizeof(xmlNotationPtr));
1.5       daniel   1262:     if (ret->table == NULL) {
                   1263:         fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26      daniel   1264:        xmlFree(ret);
1.5       daniel   1265:        return(NULL);
                   1266:     }
                   1267:     ret->max_notations = table->max_notations;
                   1268:     ret->nb_notations = table->nb_notations;
                   1269:     for (i = 0;i < ret->nb_notations;i++) {
1.26      daniel   1270:        cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15      daniel   1271:        if (cur == NULL) {
                   1272:            fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26      daniel   1273:            xmlFree(ret);
                   1274:            xmlFree(ret->table);
1.15      daniel   1275:            return(NULL);
                   1276:        }
                   1277:        ret->table[i] = cur;
                   1278:        nota = table->table[i];
1.5       daniel   1279:        if (nota->name != NULL)
                   1280:            cur->name = xmlStrdup(nota->name);
                   1281:        else
                   1282:            cur->name = NULL;
                   1283:        if (nota->PublicID != NULL)
                   1284:            cur->PublicID = xmlStrdup(nota->PublicID);
                   1285:        else
                   1286:            cur->PublicID = NULL;
                   1287:        if (nota->SystemID != NULL)
                   1288:            cur->SystemID = xmlStrdup(nota->SystemID);
                   1289:        else
                   1290:            cur->SystemID = NULL;
                   1291:     }
                   1292:     return(ret);
                   1293: }
                   1294: 
                   1295: /**
                   1296:  * xmlDumpNotationTable:
1.9       daniel   1297:  * @buf:  the XML buffer output
1.5       daniel   1298:  * @table:  A notation table
                   1299:  *
                   1300:  * This will dump the content of the notation table as an XML DTD definition
                   1301:  */
                   1302: void
1.8       daniel   1303: xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
1.5       daniel   1304:     int i;
                   1305:     xmlNotationPtr cur;
                   1306: 
                   1307:     if (table == NULL) return;
                   1308: 
                   1309:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1310:         cur = table->table[i];
1.8       daniel   1311:        xmlBufferWriteChar(buf, "<!NOTATION ");
                   1312:        xmlBufferWriteCHAR(buf, cur->name);
1.5       daniel   1313:        if (cur->PublicID != NULL) {
1.10      daniel   1314:            xmlBufferWriteChar(buf, " PUBLIC ");
                   1315:            xmlBufferWriteQuotedString(buf, cur->PublicID);
1.5       daniel   1316:            if (cur->SystemID != NULL) {
1.8       daniel   1317:                xmlBufferWriteChar(buf, " ");
                   1318:                xmlBufferWriteCHAR(buf, cur->SystemID);
1.5       daniel   1319:            }
                   1320:        } else {
1.8       daniel   1321:            xmlBufferWriteChar(buf, " SYSTEM ");
                   1322:            xmlBufferWriteCHAR(buf, cur->SystemID);
1.5       daniel   1323:        }
1.8       daniel   1324:         xmlBufferWriteChar(buf, " >\n");
1.2       daniel   1325:     }
                   1326: }
1.14      daniel   1327: 
                   1328: /************************************************************************
                   1329:  *                                                                     *
1.27      daniel   1330:  *                             IDs                                     *
1.21      daniel   1331:  *                                                                     *
                   1332:  ************************************************************************/
                   1333: /**
                   1334:  * xmlCreateIDTable:
                   1335:  *
                   1336:  * create and initialize an empty id hash table.
                   1337:  *
                   1338:  * Returns the xmlIDTablePtr just created or NULL in case
                   1339:  *                of error.
                   1340:  */
                   1341: xmlIDTablePtr
                   1342: xmlCreateIDTable(void) {
                   1343:     xmlIDTablePtr ret;
                   1344: 
                   1345:     ret = (xmlIDTablePtr) 
1.26      daniel   1346:          xmlMalloc(sizeof(xmlIDTable));
1.21      daniel   1347:     if (ret == NULL) {
1.26      daniel   1348:         fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21      daniel   1349:                (long)sizeof(xmlIDTable));
                   1350:         return(NULL);
                   1351:     }
                   1352:     ret->max_ids = XML_MIN_NOTATION_TABLE;
                   1353:     ret->nb_ids = 0;
                   1354:     ret->table = (xmlIDPtr *) 
1.26      daniel   1355:          xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
1.21      daniel   1356:     if (ret == NULL) {
1.26      daniel   1357:         fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21      daniel   1358:                ret->max_ids * (long)sizeof(xmlID));
1.26      daniel   1359:        xmlFree(ret);
1.21      daniel   1360:         return(NULL);
                   1361:     }
                   1362:     return(ret);
                   1363: }
                   1364: 
                   1365: 
                   1366: /**
                   1367:  * xmlAddID:
                   1368:  * @ctxt:  the validation context
                   1369:  * @doc:  pointer to the document
                   1370:  * @value:  the value name
                   1371:  * @attr:  the attribute holding the ID
                   1372:  *
                   1373:  * Register a new id declaration
                   1374:  *
                   1375:  * Returns NULL if not, othervise the new xmlIDPtr
                   1376:  */
                   1377: xmlIDPtr 
                   1378: xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
                   1379:          xmlAttrPtr attr) {
                   1380:     xmlIDPtr ret, cur;
                   1381:     xmlIDTablePtr table;
                   1382:     int i;
                   1383: 
                   1384:     if (doc == NULL) {
                   1385:         fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
                   1386:        return(NULL);
                   1387:     }
                   1388:     if (value == NULL) {
                   1389:         fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
                   1390:        return(NULL);
                   1391:     }
                   1392:     if (attr == NULL) {
                   1393:         fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
                   1394:        return(NULL);
                   1395:     }
                   1396: 
                   1397:     /*
                   1398:      * Create the ID table if needed.
                   1399:      */
                   1400:     table = doc->ids;
                   1401:     if (table == NULL) 
                   1402:         table = doc->ids = xmlCreateIDTable();
                   1403:     if (table == NULL) {
                   1404:        fprintf(stderr, "xmlAddID: Table creation failed!\n");
                   1405:         return(NULL);
                   1406:     }
                   1407: 
                   1408:     /*
                   1409:      * Validity Check:
                   1410:      * Search the DTD for previous declarations of the ATTLIST
                   1411:      */
                   1412:     for (i = 0;i < table->nb_ids;i++) {
                   1413:         cur = table->table[i];
                   1414:        if (!xmlStrcmp(cur->value, value)) {
                   1415:            /*
                   1416:             * The id is already defined in this Dtd.
                   1417:             */
                   1418:            VERROR(ctxt->userData, "ID %s already defined\n", value);
                   1419:            return(NULL);
                   1420:        }
                   1421:     }
                   1422: 
                   1423:     /*
                   1424:      * Grow the table, if needed.
                   1425:      */
                   1426:     if (table->nb_ids >= table->max_ids) {
                   1427:         /*
                   1428:         * need more ids.
                   1429:         */
                   1430:        table->max_ids *= 2;
                   1431:        table->table = (xmlIDPtr *) 
1.26      daniel   1432:            xmlRealloc(table->table, table->max_ids *
1.21      daniel   1433:                    sizeof(xmlIDPtr));
                   1434:        if (table->table == NULL) {
                   1435:            fprintf(stderr, "xmlAddID: out of memory\n");
                   1436:            return(NULL);
                   1437:        }
                   1438:     }
1.26      daniel   1439:     ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
1.21      daniel   1440:     if (ret == NULL) {
                   1441:        fprintf(stderr, "xmlAddID: out of memory\n");
                   1442:        return(NULL);
                   1443:     }
                   1444:     table->table[table->nb_ids] = ret;
                   1445: 
                   1446:     /*
                   1447:      * fill the structure.
                   1448:      */
                   1449:     ret->value = xmlStrdup(value);
                   1450:     ret->attr = attr;
                   1451:     table->nb_ids++;
                   1452: 
                   1453:     return(ret);
                   1454: }
                   1455: 
                   1456: /**
                   1457:  * xmlFreeID:
                   1458:  * @not:  A id
                   1459:  *
                   1460:  * Deallocate the memory used by an id definition
                   1461:  */
                   1462: void
                   1463: xmlFreeID(xmlIDPtr id) {
                   1464:     if (id == NULL) return;
                   1465:     if (id->value != NULL)
1.26      daniel   1466:        xmlFree((CHAR *) id->value);
1.21      daniel   1467:     memset(id, -1, sizeof(xmlID));
1.26      daniel   1468:     xmlFree(id);
1.21      daniel   1469: }
                   1470: 
                   1471: /**
                   1472:  * xmlFreeIDTable:
                   1473:  * @table:  An id table
                   1474:  *
                   1475:  * Deallocate the memory used by an ID hash table.
                   1476:  */
                   1477: void
                   1478: xmlFreeIDTable(xmlIDTablePtr table) {
                   1479:     int i;
                   1480: 
                   1481:     if (table == NULL) return;
                   1482: 
                   1483:     for (i = 0;i < table->nb_ids;i++) {
                   1484:         xmlFreeID(table->table[i]);
                   1485:     }
1.26      daniel   1486:     xmlFree(table->table);
                   1487:     xmlFree(table);
1.21      daniel   1488: }
                   1489: 
                   1490: /**
                   1491:  * xmlIsID
                   1492:  * @doc:  the document
                   1493:  * @elem:  the element carrying the attribute
                   1494:  * @attr:  the attribute
                   1495:  *
                   1496:  * Determine whether an attribute is of type ID. In case we have Dtd(s)
                   1497:  * then this is simple, otherwise we use an heuristic: name ID (upper
                   1498:  * or lowercase).
                   1499:  *
                   1500:  * Returns 0 or 1 depending on the lookup result
                   1501:  */
                   1502: int
                   1503: xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
                   1504:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
                   1505:         if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
                   1506:             ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
                   1507:            (attr->name[2] == 0)) return(1);
                   1508:     } else {
                   1509:        xmlAttributePtr attrDecl;
                   1510: 
                   1511:        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   1512:        if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   1513:            attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
                   1514:                                         attr->name);
                   1515: 
1.22      daniel   1516:         if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
1.21      daniel   1517:            return(1);
                   1518:     }
                   1519:     return(0);
                   1520: }
                   1521: 
1.22      daniel   1522: /**
                   1523:  * xmlGetID:
                   1524:  * @doc:  pointer to the document
                   1525:  * @ID:  the ID value
                   1526:  *
                   1527:  * Search the attribute declaring the given ID
                   1528:  *
                   1529:  * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
                   1530:  */
                   1531: xmlAttrPtr 
                   1532: xmlGetID(xmlDocPtr doc, const CHAR *ID) {
                   1533:     xmlIDPtr cur;
                   1534:     xmlIDTablePtr table;
                   1535:     int i;
                   1536: 
                   1537:     if (doc == NULL) {
                   1538:         fprintf(stderr, "xmlGetID: doc == NULL\n");
                   1539:        return(NULL);
                   1540:     }
                   1541: 
                   1542:     if (ID == NULL) {
                   1543:         fprintf(stderr, "xmlGetID: ID == NULL\n");
                   1544:        return(NULL);
                   1545:     }
                   1546: 
                   1547:     table = doc->ids;
                   1548:     if (table == NULL) 
                   1549:         return(NULL);
                   1550: 
                   1551:     /*
                   1552:      * Search the ID list.
                   1553:      */
                   1554:     for (i = 0;i < table->nb_ids;i++) {
                   1555:         cur = table->table[i];
                   1556:        if (!xmlStrcmp(cur->value, ID)) {
                   1557:            return(cur->attr);
                   1558:        }
                   1559:     }
                   1560:     return(NULL);
                   1561: }
                   1562: 
1.21      daniel   1563: /************************************************************************
                   1564:  *                                                                     *
1.27      daniel   1565:  *                             Refs                                    *
                   1566:  *                                                                     *
                   1567:  ************************************************************************/
                   1568: /**
                   1569:  * xmlCreateRefTable:
                   1570:  *
                   1571:  * create and initialize an empty ref hash table.
                   1572:  *
                   1573:  * Returns the xmlRefTablePtr just created or NULL in case
                   1574:  *                of error.
                   1575:  */
                   1576: xmlRefTablePtr
                   1577: xmlCreateRefTable(void) {
                   1578:     xmlRefTablePtr ret;
                   1579: 
                   1580:     ret = (xmlRefTablePtr) 
                   1581:          xmlMalloc(sizeof(xmlRefTable));
                   1582:     if (ret == NULL) {
                   1583:         fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
                   1584:                (long)sizeof(xmlRefTable));
                   1585:         return(NULL);
                   1586:     }
                   1587:     ret->max_refs = XML_MIN_NOTATION_TABLE;
                   1588:     ret->nb_refs = 0;
                   1589:     ret->table = (xmlRefPtr *) 
                   1590:          xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
                   1591:     if (ret == NULL) {
                   1592:         fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
                   1593:                ret->max_refs * (long)sizeof(xmlRef));
                   1594:        xmlFree(ret);
                   1595:         return(NULL);
                   1596:     }
                   1597:     return(ret);
                   1598: }
                   1599: 
                   1600: 
                   1601: /**
                   1602:  * xmlAddRef:
                   1603:  * @ctxt:  the validation context
                   1604:  * @doc:  pointer to the document
                   1605:  * @value:  the value name
                   1606:  * @attr:  the attribute holding the Ref
                   1607:  *
                   1608:  * Register a new ref declaration
                   1609:  *
                   1610:  * Returns NULL if not, othervise the new xmlRefPtr
                   1611:  */
                   1612: xmlRefPtr 
                   1613: xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
                   1614:          xmlAttrPtr attr) {
1.28      daniel   1615:     xmlRefPtr ret;
1.27      daniel   1616:     xmlRefTablePtr table;
                   1617: 
                   1618:     if (doc == NULL) {
                   1619:         fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
                   1620:        return(NULL);
                   1621:     }
                   1622:     if (value == NULL) {
                   1623:         fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
                   1624:        return(NULL);
                   1625:     }
                   1626:     if (attr == NULL) {
                   1627:         fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
                   1628:        return(NULL);
                   1629:     }
                   1630: 
                   1631:     /*
                   1632:      * Create the Ref table if needed.
                   1633:      */
                   1634:     table = doc->refs;
                   1635:     if (table == NULL) 
                   1636:         table = doc->refs = xmlCreateRefTable();
                   1637:     if (table == NULL) {
                   1638:        fprintf(stderr, "xmlAddRef: Table creation failed!\n");
                   1639:         return(NULL);
                   1640:     }
                   1641: 
                   1642:     /*
                   1643:      * Grow the table, if needed.
                   1644:      */
                   1645:     if (table->nb_refs >= table->max_refs) {
                   1646:         /*
                   1647:         * need more refs.
                   1648:         */
                   1649:        table->max_refs *= 2;
                   1650:        table->table = (xmlRefPtr *) 
                   1651:            xmlRealloc(table->table, table->max_refs *
                   1652:                    sizeof(xmlRefPtr));
                   1653:        if (table->table == NULL) {
                   1654:            fprintf(stderr, "xmlAddRef: out of memory\n");
                   1655:            return(NULL);
                   1656:        }
                   1657:     }
                   1658:     ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
                   1659:     if (ret == NULL) {
                   1660:        fprintf(stderr, "xmlAddRef: out of memory\n");
                   1661:        return(NULL);
                   1662:     }
                   1663:     table->table[table->nb_refs] = ret;
                   1664: 
                   1665:     /*
                   1666:      * fill the structure.
                   1667:      */
                   1668:     ret->value = xmlStrdup(value);
                   1669:     ret->attr = attr;
                   1670:     table->nb_refs++;
                   1671: 
                   1672:     return(ret);
                   1673: }
                   1674: 
                   1675: /**
                   1676:  * xmlFreeRef:
                   1677:  * @not:  A ref
                   1678:  *
                   1679:  * Deallocate the memory used by an ref definition
                   1680:  */
                   1681: void
                   1682: xmlFreeRef(xmlRefPtr ref) {
                   1683:     if (ref == NULL) return;
                   1684:     if (ref->value != NULL)
                   1685:        xmlFree((CHAR *) ref->value);
                   1686:     memset(ref, -1, sizeof(xmlRef));
                   1687:     xmlFree(ref);
                   1688: }
                   1689: 
                   1690: /**
                   1691:  * xmlFreeRefTable:
                   1692:  * @table:  An ref table
                   1693:  *
                   1694:  * Deallocate the memory used by an Ref hash table.
                   1695:  */
                   1696: void
                   1697: xmlFreeRefTable(xmlRefTablePtr table) {
                   1698:     int i;
                   1699: 
                   1700:     if (table == NULL) return;
                   1701: 
                   1702:     for (i = 0;i < table->nb_refs;i++) {
                   1703:         xmlFreeRef(table->table[i]);
                   1704:     }
                   1705:     xmlFree(table->table);
                   1706:     xmlFree(table);
                   1707: }
                   1708: 
                   1709: /**
                   1710:  * xmlIsRef
                   1711:  * @doc:  the document
                   1712:  * @elem:  the element carrying the attribute
                   1713:  * @attr:  the attribute
                   1714:  *
                   1715:  * Determine whether an attribute is of type Ref. In case we have Dtd(s)
                   1716:  * then this is simple, otherwise we use an heuristic: name Ref (upper
                   1717:  * or lowercase).
                   1718:  *
                   1719:  * Returns 0 or 1 depending on the lookup result
                   1720:  */
                   1721: int
                   1722: xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
                   1723:     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
                   1724:         return(0);
                   1725:        /*******************
                   1726:         if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
                   1727:             ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
                   1728:            (attr->name[2] == 0)) return(1);
                   1729:         *******************/
                   1730:     } else {
                   1731:        xmlAttributePtr attrDecl;
                   1732: 
                   1733:        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   1734:        if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   1735:            attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
                   1736:                                         attr->name);
                   1737: 
                   1738:         if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
                   1739:            return(1);
                   1740:     }
                   1741:     return(0);
                   1742: }
                   1743: 
                   1744: /**
                   1745:  * xmlGetRef:
                   1746:  * @doc:  pointer to the document
                   1747:  * @Ref:  the Ref value
                   1748:  *
                   1749:  * Search the attribute declaring the given Ref
                   1750:  *
                   1751:  * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
                   1752:  */
                   1753: xmlAttrPtr 
                   1754: xmlGetRef(xmlDocPtr doc, const CHAR *Ref) {
                   1755:     xmlRefPtr cur;
                   1756:     xmlRefTablePtr table;
                   1757:     int i;
                   1758: 
                   1759:     if (doc == NULL) {
                   1760:         fprintf(stderr, "xmlGetRef: doc == NULL\n");
                   1761:        return(NULL);
                   1762:     }
                   1763: 
                   1764:     if (Ref == NULL) {
                   1765:         fprintf(stderr, "xmlGetRef: Ref == NULL\n");
                   1766:        return(NULL);
                   1767:     }
                   1768: 
                   1769:     table = doc->refs;
                   1770:     if (table == NULL) 
                   1771:         return(NULL);
                   1772: 
                   1773:     /*
                   1774:      * Search the Ref list.
                   1775:      */
                   1776:     for (i = 0;i < table->nb_refs;i++) {
                   1777:         cur = table->table[i];
                   1778:        if (!xmlStrcmp(cur->value, Ref)) {
                   1779:            return(cur->attr);
                   1780:        }
                   1781:     }
                   1782:     return(NULL);
                   1783: }
                   1784: 
                   1785: /************************************************************************
                   1786:  *                                                                     *
1.14      daniel   1787:  *             Routines for validity checking                          *
                   1788:  *                                                                     *
                   1789:  ************************************************************************/
                   1790: 
                   1791: /**
                   1792:  * xmlGetDtdElementDesc:
                   1793:  * @dtd:  a pointer to the DtD to search
                   1794:  * @name:  the element name
                   1795:  *
                   1796:  * Search the Dtd for the description of this element
                   1797:  *
                   1798:  * returns the xmlElementPtr if found or NULL
                   1799:  */
                   1800: 
                   1801: xmlElementPtr
                   1802: xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
                   1803:     xmlElementTablePtr table;
                   1804:     xmlElementPtr cur;
                   1805:     int i;
                   1806: 
                   1807:     if (dtd == NULL) return(NULL);
                   1808:     if (dtd->elements == NULL) return(NULL);
                   1809:     table = dtd->elements;
                   1810: 
                   1811:     for (i = 0;i < table->nb_elements;i++) {
1.15      daniel   1812:         cur = table->table[i];
1.14      daniel   1813:        if (!xmlStrcmp(cur->name, name))
                   1814:            return(cur);
                   1815:     }
                   1816:     return(NULL);
                   1817: }
                   1818: 
                   1819: /**
                   1820:  * xmlGetDtdAttrDesc:
                   1821:  * @dtd:  a pointer to the DtD to search
1.15      daniel   1822:  * @elem:  the element name
1.14      daniel   1823:  * @name:  the attribute name
                   1824:  *
1.15      daniel   1825:  * Search the Dtd for the description of this attribute on
                   1826:  * this element.
1.14      daniel   1827:  *
                   1828:  * returns the xmlAttributePtr if found or NULL
                   1829:  */
                   1830: 
                   1831: xmlAttributePtr
1.15      daniel   1832: xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
1.14      daniel   1833:     xmlAttributeTablePtr table;
                   1834:     xmlAttributePtr cur;
                   1835:     int i;
                   1836: 
                   1837:     if (dtd == NULL) return(NULL);
                   1838:     if (dtd->attributes == NULL) return(NULL);
                   1839:     table = dtd->attributes;
                   1840: 
                   1841:     for (i = 0;i < table->nb_attributes;i++) {
1.15      daniel   1842:         cur = table->table[i];
                   1843:        if ((!xmlStrcmp(cur->name, name)) &&
                   1844:            (!xmlStrcmp(cur->elem, elem)))
1.14      daniel   1845:            return(cur);
                   1846:     }
                   1847:     return(NULL);
                   1848: }
                   1849: 
                   1850: /**
                   1851:  * xmlGetDtdNotationDesc:
                   1852:  * @dtd:  a pointer to the DtD to search
                   1853:  * @name:  the notation name
                   1854:  *
                   1855:  * Search the Dtd for the description of this notation
                   1856:  *
                   1857:  * returns the xmlNotationPtr if found or NULL
                   1858:  */
                   1859: 
                   1860: xmlNotationPtr
                   1861: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
                   1862:     xmlNotationTablePtr table;
                   1863:     xmlNotationPtr cur;
                   1864:     int i;
                   1865: 
                   1866:     if (dtd == NULL) return(NULL);
                   1867:     if (dtd->notations == NULL) return(NULL);
                   1868:     table = dtd->notations;
                   1869: 
                   1870:     for (i = 0;i < table->nb_notations;i++) {
1.15      daniel   1871:         cur = table->table[i];
1.14      daniel   1872:        if (!xmlStrcmp(cur->name, name))
                   1873:            return(cur);
                   1874:     }
                   1875:     return(NULL);
                   1876: }
                   1877: 
                   1878: /**
1.23      daniel   1879:  * xmlValidateNotationUse:
                   1880:  * @ctxt:  the validation context
                   1881:  * @doc:  the document
                   1882:  * @notationName:  the notation name to check
                   1883:  *
                   1884:  * Validate that the given mame match a notation declaration.
                   1885:  * - [ VC: Notation Declared ]
                   1886:  *
                   1887:  * returns 1 if valid or 0 otherwise
                   1888:  */
                   1889: 
                   1890: int
                   1891: xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
                   1892:                        const CHAR *notationName) {
                   1893:     xmlNotationPtr notaDecl;
                   1894:     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
                   1895: 
                   1896:     notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
                   1897:     if ((notaDecl == NULL) && (doc->extSubset != NULL))
                   1898:        notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
                   1899: 
                   1900:     if (notaDecl == NULL) {
                   1901:        VERROR(ctxt->userData, "NOTATION %s is not declared\n",
                   1902:               notationName);
                   1903:        return(0);
                   1904:     }
                   1905:     return(1);
                   1906: }
                   1907: 
                   1908: /**
1.18      daniel   1909:  * xmlIsMixedElement
                   1910:  * @doc:  the document
                   1911:  * @name:  the element name
                   1912:  *
                   1913:  * Search in the DtDs whether an element accept Mixed content (or ANY)
                   1914:  * basically if it is supposed to accept text childs
                   1915:  *
                   1916:  * returns 0 if no, 1 if yes, and -1 if no element description is available
                   1917:  */
                   1918: 
                   1919: int
                   1920: xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
                   1921:     xmlElementPtr elemDecl;
                   1922: 
                   1923:     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
                   1924: 
                   1925:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
                   1926:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   1927:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
                   1928:     if (elemDecl == NULL) return(-1);
                   1929:     switch (elemDecl->type) {
                   1930:        case XML_ELEMENT_TYPE_ELEMENT:
                   1931:            return(0);
                   1932:         case XML_ELEMENT_TYPE_EMPTY:
                   1933:            /*
                   1934:             * return 1 for EMPTY since we want VC error to pop up
                   1935:             * on <empty>     </empty> for example
                   1936:             */
                   1937:        case XML_ELEMENT_TYPE_ANY:
                   1938:        case XML_ELEMENT_TYPE_MIXED:
                   1939:            return(1);
                   1940:     }
                   1941:     return(1);
                   1942: }
                   1943: 
                   1944: /**
1.16      daniel   1945:  * xmlValidateNameValue:
                   1946:  * @value:  an Name value
                   1947:  *
                   1948:  * Validate that the given value match Name production
                   1949:  *
                   1950:  * returns 1 if valid or 0 otherwise
                   1951:  */
                   1952: 
                   1953: int
                   1954: xmlValidateNameValue(const CHAR *value) {
                   1955:     const CHAR *cur;
                   1956: 
                   1957:     if (value == NULL) return(0);
                   1958:     cur = value;
                   1959:     
                   1960:     if (!IS_LETTER(*cur) && (*cur != '_') &&
                   1961:         (*cur != ':')) {
                   1962:        return(0);
                   1963:     }
                   1964: 
                   1965:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   1966:            (*cur == '.') || (*cur == '-') ||
                   1967:           (*cur == '_') || (*cur == ':') || 
                   1968:           (IS_COMBINING(*cur)) ||
                   1969:           (IS_EXTENDER(*cur)))
                   1970:           cur++;
                   1971: 
                   1972:     if (*cur != 0) return(0);
                   1973: 
                   1974:     return(1);
                   1975: }
                   1976: 
                   1977: /**
                   1978:  * xmlValidateNamesValue:
                   1979:  * @value:  an Names value
                   1980:  *
                   1981:  * Validate that the given value match Names production
                   1982:  *
                   1983:  * returns 1 if valid or 0 otherwise
                   1984:  */
                   1985: 
                   1986: int
                   1987: xmlValidateNamesValue(const CHAR *value) {
                   1988:     const CHAR *cur;
                   1989: 
                   1990:     if (value == NULL) return(0);
                   1991:     cur = value;
                   1992:     
                   1993:     if (!IS_LETTER(*cur) && (*cur != '_') &&
                   1994:         (*cur != ':')) {
                   1995:        return(0);
                   1996:     }
                   1997: 
                   1998:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   1999:            (*cur == '.') || (*cur == '-') ||
                   2000:           (*cur == '_') || (*cur == ':') || 
                   2001:           (IS_COMBINING(*cur)) ||
                   2002:           (IS_EXTENDER(*cur)))
                   2003:           cur++;
                   2004: 
                   2005:     while (IS_BLANK(*cur)) {
                   2006:        while (IS_BLANK(*cur)) cur++;
                   2007: 
                   2008:        if (!IS_LETTER(*cur) && (*cur != '_') &&
                   2009:            (*cur != ':')) {
                   2010:            return(0);
                   2011:        }
                   2012: 
                   2013:        while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2014:               (*cur == '.') || (*cur == '-') ||
                   2015:               (*cur == '_') || (*cur == ':') || 
                   2016:               (IS_COMBINING(*cur)) ||
                   2017:               (IS_EXTENDER(*cur)))
                   2018:               cur++;
                   2019:     }
                   2020: 
                   2021:     if (*cur != 0) return(0);
                   2022: 
                   2023:     return(1);
                   2024: }
                   2025: 
                   2026: /**
                   2027:  * xmlValidateNmtokenValue:
                   2028:  * @value:  an Mntoken value
                   2029:  *
                   2030:  * Validate that the given value match Nmtoken production
                   2031:  *
                   2032:  * [ VC: Name Token ]
                   2033:  * 
                   2034:  * returns 1 if valid or 0 otherwise
                   2035:  */
                   2036: 
                   2037: int
                   2038: xmlValidateNmtokenValue(const CHAR *value) {
                   2039:     const CHAR *cur;
                   2040: 
                   2041:     if (value == NULL) return(0);
                   2042:     cur = value;
                   2043:     
                   2044:     if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
                   2045:         (*cur != '.') && (*cur != '-') &&
                   2046:         (*cur != '_') && (*cur != ':') && 
                   2047:         (!IS_COMBINING(*cur)) &&
                   2048:         (!IS_EXTENDER(*cur)))
                   2049:        return(0);
                   2050: 
                   2051:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                   2052:            (*cur == '.') || (*cur == '-') ||
                   2053:           (*cur == '_') || (*cur == ':') || 
                   2054:           (IS_COMBINING(*cur)) ||
                   2055:           (IS_EXTENDER(*cur)))
                   2056:           cur++;
                   2057: 
                   2058:     if (*cur != 0) return(0);
                   2059: 
                   2060:     return(1);
                   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
                   2076: xmlValidateNmtokensValue(const CHAR *value) {
                   2077:     const CHAR *cur;
                   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
                   2168: xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
                   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;
                   2285:         const CHAR *name;
                   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
                   2346:  *
                   2347:  * Try to validate a single attribute for an element
                   2348:  * basically it * does the following checks as described by the
                   2349:  * XML-1.0 recommendation:
1.18      daniel   2350:  *  - [ VC: Attribute Value Type ]
                   2351:  *  - [ VC: Fixed Attribute Default ]
1.14      daniel   2352:  *  - [ VC: Entity Name ]
                   2353:  *  - [ VC: Name Token ]
                   2354:  *  - [ VC: ID ]
                   2355:  *  - [ VC: IDREF ]
                   2356:  *  - [ VC: Entity Name ]
1.16      daniel   2357:  *  - [ VC: Notation Attributes ]
1.14      daniel   2358:  *
                   2359:  * The ID/IDREF uniqueness and matching are done separately
                   2360:  *
                   2361:  * returns 1 if valid or 0 otherwise
                   2362:  */
                   2363: 
                   2364: int
1.16      daniel   2365: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18      daniel   2366:                         xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
1.24      daniel   2367:     /* xmlElementPtr elemDecl; */
1.18      daniel   2368:     xmlAttributePtr attrDecl;
                   2369:     int val;
                   2370:     int ret = 1;
                   2371: 
1.14      daniel   2372:     CHECK_DTD;
1.18      daniel   2373:     if ((elem == NULL) || (elem->name == NULL)) return(0);
                   2374:     if ((attr == NULL) || (attr->name == NULL)) return(0);
                   2375: 
                   2376:     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
                   2377:     if ((attrDecl == NULL) && (doc->extSubset != NULL))
                   2378:        attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
                   2379: 
1.14      daniel   2380: 
1.18      daniel   2381:     /* Validity Constraint: Attribute Value Type */
                   2382:     if (attrDecl == NULL) {
                   2383:        VERROR(ctxt->userData,
                   2384:               "No declaration for attribute %s on element %s\n",
                   2385:               attr->name, elem->name);
                   2386:        return(0);
                   2387:     }
                   2388:     val = xmlValidateAttributeValue(attrDecl->type, value);
                   2389:     if (val == 0) {
                   2390:        VERROR(ctxt->userData, 
                   2391:           "Syntax of value for attribute %s on %s is not valid\n",
                   2392:               attr->name, elem->name);
                   2393:         ret = 0;
1.22      daniel   2394:     }
                   2395: 
                   2396:     /* Validity Constraint: ID uniqueness */
                   2397:     if (attrDecl->type == XML_ATTRIBUTE_ID) {
                   2398:         xmlAddID(ctxt, doc, value, attr);
1.18      daniel   2399:     }
                   2400: 
1.28      daniel   2401:     if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
                   2402:         xmlAddRef(ctxt, doc, value, attr);
                   2403:     }
                   2404: 
1.18      daniel   2405:     /* Validity Constraint: Notation Attributes */
                   2406:     if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
                   2407:         xmlEnumerationPtr tree = attrDecl->tree;
                   2408:         xmlNotationPtr nota;
                   2409: 
                   2410:         /* First check that the given NOTATION was declared */
                   2411:        nota = xmlGetDtdNotationDesc(doc->intSubset, value);
                   2412:        if (nota == NULL)
                   2413:            nota = xmlGetDtdNotationDesc(doc->extSubset, value);
                   2414:        
                   2415:        if (nota == NULL) {
                   2416:            VERROR(ctxt->userData, 
                   2417:        "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
                   2418:                   value, attr->name, elem->name);
                   2419:            ret = 0;
                   2420:         }
                   2421: 
                   2422:        /* Second, verify that it's among the list */
                   2423:        while (tree != NULL) {
                   2424:            if (!xmlStrcmp(tree->name, value)) break;
                   2425:            tree = tree->next;
                   2426:        }
                   2427:        if (tree == NULL) {
                   2428:            VERROR(ctxt->userData, 
                   2429:    "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
                   2430:                   value, attr->name, elem->name);
                   2431:            ret = 0;
                   2432:        }
                   2433:     }
                   2434: 
                   2435:     /* Validity Constraint: Enumeration */
                   2436:     if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
                   2437:         xmlEnumerationPtr tree = attrDecl->tree;
                   2438:        while (tree != NULL) {
                   2439:            if (!xmlStrcmp(tree->name, value)) break;
                   2440:            tree = tree->next;
                   2441:        }
                   2442:        if (tree == NULL) {
                   2443:            VERROR(ctxt->userData, 
                   2444:        "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
                   2445:                   value, attr->name, elem->name);
                   2446:            ret = 0;
                   2447:        }
                   2448:     }
                   2449: 
                   2450:     /* Fixed Attribute Default */
                   2451:     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
                   2452:         (xmlStrcmp(attrDecl->defaultValue, value))) {
                   2453:        VERROR(ctxt->userData, 
                   2454:           "Value for attribute %s on %s must be \"%s\"\n",
                   2455:               attr->name, elem->name, attrDecl->defaultValue);
                   2456:         ret = 0;
                   2457:     }
                   2458: 
1.24      daniel   2459:     /********
1.18      daniel   2460:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
                   2461:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   2462:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
                   2463:     if (elemDecl == NULL) {
                   2464:        return(0);
                   2465:     }
1.24      daniel   2466:      ********/
1.18      daniel   2467:     return(ret);
                   2468: }
                   2469: 
                   2470: int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2471:                                  xmlElementContentPtr cont);
                   2472: 
                   2473: /**
                   2474:  * xmlValidateElementTypeExpr:
                   2475:  * @ctxt:  the validation context
                   2476:  * @child:  pointer to the child list
                   2477:  * @cont:  pointer to the content declaration
                   2478:  *
                   2479:  * Try to validate the content of an element of type element
                   2480:  * but don't handle the occurence factor
                   2481:  *
                   2482:  * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
                   2483:  *         also update child value in-situ.
                   2484:  */
                   2485: 
                   2486: int
                   2487: xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2488:                           xmlElementContentPtr cont) {
                   2489:     xmlNodePtr cur;
                   2490:     int ret = 1;
                   2491: 
                   2492:     if (cont == NULL) return(-1);
                   2493:     while (*child != NULL) {
                   2494:         if ((*child)->type == XML_PI_NODE) {
                   2495:            *child = (*child)->next;
                   2496:            continue;
                   2497:        }
                   2498:         if ((*child)->type == XML_COMMENT_NODE) {
                   2499:            *child = (*child)->next;
                   2500:            continue;
                   2501:        }
                   2502:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2503:            return(-1);
                   2504:        }
                   2505:        break;
                   2506:     }
                   2507:     switch (cont->type) {
                   2508:        case XML_ELEMENT_CONTENT_PCDATA:
                   2509:            /* Internal error !!! */
                   2510:            fprintf(stderr, "Internal: MIXED struct bad\n");
                   2511:            return(-1);
                   2512:        case XML_ELEMENT_CONTENT_ELEMENT:
1.20      daniel   2513:            if (*child == NULL) return(0);
1.18      daniel   2514:            ret = (!xmlStrcmp((*child)->name, cont->name));
                   2515:            if (ret == 1)
                   2516:                *child = (*child)->next;
                   2517:            return(ret);
                   2518:        case XML_ELEMENT_CONTENT_OR:
                   2519:            cur = *child;
                   2520:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
                   2521:            if (ret == -1) return(-1);
                   2522:            if (ret == 1) {
                   2523:                 return(1);
                   2524:            }
                   2525:            /* rollback and retry the other path */
                   2526:            *child = cur;
                   2527:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
                   2528:            if (ret == -1) return(-1);
                   2529:            if (ret == 0) {
                   2530:                *child = cur;
                   2531:                return(0);
                   2532:            }
                   2533:            return(1);
                   2534:        case XML_ELEMENT_CONTENT_SEQ:
                   2535:            cur = *child;
                   2536:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
                   2537:            if (ret == -1) return(-1);
                   2538:            if (ret == 0) {
                   2539:                *child = cur;
                   2540:                return(0);
                   2541:            }
                   2542:            ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
                   2543:            if (ret == -1) return(-1);
                   2544:            if (ret == 0) {
                   2545:                *child = cur;
                   2546:                return(0);
                   2547:            }
                   2548:            return(1);
                   2549:     }
                   2550:     return(ret);
                   2551: }
                   2552: 
                   2553: /**
                   2554:  * xmlValidateElementTypeElement:
                   2555:  * @ctxt:  the validation context
                   2556:  * @child:  pointer to the child list
                   2557:  * @cont:  pointer to the content declaration
                   2558:  *
                   2559:  * Try to validate the content of an element of type element
                   2560:  * yeah, Yet Another Regexp Implementation, and recursive
                   2561:  *
                   2562:  * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
                   2563:  *         also update child and content values in-situ.
                   2564:  */
                   2565: 
                   2566: int
                   2567: xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
                   2568:                              xmlElementContentPtr cont) {
                   2569:     xmlNodePtr cur;
                   2570:     int ret = 1;
                   2571: 
                   2572:     if (cont == NULL) return(-1);
                   2573:     while (*child != NULL) {
                   2574:         if ((*child)->type == XML_PI_NODE) {
                   2575:            *child = (*child)->next;
                   2576:            continue;
                   2577:        }
                   2578:         if ((*child)->type == XML_COMMENT_NODE) {
                   2579:            *child = (*child)->next;
                   2580:            continue;
                   2581:        }
                   2582:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2583:            return(-1);
                   2584:        }
                   2585:        break;
                   2586:     }
                   2587:     cur = *child;
                   2588:     ret = xmlValidateElementTypeExpr(ctxt, child, cont);
                   2589:     if (ret == -1) return(-1);
                   2590:     switch (cont->ocur) {
                   2591:        case XML_ELEMENT_CONTENT_ONCE:
                   2592:            if (ret == 1) {
                   2593:                return(1);
                   2594:            }
                   2595:            *child = cur;
                   2596:            return(0);
                   2597:        case XML_ELEMENT_CONTENT_OPT:
                   2598:            if (ret == 0) {
                   2599:                *child = cur;
                   2600:                return(1);
                   2601:            }
1.19      daniel   2602:            break;
1.18      daniel   2603:        case XML_ELEMENT_CONTENT_MULT:
                   2604:            if (ret == 0) {
                   2605:                *child = cur;
1.19      daniel   2606:                break;
1.18      daniel   2607:            }
                   2608:            /* no break on purpose */
                   2609:        case XML_ELEMENT_CONTENT_PLUS:
                   2610:            if (ret == 0) {
                   2611:                *child = cur;
                   2612:                return(0);
                   2613:            }
                   2614:            do {
                   2615:                cur = *child;
                   2616:                ret = xmlValidateElementTypeExpr(ctxt, child, cont);
                   2617:            } while (ret == 1);
                   2618:            if (ret == -1) return(-1);
                   2619:            *child = cur;
1.19      daniel   2620:            break;
                   2621:     }
                   2622:     while (*child != NULL) {
                   2623:         if ((*child)->type == XML_PI_NODE) {
                   2624:            *child = (*child)->next;
                   2625:            continue;
                   2626:        }
                   2627:         if ((*child)->type == XML_COMMENT_NODE) {
                   2628:            *child = (*child)->next;
                   2629:            continue;
                   2630:        }
                   2631:        else if ((*child)->type != XML_ELEMENT_NODE) {
                   2632:            return(-1);
                   2633:        }
                   2634:        break;
                   2635:     }
                   2636:     return(1);
                   2637: }
                   2638: 
                   2639: /**
                   2640:  * xmlSprintfElementChilds:
                   2641:  * @buf:  an output buffer
                   2642:  * @content:  An element
                   2643:  * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
                   2644:  *
                   2645:  * This will dump the list of childs to the buffer
                   2646:  * Intended just for the debug routine
                   2647:  */
                   2648: void
                   2649: xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
                   2650:     xmlNodePtr cur;
                   2651: 
                   2652:     if (node == NULL) return;
                   2653:     if (glob) strcat(buf, "(");
                   2654:     cur = node->childs;
                   2655:     while (cur != NULL) {
                   2656:         switch (cur->type) {
                   2657:             case XML_ELEMENT_NODE:
1.23      daniel   2658:                 strcat(buf, (char *) cur->name);
1.19      daniel   2659:                 if (cur->next != NULL)
                   2660:                     strcat(buf, " ");
                   2661:                 break;
                   2662:             case XML_TEXT_NODE:
                   2663:             case XML_CDATA_SECTION_NODE:
                   2664:             case XML_ENTITY_REF_NODE:
                   2665:                 strcat(buf, "CDATA");
                   2666:                 if (cur->next != NULL)
                   2667:                     strcat(buf, " ");
                   2668:                 break;
                   2669:             case XML_ATTRIBUTE_NODE:
                   2670:             case XML_DOCUMENT_NODE:
                   2671:             case XML_DOCUMENT_TYPE_NODE:
                   2672:             case XML_DOCUMENT_FRAG_NODE:
                   2673:             case XML_NOTATION_NODE:
                   2674:                 strcat(buf, "???");
                   2675:                 if (cur->next != NULL)
                   2676:                     strcat(buf, " ");
                   2677:                 break;
                   2678:             case XML_ENTITY_NODE:
                   2679:             case XML_PI_NODE:
                   2680:             case XML_COMMENT_NODE:
                   2681:                 break;
                   2682:        }
                   2683:        cur = cur->next;
1.18      daniel   2684:     }
1.19      daniel   2685:     if (glob) strcat(buf, ")");
1.14      daniel   2686: }
                   2687: 
1.19      daniel   2688: 
1.14      daniel   2689: /**
                   2690:  * xmlValidateOneElement:
                   2691:  * @ctxt:  the validation context
                   2692:  * @doc:  a document instance
                   2693:  * @elem:  an element instance
                   2694:  *
                   2695:  * Try to validate a single element and it's attributes,
                   2696:  * basically it does the following checks as described by the
                   2697:  * XML-1.0 recommendation:
                   2698:  *  - [ VC: Element Valid ]
                   2699:  *  - [ VC: Required Attribute ]
                   2700:  * Then call xmlValidateOneAttribute() for each attribute present.
                   2701:  *
                   2702:  * The ID/IDREF checkings are done separately
                   2703:  *
                   2704:  * returns 1 if valid or 0 otherwise
                   2705:  */
                   2706: 
                   2707: int
1.16      daniel   2708: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18      daniel   2709:                       xmlNodePtr elem) {
                   2710:     xmlElementPtr elemDecl;
                   2711:     xmlElementContentPtr cont;
                   2712:     xmlNodePtr child;
                   2713:     int ret = 1;
                   2714:     const CHAR *name;
                   2715: 
1.14      daniel   2716:     CHECK_DTD;
                   2717: 
1.18      daniel   2718:     if ((elem == NULL) || (elem->name == NULL)) return(0);
                   2719: 
                   2720:     elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
                   2721:     if ((elemDecl == NULL) && (doc->extSubset != NULL))
                   2722:        elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
                   2723:     if (elemDecl == NULL) {
                   2724:        VERROR(ctxt->userData, "No declaration for element %s\n",
                   2725:               elem->name);
                   2726:        return(0);
                   2727:     }
                   2728: 
                   2729:     /* Check taht the element content matches the definition */
                   2730:     switch (elemDecl->type) {
                   2731:         case XML_ELEMENT_TYPE_EMPTY:
                   2732:            if (elem->childs != NULL) {
                   2733:                VERROR(ctxt->userData,
                   2734:               "Element %s was declared EMPTY this one has content\n",
                   2735:                       elem->name);
                   2736:                ret = 0;
                   2737:            }
                   2738:            break;
                   2739:         case XML_ELEMENT_TYPE_ANY:
                   2740:            /* I don't think anything is required then */
                   2741:            break;
                   2742:         case XML_ELEMENT_TYPE_MIXED:
                   2743:            /* Hum, this start to get messy */
                   2744:            child = elem->childs;
                   2745:            while (child != NULL) {
                   2746:                if (child->type == XML_ELEMENT_NODE) {
                   2747:                    name = child->name;
                   2748:                    cont = elemDecl->content;
                   2749:                    while (cont != NULL) {
                   2750:                        if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
                   2751:                            if (!xmlStrcmp(cont->name, name)) break;
                   2752:                        } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
                   2753:                           (cont->c1 != NULL) &&
                   2754:                           (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
                   2755:                            if (!xmlStrcmp(cont->c1->name, name)) break;
                   2756:                        } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
                   2757:                            (cont->c1 == NULL) ||
                   2758:                            (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
                   2759:                            /* Internal error !!! */
                   2760:                            fprintf(stderr, "Internal: MIXED struct bad\n");
                   2761:                            break;
                   2762:                        }
                   2763:                        cont = cont->c2;
                   2764:                    }
                   2765:                    if (cont == NULL) {
                   2766:                        VERROR(ctxt->userData,
                   2767:               "Element %s is not declared in %s list of possible childs\n",
                   2768:                               name, elem->name);
                   2769:                        ret = 0;
                   2770:                    }
                   2771:                }
                   2772:                child = child->next;
                   2773:            }
                   2774:            break;
                   2775:         case XML_ELEMENT_TYPE_ELEMENT:
                   2776:            child = elem->childs;
                   2777:            cont = elemDecl->content;
                   2778:            ret = xmlValidateElementTypeElement(ctxt, &child, cont);
1.19      daniel   2779:            if ((ret == 0) || (child != NULL)) {
                   2780:                char expr[1000];
                   2781:                char list[2000];
                   2782: 
                   2783:                expr[0] = 0;
                   2784:                xmlSprintfElementContent(expr, cont, 1);
                   2785:                list[0] = 0;
                   2786:                xmlSprintfElementChilds(list, elem, 1);
                   2787: 
1.18      daniel   2788:                VERROR(ctxt->userData,
1.19      daniel   2789:           "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
                   2790:                       elem->name, expr, list);
1.18      daniel   2791:                ret = 0;
                   2792:            }
                   2793:            break;
                   2794:     }
                   2795: 
1.24      daniel   2796:     /* TODO - [ VC: Required Attribute ] */
1.18      daniel   2797:     return(ret);
1.14      daniel   2798: }
                   2799: 
                   2800: /**
                   2801:  * xmlValidateRoot:
                   2802:  * @ctxt:  the validation context
                   2803:  * @doc:  a document instance
                   2804:  *
                   2805:  * Try to validate a the root element
                   2806:  * basically it does the following check as described by the
                   2807:  * XML-1.0 recommendation:
                   2808:  *  - [ VC: Root Element Type ]
                   2809:  * it doesn't try to recurse or apply other check to the element
                   2810:  *
                   2811:  * returns 1 if valid or 0 otherwise
                   2812:  */
                   2813: 
                   2814: int
                   2815: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
                   2816:     if (doc == NULL) return(0);
                   2817: 
                   2818:     if ((doc->intSubset == NULL) ||
                   2819:        (doc->intSubset->name == NULL)) {
                   2820:        VERROR(ctxt->userData, "Not valid: no DtD found\n");
                   2821:         return(0);
                   2822:     }
                   2823:     if ((doc->root == NULL) || (doc->root->name == NULL)) {
                   2824:        VERROR(ctxt->userData, "Not valid: no root element\n");
                   2825:         return(0);
                   2826:     }
                   2827:     if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
                   2828:        VERROR(ctxt->userData,
                   2829:               "Not valid: root and DtD name do not match %s and %s\n",
                   2830:               doc->root->name, doc->intSubset->name);
                   2831:        return(0);
                   2832:     }
                   2833:     return(1);
                   2834: }
                   2835: 
                   2836: 
                   2837: /**
                   2838:  * xmlValidateElement:
                   2839:  * @ctxt:  the validation context
                   2840:  * @doc:  a document instance
                   2841:  * @elem:  an element instance
                   2842:  *
                   2843:  * Try to validate the subtree under an element 
                   2844:  *
                   2845:  * returns 1 if valid or 0 otherwise
                   2846:  */
                   2847: 
                   2848: int
1.18      daniel   2849: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
1.27      daniel   2850:     xmlNodePtr child;
                   2851:     xmlAttrPtr attr;
                   2852:     CHAR *value;
                   2853:     int ret = 1;
                   2854: 
                   2855:     /* TODO xmlValidateElement */
                   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: 

Webmaster