Annotation of XML/valid.c, revision 1.51

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

Webmaster