valid.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:102k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

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