blob: bc66ac577976609789b375bc49e3fc990ea818db [file] [log] [blame]
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001/*
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
Daniel Veillard7f7d1111999-09-22 09:46:25 +000010#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000011#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000012#else
13#include "config.h"
14#endif
15
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000016#include <stdio.h>
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000017#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018
19#ifdef HAVE_STDLIB_H
20#include <stdlib.h>
21#endif
22
Daniel Veillard361d8452000-04-03 19:48:13 +000023#include <libxml/xmlmemory.h>
24#include <libxml/valid.h>
25#include <libxml/parser.h>
26#include <libxml/parserInternals.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000027
Daniel Veillardcf461992000-03-14 18:30:20 +000028/*
29 * Generic function for accessing stacks in the Validity Context
30 */
31
32#define PUSH_AND_POP(scope, type, name) \
33scope int name##VPush(xmlValidCtxtPtr ctxt, type value) { \
34 if (ctxt->name##Nr >= ctxt->name##Max) { \
35 ctxt->name##Max *= 2; \
36 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
37 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
38 if (ctxt->name##Tab == NULL) { \
39 fprintf(stderr, "realloc failed !\n"); \
40 return(0); \
41 } \
42 } \
43 ctxt->name##Tab[ctxt->name##Nr] = value; \
44 ctxt->name = value; \
45 return(ctxt->name##Nr++); \
46} \
47scope type name##VPop(xmlValidCtxtPtr ctxt) { \
48 type ret; \
49 if (ctxt->name##Nr <= 0) return(0); \
50 ctxt->name##Nr--; \
51 if (ctxt->name##Nr > 0) \
52 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
53 else \
54 ctxt->name = NULL; \
55 ret = ctxt->name##Tab[ctxt->name##Nr]; \
56 ctxt->name##Tab[ctxt->name##Nr] = 0; \
57 return(ret); \
58} \
59
60PUSH_AND_POP(static, xmlNodePtr, node)
61
62/* #define DEBUG_VALID_ALGO */
63
64#ifdef DEBUG_VALID_ALGO
65void xmlValidPrintNodeList(xmlNodePtr cur) {
66 if (cur == NULL)
67 fprintf(stderr, "null ");
68 while (cur != NULL) {
69 switch (cur->type) {
70 case XML_ELEMENT_NODE:
71 fprintf(stderr, "%s ", cur->name);
72 break;
73 case XML_TEXT_NODE:
74 fprintf(stderr, "text ");
75 break;
76 case XML_CDATA_SECTION_NODE:
77 fprintf(stderr, "cdata ");
78 break;
79 case XML_ENTITY_REF_NODE:
80 fprintf(stderr, "&%s; ", cur->name);
81 break;
82 case XML_PI_NODE:
83 fprintf(stderr, "pi(%s) ", cur->name);
84 break;
85 case XML_COMMENT_NODE:
86 fprintf(stderr, "comment ");
87 break;
88 case XML_ATTRIBUTE_NODE:
89 fprintf(stderr, "?attr? ");
90 break;
91 case XML_ENTITY_NODE:
92 fprintf(stderr, "?ent? ");
93 break;
94 case XML_DOCUMENT_NODE:
95 fprintf(stderr, "?doc? ");
96 break;
97 case XML_DOCUMENT_TYPE_NODE:
98 fprintf(stderr, "?doctype? ");
99 break;
100 case XML_DOCUMENT_FRAG_NODE:
101 fprintf(stderr, "?frag? ");
102 break;
103 case XML_NOTATION_NODE:
104 fprintf(stderr, "?nota? ");
105 break;
106 case XML_HTML_DOCUMENT_NODE:
107 fprintf(stderr, "?html? ");
108 break;
109 case XML_DTD_NODE:
110 fprintf(stderr, "?dtd? ");
111 break;
112 case XML_ELEMENT_DECL:
113 fprintf(stderr, "?edecl? ");
114 break;
115 case XML_ATTRIBUTE_DECL:
116 fprintf(stderr, "?adecl? ");
117 break;
118 case XML_ENTITY_DECL:
119 fprintf(stderr, "?entdecl? ");
120 break;
121 }
122 cur = cur->next;
123 }
124}
125
126void xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
127 char expr[1000];
128
129 expr[0] = 0;
130 fprintf(stderr, "valid: ");
131 xmlValidPrintNodeList(cur);
132 fprintf(stderr, "against ");
133 xmlSprintfElementContent(expr, cont, 0);
134 fprintf(stderr, "%s\n", expr);
135}
136
137#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
138#else
139#define DEBUG_VALID_STATE(n,c)
140#endif
141
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000142/* TODO: use hash table for accesses to elem and attribute dedinitions */
143
Daniel Veillardb05deb71999-08-10 19:04:08 +0000144#define VERROR \
145 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
146
147#define VWARNING \
148 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
149
150#define CHECK_DTD \
151 if (doc == NULL) return(0); \
152 else if (doc->intSubset == NULL) return(0)
153
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000154xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
155xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000156
157/****************************************************************
158 * *
159 * Util functions for data allocation/deallocation *
160 * *
161 ****************************************************************/
162
163/**
164 * xmlNewElementContent:
165 * @name: the subelement name or NULL
166 * @type: the type of element content decl
167 *
168 * Allocate an element content structure.
169 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000170 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000171 */
172xmlElementContentPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000173xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000174 xmlElementContentPtr ret;
175
176 switch(type) {
177 case XML_ELEMENT_CONTENT_ELEMENT:
178 if (name == NULL) {
179 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
180 }
181 break;
182 case XML_ELEMENT_CONTENT_PCDATA:
183 case XML_ELEMENT_CONTENT_SEQ:
184 case XML_ELEMENT_CONTENT_OR:
185 if (name != NULL) {
186 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
187 }
188 break;
189 default:
190 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
Daniel Veillard0142b842000-01-14 14:45:24 +0000191 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000192 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000193 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000194 if (ret == NULL) {
195 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
196 return(NULL);
197 }
198 ret->type = type;
199 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000200 if (name != NULL)
201 ret->name = xmlStrdup(name);
202 else
203 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000204 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000205 return(ret);
206}
207
208/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000209 * xmlCopyElementContent:
210 * @content: An element content pointer.
211 *
212 * Build a copy of an element content description.
213 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000214 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000215 */
216xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000217xmlCopyElementContent(xmlElementContentPtr cur) {
218 xmlElementContentPtr ret;
219
220 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000221 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +0000222 if (ret == NULL) {
223 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
224 return(NULL);
225 }
226 ret->ocur = cur->ocur;
227 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
228 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000229 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000230}
231
232/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000233 * xmlFreeElementContent:
234 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000235 *
236 * Free an element content structure. This is a recursive call !
237 */
238void
239xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000240 if (cur == NULL) return;
241 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
242 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000243 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000244 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000245 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000246}
247
Daniel Veillard1899e851999-02-01 12:18:54 +0000248/**
249 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000250 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000251 * @content: An element table
252 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
253 *
254 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000255 */
256void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000257xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000258 if (content == NULL) return;
259
Daniel Veillard5099ae81999-04-21 20:12:07 +0000260 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000261 switch (content->type) {
262 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000263 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000264 break;
265 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000266 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000267 break;
268 case XML_ELEMENT_CONTENT_SEQ:
269 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
270 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000271 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000272 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000273 xmlDumpElementContent(buf, content->c1, 0);
274 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000275 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000276 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000277 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000278 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000279 break;
280 case XML_ELEMENT_CONTENT_OR:
281 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
282 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000283 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000284 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000285 xmlDumpElementContent(buf, content->c1, 0);
286 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000287 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000288 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000289 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000290 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000291 break;
292 default:
293 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
294 content->type);
295 }
296 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000297 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000298 switch (content->ocur) {
299 case XML_ELEMENT_CONTENT_ONCE:
300 break;
301 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000302 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000303 break;
304 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000305 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000306 break;
307 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000308 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000309 break;
310 }
311}
312
Daniel Veillardb05deb71999-08-10 19:04:08 +0000313/**
314 * xmlSprintfElementContent:
315 * @buf: an output buffer
316 * @content: An element table
317 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
318 *
319 * This will dump the content of the element content definition
320 * Intended just for the debug routine
321 */
322void
323xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
324 if (content == NULL) return;
325 if (glob) strcat(buf, "(");
326 switch (content->type) {
327 case XML_ELEMENT_CONTENT_PCDATA:
328 strcat(buf, "#PCDATA");
329 break;
330 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000331 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000332 break;
333 case XML_ELEMENT_CONTENT_SEQ:
334 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
335 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
336 xmlSprintfElementContent(buf, content->c1, 1);
337 else
338 xmlSprintfElementContent(buf, content->c1, 0);
339 strcat(buf, " , ");
340 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
341 xmlSprintfElementContent(buf, content->c2, 1);
342 else
343 xmlSprintfElementContent(buf, content->c2, 0);
344 break;
345 case XML_ELEMENT_CONTENT_OR:
346 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
347 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
348 xmlSprintfElementContent(buf, content->c1, 1);
349 else
350 xmlSprintfElementContent(buf, content->c1, 0);
351 strcat(buf, " | ");
352 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
353 xmlSprintfElementContent(buf, content->c2, 1);
354 else
355 xmlSprintfElementContent(buf, content->c2, 0);
356 break;
357 }
358 if (glob)
359 strcat(buf, ")");
360 switch (content->ocur) {
361 case XML_ELEMENT_CONTENT_ONCE:
362 break;
363 case XML_ELEMENT_CONTENT_OPT:
364 strcat(buf, "?");
365 break;
366 case XML_ELEMENT_CONTENT_MULT:
367 strcat(buf, "*");
368 break;
369 case XML_ELEMENT_CONTENT_PLUS:
370 strcat(buf, "+");
371 break;
372 }
373}
374
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000375/****************************************************************
376 * *
377 * Registration of DTD declarations *
378 * *
379 ****************************************************************/
380
Daniel Veillard3b9def11999-01-31 22:15:06 +0000381/**
382 * xmlCreateElementTable:
383 *
384 * create and initialize an empty element hash table.
385 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000386 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000387 */
388xmlElementTablePtr
389xmlCreateElementTable(void) {
390 xmlElementTablePtr ret;
391
392 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000393 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000394 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000395 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000396 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000397 return(NULL);
398 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000399 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000400 ret->nb_elements = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000401 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000402 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000403 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000404 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000405 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000406 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000407 return(NULL);
408 }
409 return(ret);
410}
411
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000412
413/**
414 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000415 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000416 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000417 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000418 * @type: the element type
419 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000420 *
421 * Register a new element declaration
422 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000423 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000424 */
425xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000426xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillardcf461992000-03-14 18:30:20 +0000427 xmlElementTypeVal type,
428 xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000429 xmlElementPtr ret, cur;
430 xmlElementTablePtr table;
431 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000432
433 if (dtd == NULL) {
434 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
435 return(NULL);
436 }
437 if (name == NULL) {
438 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
439 return(NULL);
440 }
441 switch (type) {
442 case XML_ELEMENT_TYPE_EMPTY:
443 if (content != NULL) {
444 fprintf(stderr,
445 "xmlAddElementDecl: content != NULL for EMPTY\n");
446 return(NULL);
447 }
448 break;
449 case XML_ELEMENT_TYPE_ANY:
450 if (content != NULL) {
451 fprintf(stderr,
452 "xmlAddElementDecl: content != NULL for ANY\n");
453 return(NULL);
454 }
455 break;
456 case XML_ELEMENT_TYPE_MIXED:
457 if (content == NULL) {
458 fprintf(stderr,
459 "xmlAddElementDecl: content == NULL for MIXED\n");
460 return(NULL);
461 }
462 break;
463 case XML_ELEMENT_TYPE_ELEMENT:
464 if (content == NULL) {
465 fprintf(stderr,
466 "xmlAddElementDecl: content == NULL for ELEMENT\n");
467 return(NULL);
468 }
469 break;
470 default:
471 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
472 return(NULL);
473 }
474
475 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000476 * Create the Element table if needed.
477 */
478 table = dtd->elements;
479 if (table == NULL)
480 table = dtd->elements = xmlCreateElementTable();
481 if (table == NULL) {
482 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
483 return(NULL);
484 }
485
486 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000487 * Validity Check:
488 * Search the DTD for previous declarations of the ELEMENT
489 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000490 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000491 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000492 if (!xmlStrcmp(cur->name, name)) {
493 /*
494 * The element is already defined in this Dtd.
495 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000496 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000497 return(NULL);
498 }
499 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000500
501 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000502 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000503 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000504 if (table->nb_elements >= table->max_elements) {
505 /*
506 * need more elements.
507 */
508 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000509 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000510 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000511 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000512 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
513 return(NULL);
514 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000515 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000516 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000517 if (ret == NULL) {
518 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
519 return(NULL);
520 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000521 memset(ret, 0, sizeof(xmlElement));
522 ret->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000523 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000524
525 /*
526 * fill the structure.
527 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000528 ret->etype = type;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000529 ret->name = xmlStrdup(name);
Daniel Veillard14fff061999-06-22 21:49:07 +0000530 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000531 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000532 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000533
Daniel Veillardcf461992000-03-14 18:30:20 +0000534 /*
535 * Link it to the Dtd
536 */
537 ret->parent = dtd;
538 ret->doc = dtd->doc;
539 if (dtd->last == NULL) {
540 dtd->children = dtd->last = (xmlNodePtr) ret;
541 } else {
542 dtd->last->next = (xmlNodePtr) ret;
543 ret->prev = dtd->last;
544 dtd->last = (xmlNodePtr) ret;
545 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000546 return(ret);
547}
548
Daniel Veillard3b9def11999-01-31 22:15:06 +0000549/**
550 * xmlFreeElement:
551 * @elem: An element
552 *
553 * Deallocate the memory used by an element definition
554 */
555void
556xmlFreeElement(xmlElementPtr elem) {
557 if (elem == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +0000558 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000559 xmlFreeElementContent(elem->content);
560 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000561 xmlFree((xmlChar *) elem->name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000562 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000563 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000564}
565
566/**
567 * xmlFreeElementTable:
568 * @table: An element table
569 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000570 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000571 */
572void
573xmlFreeElementTable(xmlElementTablePtr table) {
574 int i;
575
576 if (table == NULL) return;
577
578 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000579 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000580 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000581 xmlFree(table->table);
582 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000583}
584
585/**
586 * xmlCopyElementTable:
587 * @table: An element table
588 *
589 * Build a copy of an element table.
590 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000591 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000592 */
593xmlElementTablePtr
594xmlCopyElementTable(xmlElementTablePtr table) {
595 xmlElementTablePtr ret;
596 xmlElementPtr cur, ent;
597 int i;
598
Daniel Veillard6454aec1999-09-02 22:04:43 +0000599 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000600 if (ret == NULL) {
601 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
602 return(NULL);
603 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000604 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000605 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000606 if (ret->table == NULL) {
607 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000608 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000609 return(NULL);
610 }
611 ret->max_elements = table->max_elements;
612 ret->nb_elements = table->nb_elements;
613 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000614 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000615 if (cur == NULL) {
616 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000617 xmlFree(ret);
618 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000619 return(NULL);
620 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000621 memset(cur, 0, sizeof(xmlElement));
622 cur->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000623 ret->table[i] = cur;
624 ent = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000625 cur->etype = ent->etype;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000626 if (ent->name != NULL)
627 cur->name = xmlStrdup(ent->name);
628 else
629 cur->name = NULL;
630 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000631 /* TODO : rebuild the attribute list on the copy */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000632 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000633 }
634 return(ret);
635}
636
637/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000638 * xmlDumpElementDecl:
639 * @buf: the XML buffer output
640 * @elem: An element table
641 *
642 * This will dump the content of the element declaration as an XML
643 * DTD definition
644 */
645void
646xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
647 switch (elem->etype) {
648 case XML_ELEMENT_TYPE_EMPTY:
649 xmlBufferWriteChar(buf, "<!ELEMENT ");
650 xmlBufferWriteCHAR(buf, elem->name);
651 xmlBufferWriteChar(buf, " EMPTY>\n");
652 break;
653 case XML_ELEMENT_TYPE_ANY:
654 xmlBufferWriteChar(buf, "<!ELEMENT ");
655 xmlBufferWriteCHAR(buf, elem->name);
656 xmlBufferWriteChar(buf, " ANY>\n");
657 break;
658 case XML_ELEMENT_TYPE_MIXED:
659 xmlBufferWriteChar(buf, "<!ELEMENT ");
660 xmlBufferWriteCHAR(buf, elem->name);
661 xmlBufferWriteChar(buf, " ");
662 xmlDumpElementContent(buf, elem->content, 1);
663 xmlBufferWriteChar(buf, ">\n");
664 break;
665 case XML_ELEMENT_TYPE_ELEMENT:
666 xmlBufferWriteChar(buf, "<!ELEMENT ");
667 xmlBufferWriteCHAR(buf, elem->name);
668 xmlBufferWriteChar(buf, " ");
669 xmlDumpElementContent(buf, elem->content, 1);
670 xmlBufferWriteChar(buf, ">\n");
671 break;
672 default:
673 fprintf(stderr,
674 "xmlDumpElementDecl: internal: unknown type %d\n",
675 elem->etype);
676 }
677}
678
679/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000680 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000681 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000682 * @table: An element table
683 *
684 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000685 */
686void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000687xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000688 int i;
689 xmlElementPtr cur;
690
691 if (table == NULL) return;
692
693 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000694 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000695 xmlDumpElementDecl(buf, cur);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000696 }
697}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000698
699/**
700 * xmlCreateEnumeration:
701 * @name: the enumeration name or NULL
702 *
703 * create and initialize an enumeration attribute node.
704 *
705 * Returns the xmlEnumerationPtr just created or NULL in case
706 * of error.
707 */
708xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000709xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000710 xmlEnumerationPtr ret;
711
Daniel Veillard6454aec1999-09-02 22:04:43 +0000712 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000713 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000714 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000715 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000716 return(NULL);
717 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000718 memset(ret, 0, sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000719
720 if (name != NULL)
721 ret->name = xmlStrdup(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000722 return(ret);
723}
724
725/**
726 * xmlFreeEnumeration:
727 * @cur: the tree to free.
728 *
729 * free an enumeration attribute node (recursive).
730 */
731void
732xmlFreeEnumeration(xmlEnumerationPtr cur) {
733 if (cur == NULL) return;
734
735 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
736
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000737 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000738 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000739 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000740}
741
742/**
743 * xmlCopyEnumeration:
744 * @cur: the tree to copy.
745 *
746 * Copy an enumeration attribute node (recursive).
747 *
748 * Returns the xmlEnumerationPtr just created or NULL in case
749 * of error.
750 */
751xmlEnumerationPtr
752xmlCopyEnumeration(xmlEnumerationPtr cur) {
753 xmlEnumerationPtr ret;
754
755 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000756 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000757
758 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
759 else ret->next = NULL;
760
761 return(ret);
762}
763
764/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000765 * xmlDumpEnumeration:
766 * @buf: the XML buffer output
767 * @enum: An enumeration
768 *
769 * This will dump the content of the enumeration
770 */
771void
772xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
773 if (cur == NULL) return;
774
775 xmlBufferWriteCHAR(buf, cur->name);
776 if (cur->next == NULL)
777 xmlBufferWriteChar(buf, ")");
778 else {
779 xmlBufferWriteChar(buf, " | ");
780 xmlDumpEnumeration(buf, cur->next);
781 }
782}
783
784/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000785 * xmlCreateAttributeTable:
786 *
787 * create and initialize an empty attribute hash table.
788 *
789 * Returns the xmlAttributeTablePtr just created or NULL in case
790 * of error.
791 */
792xmlAttributeTablePtr
793xmlCreateAttributeTable(void) {
794 xmlAttributeTablePtr ret;
795
796 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000797 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000798 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000799 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000800 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000801 return(NULL);
802 }
803 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
804 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000805 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000806 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000807 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000808 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000809 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000810 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000811 return(NULL);
812 }
813 return(ret);
814}
815
Daniel Veillardb05deb71999-08-10 19:04:08 +0000816/**
817 * xmlScanAttributeDecl:
818 * @dtd: pointer to the DTD
819 * @elem: the element name
820 *
821 * When inserting a new element scan the DtD for existing attributes
822 * for taht element and initialize the Attribute chain
823 *
824 * Returns the pointer to the first attribute decl in the chain,
825 * possibly NULL.
826 */
827xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000828xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000829 xmlAttributePtr ret = NULL;
830 xmlAttributeTablePtr table;
831 int i;
832
833 if (dtd == NULL) {
834 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
835 return(NULL);
836 }
837 if (elem == NULL) {
838 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
839 return(NULL);
840 }
841 table = dtd->attributes;
842 if (table == NULL)
843 return(NULL);
844
845 for (i = 0;i < table->nb_attributes;i++) {
846 if (!xmlStrcmp(table->table[i]->elem, elem)) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000847 table->table[i]->nexth = ret;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000848 ret = table->table[i];
849 }
850 }
851 return(ret);
852}
853
854/**
855 * xmlScanIDAttributeDecl:
856 * @ctxt: the validation context
857 * @elem: the element name
858 *
Daniel Veillard71b656e2000-01-05 14:46:17 +0000859 * Verify that the element don't have too many ID attributes
Daniel Veillardb05deb71999-08-10 19:04:08 +0000860 * declared.
861 *
862 * Returns the number of ID attributes found.
863 */
864int
865xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
866 xmlAttributePtr cur;
867 int ret = 0;
868
869 if (elem == NULL) return(0);
870 cur = elem->attributes;
871 while (cur != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000872 if (cur->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000873 ret ++;
874 if (ret > 1)
875 VERROR(ctxt->userData,
876 "Element %s has too may ID attributes defined : %s\n",
877 elem->name, cur->name);
878 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000879 cur = cur->nexth;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000880 }
881 return(ret);
882}
883
Daniel Veillard1e346af1999-02-22 10:33:01 +0000884
885/**
886 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000887 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000888 * @dtd: pointer to the DTD
889 * @elem: the element name
890 * @name: the attribute name
Daniel Veillardcf461992000-03-14 18:30:20 +0000891 * @ns: the attribute namespace prefix
Daniel Veillard1e346af1999-02-22 10:33:01 +0000892 * @type: the attribute type
893 * @def: the attribute default type
894 * @defaultValue: the attribute default value
895 * @tree: if it's an enumeration, the associated list
896 *
897 * Register a new attribute declaration
898 *
899 * Returns NULL if not, othervise the entity
900 */
901xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000902xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
Daniel Veillardcf461992000-03-14 18:30:20 +0000903 const xmlChar *name, const xmlChar *ns,
904 xmlAttributeType type, xmlAttributeDefault def,
905 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000906 xmlAttributePtr ret, cur;
907 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000908 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000909 int i;
910
911 if (dtd == NULL) {
912 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
913 return(NULL);
914 }
915 if (name == NULL) {
916 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
917 return(NULL);
918 }
919 if (elem == NULL) {
920 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
921 return(NULL);
922 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000923 /*
924 * Check the type and possibly the default value.
925 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000926 switch (type) {
927 case XML_ATTRIBUTE_CDATA:
928 break;
929 case XML_ATTRIBUTE_ID:
930 break;
931 case XML_ATTRIBUTE_IDREF:
932 break;
933 case XML_ATTRIBUTE_IDREFS:
934 break;
935 case XML_ATTRIBUTE_ENTITY:
936 break;
937 case XML_ATTRIBUTE_ENTITIES:
938 break;
939 case XML_ATTRIBUTE_NMTOKEN:
940 break;
941 case XML_ATTRIBUTE_NMTOKENS:
942 break;
943 case XML_ATTRIBUTE_ENUMERATION:
944 break;
945 case XML_ATTRIBUTE_NOTATION:
946 break;
947 default:
948 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
949 return(NULL);
950 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000951 if ((defaultValue != NULL) &&
952 (!xmlValidateAttributeValue(type, defaultValue))) {
953 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
954 elem, name, defaultValue);
955 defaultValue = NULL;
956 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000957
958 /*
959 * Create the Attribute table if needed.
960 */
961 table = dtd->attributes;
962 if (table == NULL)
963 table = dtd->attributes = xmlCreateAttributeTable();
964 if (table == NULL) {
965 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
966 return(NULL);
967 }
968
969 /*
970 * Validity Check:
971 * Search the DTD for previous declarations of the ATTLIST
972 */
973 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000974 cur = table->table[i];
Daniel Veillard10a2c651999-12-12 13:03:50 +0000975 if ((ns != NULL) && (cur->prefix == NULL)) continue;
976 if ((ns == NULL) && (cur->prefix != NULL)) continue;
Daniel Veillardcf461992000-03-14 18:30:20 +0000977 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem)) &&
Daniel Veillard10a2c651999-12-12 13:03:50 +0000978 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000979 /*
980 * The attribute is already defined in this Dtd.
981 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000982 VWARNING(ctxt->userData, "Attribute %s on %s: already defined\n",
Daniel Veillardb96e6431999-08-29 21:02:19 +0000983 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000984 }
985 }
986
987 /*
988 * Grow the table, if needed.
989 */
990 if (table->nb_attributes >= table->max_attributes) {
991 /*
992 * need more attributes.
993 */
994 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000995 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000996 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000997 sizeof(xmlAttributePtr));
998 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000999 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1000 return(NULL);
1001 }
1002 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001003 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001004 if (ret == NULL) {
1005 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1006 return(NULL);
1007 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001008 memset(ret, 0, sizeof(xmlAttribute));
1009 ret->type = XML_ATTRIBUTE_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001010 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001011
1012 /*
1013 * fill the structure.
1014 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001015 ret->atype = type;
1016 ret->name = xmlStrdup(name);
1017 ret->prefix = xmlStrdup(ns);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001018 ret->elem = xmlStrdup(elem);
1019 ret->def = def;
1020 ret->tree = tree;
1021 if (defaultValue != NULL)
1022 ret->defaultValue = xmlStrdup(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001023 elemDef = xmlGetDtdElementDesc(dtd, elem);
1024 if (elemDef != NULL) {
1025 if ((type == XML_ATTRIBUTE_ID) &&
1026 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
1027 VERROR(ctxt->userData,
1028 "Element %s has too may ID attributes defined : %s\n",
1029 elem, name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001030 ret->nexth = elemDef->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001031 elemDef->attributes = ret;
1032 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001033 table->nb_attributes++;
1034
Daniel Veillardcf461992000-03-14 18:30:20 +00001035 /*
1036 * Link it to the Dtd
1037 */
1038 ret->parent = dtd;
1039 ret->doc = dtd->doc;
1040 if (dtd->last == NULL) {
1041 dtd->children = dtd->last = (xmlNodePtr) ret;
1042 } else {
1043 dtd->last->next = (xmlNodePtr) ret;
1044 ret->prev = dtd->last;
1045 dtd->last = (xmlNodePtr) ret;
1046 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001047 return(ret);
1048}
1049
1050/**
1051 * xmlFreeAttribute:
1052 * @elem: An attribute
1053 *
1054 * Deallocate the memory used by an attribute definition
1055 */
1056void
1057xmlFreeAttribute(xmlAttributePtr attr) {
1058 if (attr == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +00001059 xmlUnlinkNode((xmlNodePtr) attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001060 if (attr->tree != NULL)
1061 xmlFreeEnumeration(attr->tree);
1062 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001063 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001064 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001065 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001066 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001067 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +00001068 if (attr->prefix != NULL)
1069 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001070 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001071 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001072}
1073
1074/**
1075 * xmlFreeAttributeTable:
1076 * @table: An attribute table
1077 *
1078 * Deallocate the memory used by an entities hash table.
1079 */
1080void
1081xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1082 int i;
1083
1084 if (table == NULL) return;
1085
1086 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001087 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001088 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001089 xmlFree(table->table);
1090 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001091}
1092
1093/**
1094 * xmlCopyAttributeTable:
1095 * @table: An attribute table
1096 *
1097 * Build a copy of an attribute table.
1098 *
1099 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1100 */
1101xmlAttributeTablePtr
1102xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1103 xmlAttributeTablePtr ret;
1104 xmlAttributePtr cur, attr;
1105 int i;
1106
Daniel Veillard6454aec1999-09-02 22:04:43 +00001107 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001108 if (ret == NULL) {
1109 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1110 return(NULL);
1111 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001112 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001113 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001114 if (ret->table == NULL) {
1115 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001116 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001117 return(NULL);
1118 }
1119 ret->max_attributes = table->max_attributes;
1120 ret->nb_attributes = table->nb_attributes;
1121 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001122 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001123 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001124 if (cur == NULL) {
1125 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001126 xmlFree(ret);
1127 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001128 return(NULL);
1129 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001130 memset(cur, 0, sizeof(xmlAttribute));
1131 /* !!! cur->type = XML_ATTRIBUTE_DECL; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001132 ret->table[i] = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001133 cur->atype = attr->atype;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001134 cur->def = attr->def;
1135 cur->tree = xmlCopyEnumeration(attr->tree);
1136 if (attr->elem != NULL)
1137 cur->elem = xmlStrdup(attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001138 if (attr->name != NULL)
1139 cur->name = xmlStrdup(attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001140 if (attr->defaultValue != NULL)
1141 cur->defaultValue = xmlStrdup(attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001142 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001143 }
1144 return(ret);
1145}
1146
1147/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001148 * xmlDumpAttributeDecl:
1149 * @buf: the XML buffer output
1150 * @attr: An attribute declaration
1151 *
1152 * This will dump the content of the attribute declaration as an XML
1153 * DTD definition
1154 */
1155void
1156xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1157 xmlBufferWriteChar(buf, "<!ATTLIST ");
1158 xmlBufferWriteCHAR(buf, attr->elem);
1159 xmlBufferWriteChar(buf, " ");
1160 xmlBufferWriteCHAR(buf, attr->name);
1161 switch (attr->atype) {
1162 case XML_ATTRIBUTE_CDATA:
1163 xmlBufferWriteChar(buf, " CDATA");
1164 break;
1165 case XML_ATTRIBUTE_ID:
1166 xmlBufferWriteChar(buf, " ID");
1167 break;
1168 case XML_ATTRIBUTE_IDREF:
1169 xmlBufferWriteChar(buf, " IDREF");
1170 break;
1171 case XML_ATTRIBUTE_IDREFS:
1172 xmlBufferWriteChar(buf, " IDREFS");
1173 break;
1174 case XML_ATTRIBUTE_ENTITY:
1175 xmlBufferWriteChar(buf, " ENTITY");
1176 break;
1177 case XML_ATTRIBUTE_ENTITIES:
1178 xmlBufferWriteChar(buf, " ENTITIES");
1179 break;
1180 case XML_ATTRIBUTE_NMTOKEN:
1181 xmlBufferWriteChar(buf, " NMTOKEN");
1182 break;
1183 case XML_ATTRIBUTE_NMTOKENS:
1184 xmlBufferWriteChar(buf, " NMTOKENS");
1185 break;
1186 case XML_ATTRIBUTE_ENUMERATION:
1187 xmlBufferWriteChar(buf, " (");
1188 xmlDumpEnumeration(buf, attr->tree);
1189 break;
1190 case XML_ATTRIBUTE_NOTATION:
1191 xmlBufferWriteChar(buf, " NOTATION (");
1192 xmlDumpEnumeration(buf, attr->tree);
1193 break;
1194 default:
1195 fprintf(stderr,
1196 "xmlDumpAttributeTable: internal: unknown type %d\n",
1197 attr->atype);
1198 }
1199 switch (attr->def) {
1200 case XML_ATTRIBUTE_NONE:
1201 break;
1202 case XML_ATTRIBUTE_REQUIRED:
1203 xmlBufferWriteChar(buf, " #REQUIRED");
1204 break;
1205 case XML_ATTRIBUTE_IMPLIED:
1206 xmlBufferWriteChar(buf, " #IMPLIED");
1207 break;
1208 case XML_ATTRIBUTE_FIXED:
1209 xmlBufferWriteChar(buf, " #FIXED");
1210 break;
1211 default:
1212 fprintf(stderr,
1213 "xmlDumpAttributeTable: internal: unknown default %d\n",
1214 attr->def);
1215 }
1216 if (attr->defaultValue != NULL) {
1217 xmlBufferWriteChar(buf, " ");
1218 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1219 }
1220 xmlBufferWriteChar(buf, ">\n");
1221}
1222
1223/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001224 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001225 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001226 * @table: An attribute table
1227 *
1228 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001229 */
1230void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001231xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001232 int i;
1233 xmlAttributePtr cur;
1234
1235 if (table == NULL) return;
1236
1237 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001238 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001239 xmlDumpAttributeDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001240 }
1241}
1242
1243/************************************************************************
1244 * *
1245 * NOTATIONs *
1246 * *
1247 ************************************************************************/
1248/**
1249 * xmlCreateNotationTable:
1250 *
1251 * create and initialize an empty notation hash table.
1252 *
1253 * Returns the xmlNotationTablePtr just created or NULL in case
1254 * of error.
1255 */
1256xmlNotationTablePtr
1257xmlCreateNotationTable(void) {
1258 xmlNotationTablePtr ret;
1259
1260 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001261 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001262 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001263 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001264 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001265 return(NULL);
1266 }
1267 ret->max_notations = XML_MIN_NOTATION_TABLE;
1268 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001269 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001270 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001271 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001272 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001273 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001274 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001275 return(NULL);
1276 }
1277 return(ret);
1278}
1279
1280
1281/**
1282 * xmlAddNotationDecl:
1283 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001284 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001285 * @name: the entity name
1286 * @PublicID: the public identifier or NULL
1287 * @SystemID: the system identifier or NULL
1288 *
1289 * Register a new notation declaration
1290 *
1291 * Returns NULL if not, othervise the entity
1292 */
1293xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001294xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1295 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001296 xmlNotationPtr ret, cur;
1297 xmlNotationTablePtr table;
1298 int i;
1299
1300 if (dtd == NULL) {
1301 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1302 return(NULL);
1303 }
1304 if (name == NULL) {
1305 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1306 return(NULL);
1307 }
1308 if ((PublicID == NULL) && (SystemID == NULL)) {
1309 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1310 }
1311
1312 /*
1313 * Create the Notation table if needed.
1314 */
1315 table = dtd->notations;
1316 if (table == NULL)
1317 table = dtd->notations = xmlCreateNotationTable();
1318 if (table == NULL) {
1319 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1320 return(NULL);
1321 }
1322
1323 /*
1324 * Validity Check:
1325 * Search the DTD for previous declarations of the ATTLIST
1326 */
1327 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001328 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001329 if (!xmlStrcmp(cur->name, name)) {
1330 /*
1331 * The notation is already defined in this Dtd.
1332 */
1333 fprintf(stderr,
1334 "xmlAddNotationDecl: %s already defined\n", name);
1335 }
1336 }
1337
1338 /*
1339 * Grow the table, if needed.
1340 */
1341 if (table->nb_notations >= table->max_notations) {
1342 /*
1343 * need more notations.
1344 */
1345 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001346 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001347 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001348 sizeof(xmlNotationPtr));
1349 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001350 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1351 return(NULL);
1352 }
1353 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001354 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001355 if (ret == NULL) {
1356 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1357 return(NULL);
1358 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001359 memset(ret, 0, sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001360 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001361
1362 /*
1363 * fill the structure.
1364 */
1365 ret->name = xmlStrdup(name);
1366 if (SystemID != NULL)
1367 ret->SystemID = xmlStrdup(SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001368 if (PublicID != NULL)
1369 ret->PublicID = xmlStrdup(PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001370 table->nb_notations++;
1371
1372 return(ret);
1373}
1374
1375/**
1376 * xmlFreeNotation:
1377 * @not: A notation
1378 *
1379 * Deallocate the memory used by an notation definition
1380 */
1381void
1382xmlFreeNotation(xmlNotationPtr nota) {
1383 if (nota == NULL) return;
1384 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001385 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001386 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001387 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001388 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001389 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001390 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001391 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001392}
1393
1394/**
1395 * xmlFreeNotationTable:
1396 * @table: An notation table
1397 *
1398 * Deallocate the memory used by an entities hash table.
1399 */
1400void
1401xmlFreeNotationTable(xmlNotationTablePtr table) {
1402 int i;
1403
1404 if (table == NULL) return;
1405
1406 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001407 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001408 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001409 xmlFree(table->table);
1410 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001411}
1412
1413/**
1414 * xmlCopyNotationTable:
1415 * @table: A notation table
1416 *
1417 * Build a copy of a notation table.
1418 *
1419 * Returns the new xmlNotationTablePtr or NULL in case of error.
1420 */
1421xmlNotationTablePtr
1422xmlCopyNotationTable(xmlNotationTablePtr table) {
1423 xmlNotationTablePtr ret;
1424 xmlNotationPtr cur, nota;
1425 int i;
1426
Daniel Veillard6454aec1999-09-02 22:04:43 +00001427 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001428 if (ret == NULL) {
1429 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1430 return(NULL);
1431 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001432 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001433 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001434 if (ret->table == NULL) {
1435 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001436 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001437 return(NULL);
1438 }
1439 ret->max_notations = table->max_notations;
1440 ret->nb_notations = table->nb_notations;
1441 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001442 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001443 if (cur == NULL) {
1444 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001445 xmlFree(ret);
1446 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001447 return(NULL);
1448 }
1449 ret->table[i] = cur;
1450 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001451 if (nota->name != NULL)
1452 cur->name = xmlStrdup(nota->name);
1453 else
1454 cur->name = NULL;
1455 if (nota->PublicID != NULL)
1456 cur->PublicID = xmlStrdup(nota->PublicID);
1457 else
1458 cur->PublicID = NULL;
1459 if (nota->SystemID != NULL)
1460 cur->SystemID = xmlStrdup(nota->SystemID);
1461 else
1462 cur->SystemID = NULL;
1463 }
1464 return(ret);
1465}
1466
1467/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001468 * xmlDumpNotationDecl:
1469 * @buf: the XML buffer output
1470 * @nota: A notation declaration
1471 *
1472 * This will dump the content the notation declaration as an XML DTD definition
1473 */
1474void
1475xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
1476 xmlBufferWriteChar(buf, "<!NOTATION ");
1477 xmlBufferWriteCHAR(buf, nota->name);
1478 if (nota->PublicID != NULL) {
1479 xmlBufferWriteChar(buf, " PUBLIC ");
1480 xmlBufferWriteQuotedString(buf, nota->PublicID);
1481 if (nota->SystemID != NULL) {
1482 xmlBufferWriteChar(buf, " ");
1483 xmlBufferWriteCHAR(buf, nota->SystemID);
1484 }
1485 } else {
1486 xmlBufferWriteChar(buf, " SYSTEM ");
1487 xmlBufferWriteCHAR(buf, nota->SystemID);
1488 }
1489 xmlBufferWriteChar(buf, " >\n");
1490}
1491
1492/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001493 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001494 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001495 * @table: A notation table
1496 *
1497 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001498 */
1499void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001500xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001501 int i;
1502 xmlNotationPtr cur;
1503
1504 if (table == NULL) return;
1505
1506 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001507 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001508 xmlDumpNotationDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001509 }
1510}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001511
1512/************************************************************************
1513 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001514 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001515 * *
1516 ************************************************************************/
1517/**
1518 * xmlCreateIDTable:
1519 *
1520 * create and initialize an empty id hash table.
1521 *
1522 * Returns the xmlIDTablePtr just created or NULL in case
1523 * of error.
1524 */
1525xmlIDTablePtr
1526xmlCreateIDTable(void) {
1527 xmlIDTablePtr ret;
1528
1529 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001530 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001531 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001532 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001533 (long)sizeof(xmlIDTable));
1534 return(NULL);
1535 }
1536 ret->max_ids = XML_MIN_NOTATION_TABLE;
1537 ret->nb_ids = 0;
1538 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001539 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001540 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001541 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001542 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001543 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001544 return(NULL);
1545 }
1546 return(ret);
1547}
1548
1549
1550/**
1551 * xmlAddID:
1552 * @ctxt: the validation context
1553 * @doc: pointer to the document
1554 * @value: the value name
1555 * @attr: the attribute holding the ID
1556 *
1557 * Register a new id declaration
1558 *
1559 * Returns NULL if not, othervise the new xmlIDPtr
1560 */
1561xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001562xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001563 xmlAttrPtr attr) {
1564 xmlIDPtr ret, cur;
1565 xmlIDTablePtr table;
1566 int i;
1567
1568 if (doc == NULL) {
1569 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1570 return(NULL);
1571 }
1572 if (value == NULL) {
1573 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1574 return(NULL);
1575 }
1576 if (attr == NULL) {
1577 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1578 return(NULL);
1579 }
1580
1581 /*
1582 * Create the ID table if needed.
1583 */
1584 table = doc->ids;
1585 if (table == NULL)
1586 table = doc->ids = xmlCreateIDTable();
1587 if (table == NULL) {
1588 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1589 return(NULL);
1590 }
1591
1592 /*
1593 * Validity Check:
1594 * Search the DTD for previous declarations of the ATTLIST
1595 */
1596 for (i = 0;i < table->nb_ids;i++) {
1597 cur = table->table[i];
1598 if (!xmlStrcmp(cur->value, value)) {
1599 /*
1600 * The id is already defined in this Dtd.
1601 */
1602 VERROR(ctxt->userData, "ID %s already defined\n", value);
1603 return(NULL);
1604 }
1605 }
1606
1607 /*
1608 * Grow the table, if needed.
1609 */
1610 if (table->nb_ids >= table->max_ids) {
1611 /*
1612 * need more ids.
1613 */
1614 table->max_ids *= 2;
1615 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001616 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001617 sizeof(xmlIDPtr));
1618 if (table->table == NULL) {
1619 fprintf(stderr, "xmlAddID: out of memory\n");
1620 return(NULL);
1621 }
1622 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001623 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001624 if (ret == NULL) {
1625 fprintf(stderr, "xmlAddID: out of memory\n");
1626 return(NULL);
1627 }
1628 table->table[table->nb_ids] = ret;
1629
1630 /*
1631 * fill the structure.
1632 */
1633 ret->value = xmlStrdup(value);
1634 ret->attr = attr;
1635 table->nb_ids++;
1636
1637 return(ret);
1638}
1639
1640/**
1641 * xmlFreeID:
1642 * @not: A id
1643 *
1644 * Deallocate the memory used by an id definition
1645 */
1646void
1647xmlFreeID(xmlIDPtr id) {
1648 if (id == NULL) return;
1649 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001650 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001651 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001652 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001653}
1654
1655/**
1656 * xmlFreeIDTable:
1657 * @table: An id table
1658 *
1659 * Deallocate the memory used by an ID hash table.
1660 */
1661void
1662xmlFreeIDTable(xmlIDTablePtr table) {
1663 int i;
1664
1665 if (table == NULL) return;
1666
1667 for (i = 0;i < table->nb_ids;i++) {
1668 xmlFreeID(table->table[i]);
1669 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001670 xmlFree(table->table);
1671 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001672}
1673
1674/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001675 * xmlIsID:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001676 * @doc: the document
1677 * @elem: the element carrying the attribute
1678 * @attr: the attribute
1679 *
1680 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1681 * then this is simple, otherwise we use an heuristic: name ID (upper
1682 * or lowercase).
1683 *
1684 * Returns 0 or 1 depending on the lookup result
1685 */
1686int
1687xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00001688 if (doc == NULL) return(0);
1689 if (attr == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001690 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1691 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1692 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1693 (attr->name[2] == 0)) return(1);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001694 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1695 if ((!xmlStrcmp(BAD_CAST "id", attr->name)) ||
1696 (!xmlStrcmp(BAD_CAST "name", attr->name)))
1697 return(1);
1698 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001699 } else {
1700 xmlAttributePtr attrDecl;
1701
Daniel Veillard71b656e2000-01-05 14:46:17 +00001702 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001703 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1704 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1705 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1706 attr->name);
1707
Daniel Veillardcf461992000-03-14 18:30:20 +00001708 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001709 return(1);
1710 }
1711 return(0);
1712}
1713
Daniel Veillardb96e6431999-08-29 21:02:19 +00001714/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001715 * xmlRemoveID
1716 * @doc: the document
1717 * @attr: the attribute
1718 *
1719 * Remove the given attribute from the ID table maintained internally.
1720 *
1721 * Returns -1 if the lookup failed and 0 otherwise
1722 */
1723int
1724xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1725 xmlIDPtr cur;
1726 xmlIDTablePtr table;
1727 int i;
1728
1729 if (doc == NULL) return(-1);
1730 if (attr == NULL) return(-1);
1731 table = doc->ids;
1732 if (table == NULL)
1733 return(-1);
1734
1735 /*
1736 * Search the ID list.
1737 */
1738 for (i = 0;i < table->nb_ids;i++) {
1739 cur = table->table[i];
1740 if (cur->attr == attr) {
1741 table->nb_ids--;
1742 memmove(&table->table[i], &table->table[i+1],
1743 (table->nb_ids - i) * sizeof(xmlIDPtr));
1744 return(0);
1745 }
1746 }
1747 return(-1);
1748}
1749
1750/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001751 * xmlGetID:
1752 * @doc: pointer to the document
1753 * @ID: the ID value
1754 *
1755 * Search the attribute declaring the given ID
1756 *
1757 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1758 */
1759xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001760xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001761 xmlIDPtr cur;
1762 xmlIDTablePtr table;
1763 int i;
1764
1765 if (doc == NULL) {
1766 fprintf(stderr, "xmlGetID: doc == NULL\n");
1767 return(NULL);
1768 }
1769
1770 if (ID == NULL) {
1771 fprintf(stderr, "xmlGetID: ID == NULL\n");
1772 return(NULL);
1773 }
1774
1775 table = doc->ids;
1776 if (table == NULL)
1777 return(NULL);
1778
1779 /*
1780 * Search the ID list.
1781 */
1782 for (i = 0;i < table->nb_ids;i++) {
1783 cur = table->table[i];
1784 if (!xmlStrcmp(cur->value, ID)) {
1785 return(cur->attr);
1786 }
1787 }
1788 return(NULL);
1789}
1790
Daniel Veillard991e63d1999-08-15 23:32:28 +00001791/************************************************************************
1792 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001793 * Refs *
1794 * *
1795 ************************************************************************/
1796/**
1797 * xmlCreateRefTable:
1798 *
1799 * create and initialize an empty ref hash table.
1800 *
1801 * Returns the xmlRefTablePtr just created or NULL in case
1802 * of error.
1803 */
1804xmlRefTablePtr
1805xmlCreateRefTable(void) {
1806 xmlRefTablePtr ret;
1807
1808 ret = (xmlRefTablePtr)
1809 xmlMalloc(sizeof(xmlRefTable));
1810 if (ret == NULL) {
1811 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1812 (long)sizeof(xmlRefTable));
1813 return(NULL);
1814 }
1815 ret->max_refs = XML_MIN_NOTATION_TABLE;
1816 ret->nb_refs = 0;
1817 ret->table = (xmlRefPtr *)
1818 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1819 if (ret == NULL) {
1820 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1821 ret->max_refs * (long)sizeof(xmlRef));
1822 xmlFree(ret);
1823 return(NULL);
1824 }
1825 return(ret);
1826}
1827
1828
1829/**
1830 * xmlAddRef:
1831 * @ctxt: the validation context
1832 * @doc: pointer to the document
1833 * @value: the value name
1834 * @attr: the attribute holding the Ref
1835 *
1836 * Register a new ref declaration
1837 *
1838 * Returns NULL if not, othervise the new xmlRefPtr
1839 */
1840xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001841xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001842 xmlAttrPtr attr) {
1843 xmlRefPtr ret;
1844 xmlRefTablePtr table;
1845
1846 if (doc == NULL) {
1847 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1848 return(NULL);
1849 }
1850 if (value == NULL) {
1851 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1852 return(NULL);
1853 }
1854 if (attr == NULL) {
1855 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1856 return(NULL);
1857 }
1858
1859 /*
1860 * Create the Ref table if needed.
1861 */
1862 table = doc->refs;
1863 if (table == NULL)
1864 table = doc->refs = xmlCreateRefTable();
1865 if (table == NULL) {
1866 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1867 return(NULL);
1868 }
1869
1870 /*
1871 * Grow the table, if needed.
1872 */
1873 if (table->nb_refs >= table->max_refs) {
1874 /*
1875 * need more refs.
1876 */
1877 table->max_refs *= 2;
1878 table->table = (xmlRefPtr *)
1879 xmlRealloc(table->table, table->max_refs *
1880 sizeof(xmlRefPtr));
1881 if (table->table == NULL) {
1882 fprintf(stderr, "xmlAddRef: out of memory\n");
1883 return(NULL);
1884 }
1885 }
1886 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1887 if (ret == NULL) {
1888 fprintf(stderr, "xmlAddRef: out of memory\n");
1889 return(NULL);
1890 }
1891 table->table[table->nb_refs] = ret;
1892
1893 /*
1894 * fill the structure.
1895 */
1896 ret->value = xmlStrdup(value);
1897 ret->attr = attr;
1898 table->nb_refs++;
1899
1900 return(ret);
1901}
1902
1903/**
1904 * xmlFreeRef:
1905 * @not: A ref
1906 *
1907 * Deallocate the memory used by an ref definition
1908 */
1909void
1910xmlFreeRef(xmlRefPtr ref) {
1911 if (ref == NULL) return;
1912 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001913 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001914 memset(ref, -1, sizeof(xmlRef));
1915 xmlFree(ref);
1916}
1917
1918/**
1919 * xmlFreeRefTable:
1920 * @table: An ref table
1921 *
1922 * Deallocate the memory used by an Ref hash table.
1923 */
1924void
1925xmlFreeRefTable(xmlRefTablePtr table) {
1926 int i;
1927
1928 if (table == NULL) return;
1929
1930 for (i = 0;i < table->nb_refs;i++) {
1931 xmlFreeRef(table->table[i]);
1932 }
1933 xmlFree(table->table);
1934 xmlFree(table);
1935}
1936
1937/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001938 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001939 * @doc: the document
1940 * @elem: the element carrying the attribute
1941 * @attr: the attribute
1942 *
1943 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1944 * then this is simple, otherwise we use an heuristic: name Ref (upper
1945 * or lowercase).
1946 *
1947 * Returns 0 or 1 depending on the lookup result
1948 */
1949int
1950xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1951 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1952 return(0);
1953 /*******************
1954 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1955 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1956 (attr->name[2] == 0)) return(1);
1957 *******************/
1958 } else {
1959 xmlAttributePtr attrDecl;
1960
1961 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1962 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1963 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1964 attr->name);
1965
Daniel Veillardcf461992000-03-14 18:30:20 +00001966 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001967 return(1);
1968 }
1969 return(0);
1970}
1971
1972/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001973 * xmlRemoveRef
1974 * @doc: the document
1975 * @attr: the attribute
1976 *
1977 * Remove the given attribute from the Ref table maintained internally.
1978 *
1979 * Returns -1 if the lookup failed and 0 otherwise
1980 */
1981int
1982xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
1983 xmlRefPtr cur;
1984 xmlRefTablePtr table;
1985 int i;
1986
1987 if (doc == NULL) return(-1);
1988 if (attr == NULL) return(-1);
1989 table = doc->refs;
1990 if (table == NULL)
1991 return(-1);
1992
1993 /*
1994 * Search the Ref list.
1995 */
1996 for (i = 0;i < table->nb_refs;i++) {
1997 cur = table->table[i];
1998 if (cur->attr == attr) {
1999 table->nb_refs--;
2000 memmove(&table->table[i], &table->table[i+1],
2001 (table->nb_refs - i) * sizeof(xmlRefPtr));
2002 return(0);
2003 }
2004 }
2005 return(-1);
2006}
2007
2008/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002009 * xmlGetRef:
2010 * @doc: pointer to the document
2011 * @Ref: the Ref value
2012 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00002013 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002014 *
2015 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
2016 */
2017xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002018xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002019 xmlRefPtr cur;
2020 xmlRefTablePtr table;
2021 int i;
2022
2023 if (doc == NULL) {
2024 fprintf(stderr, "xmlGetRef: doc == NULL\n");
2025 return(NULL);
2026 }
2027
2028 if (Ref == NULL) {
2029 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
2030 return(NULL);
2031 }
2032
2033 table = doc->refs;
2034 if (table == NULL)
2035 return(NULL);
2036
2037 /*
2038 * Search the Ref list.
2039 */
2040 for (i = 0;i < table->nb_refs;i++) {
2041 cur = table->table[i];
2042 if (!xmlStrcmp(cur->value, Ref)) {
2043 return(cur->attr);
2044 }
2045 }
2046 return(NULL);
2047}
2048
2049/************************************************************************
2050 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002051 * Routines for validity checking *
2052 * *
2053 ************************************************************************/
2054
2055/**
2056 * xmlGetDtdElementDesc:
2057 * @dtd: a pointer to the DtD to search
2058 * @name: the element name
2059 *
2060 * Search the Dtd for the description of this element
2061 *
2062 * returns the xmlElementPtr if found or NULL
2063 */
2064
2065xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002066xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002067 xmlElementTablePtr table;
2068 xmlElementPtr cur;
2069 int i;
2070
2071 if (dtd == NULL) return(NULL);
2072 if (dtd->elements == NULL) return(NULL);
2073 table = dtd->elements;
2074
2075 for (i = 0;i < table->nb_elements;i++) {
2076 cur = table->table[i];
2077 if (!xmlStrcmp(cur->name, name))
2078 return(cur);
2079 }
2080 return(NULL);
2081}
2082
2083/**
2084 * xmlGetDtdAttrDesc:
2085 * @dtd: a pointer to the DtD to search
2086 * @elem: the element name
2087 * @name: the attribute name
2088 *
2089 * Search the Dtd for the description of this attribute on
2090 * this element.
2091 *
2092 * returns the xmlAttributePtr if found or NULL
2093 */
2094
2095xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002096xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002097 xmlAttributeTablePtr table;
2098 xmlAttributePtr cur;
2099 int i;
2100
2101 if (dtd == NULL) return(NULL);
2102 if (dtd->attributes == NULL) return(NULL);
2103 table = dtd->attributes;
2104
2105 for (i = 0;i < table->nb_attributes;i++) {
2106 cur = table->table[i];
2107 if ((!xmlStrcmp(cur->name, name)) &&
2108 (!xmlStrcmp(cur->elem, elem)))
2109 return(cur);
2110 }
2111 return(NULL);
2112}
2113
2114/**
2115 * xmlGetDtdNotationDesc:
2116 * @dtd: a pointer to the DtD to search
2117 * @name: the notation name
2118 *
2119 * Search the Dtd for the description of this notation
2120 *
2121 * returns the xmlNotationPtr if found or NULL
2122 */
2123
2124xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002125xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002126 xmlNotationTablePtr table;
2127 xmlNotationPtr cur;
2128 int i;
2129
2130 if (dtd == NULL) return(NULL);
2131 if (dtd->notations == NULL) return(NULL);
2132 table = dtd->notations;
2133
2134 for (i = 0;i < table->nb_notations;i++) {
2135 cur = table->table[i];
2136 if (!xmlStrcmp(cur->name, name))
2137 return(cur);
2138 }
2139 return(NULL);
2140}
2141
2142/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002143 * xmlValidateNotationUse:
2144 * @ctxt: the validation context
2145 * @doc: the document
2146 * @notationName: the notation name to check
2147 *
2148 * Validate that the given mame match a notation declaration.
2149 * - [ VC: Notation Declared ]
2150 *
2151 * returns 1 if valid or 0 otherwise
2152 */
2153
2154int
2155xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002156 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002157 xmlNotationPtr notaDecl;
2158 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2159
2160 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2161 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2162 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2163
2164 if (notaDecl == NULL) {
2165 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2166 notationName);
2167 return(0);
2168 }
2169 return(1);
2170}
2171
2172/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002173 * xmlIsMixedElement
2174 * @doc: the document
2175 * @name: the element name
2176 *
2177 * Search in the DtDs whether an element accept Mixed content (or ANY)
2178 * basically if it is supposed to accept text childs
2179 *
2180 * returns 0 if no, 1 if yes, and -1 if no element description is available
2181 */
2182
2183int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002184xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002185 xmlElementPtr elemDecl;
2186
2187 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2188
2189 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2190 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2191 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2192 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002193 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002194 case XML_ELEMENT_TYPE_ELEMENT:
2195 return(0);
2196 case XML_ELEMENT_TYPE_EMPTY:
2197 /*
2198 * return 1 for EMPTY since we want VC error to pop up
2199 * on <empty> </empty> for example
2200 */
2201 case XML_ELEMENT_TYPE_ANY:
2202 case XML_ELEMENT_TYPE_MIXED:
2203 return(1);
2204 }
2205 return(1);
2206}
2207
2208/**
2209 * xmlValidateNameValue:
2210 * @value: an Name value
2211 *
2212 * Validate that the given value match Name production
2213 *
2214 * returns 1 if valid or 0 otherwise
2215 */
2216
2217int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002218xmlValidateNameValue(const xmlChar *value) {
2219 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002220
2221 if (value == NULL) return(0);
2222 cur = value;
2223
2224 if (!IS_LETTER(*cur) && (*cur != '_') &&
2225 (*cur != ':')) {
2226 return(0);
2227 }
2228
2229 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2230 (*cur == '.') || (*cur == '-') ||
2231 (*cur == '_') || (*cur == ':') ||
2232 (IS_COMBINING(*cur)) ||
2233 (IS_EXTENDER(*cur)))
2234 cur++;
2235
2236 if (*cur != 0) return(0);
2237
2238 return(1);
2239}
2240
2241/**
2242 * xmlValidateNamesValue:
2243 * @value: an Names value
2244 *
2245 * Validate that the given value match Names production
2246 *
2247 * returns 1 if valid or 0 otherwise
2248 */
2249
2250int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002251xmlValidateNamesValue(const xmlChar *value) {
2252 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002253
2254 if (value == NULL) return(0);
2255 cur = value;
2256
2257 if (!IS_LETTER(*cur) && (*cur != '_') &&
2258 (*cur != ':')) {
2259 return(0);
2260 }
2261
2262 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2263 (*cur == '.') || (*cur == '-') ||
2264 (*cur == '_') || (*cur == ':') ||
2265 (IS_COMBINING(*cur)) ||
2266 (IS_EXTENDER(*cur)))
2267 cur++;
2268
2269 while (IS_BLANK(*cur)) {
2270 while (IS_BLANK(*cur)) cur++;
2271
2272 if (!IS_LETTER(*cur) && (*cur != '_') &&
2273 (*cur != ':')) {
2274 return(0);
2275 }
2276
2277 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2278 (*cur == '.') || (*cur == '-') ||
2279 (*cur == '_') || (*cur == ':') ||
2280 (IS_COMBINING(*cur)) ||
2281 (IS_EXTENDER(*cur)))
2282 cur++;
2283 }
2284
2285 if (*cur != 0) return(0);
2286
2287 return(1);
2288}
2289
2290/**
2291 * xmlValidateNmtokenValue:
2292 * @value: an Mntoken value
2293 *
2294 * Validate that the given value match Nmtoken production
2295 *
2296 * [ VC: Name Token ]
2297 *
2298 * returns 1 if valid or 0 otherwise
2299 */
2300
2301int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002302xmlValidateNmtokenValue(const xmlChar *value) {
2303 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002304
2305 if (value == NULL) return(0);
2306 cur = value;
2307
2308 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2309 (*cur != '.') && (*cur != '-') &&
2310 (*cur != '_') && (*cur != ':') &&
2311 (!IS_COMBINING(*cur)) &&
2312 (!IS_EXTENDER(*cur)))
2313 return(0);
2314
2315 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2316 (*cur == '.') || (*cur == '-') ||
2317 (*cur == '_') || (*cur == ':') ||
2318 (IS_COMBINING(*cur)) ||
2319 (IS_EXTENDER(*cur)))
2320 cur++;
2321
2322 if (*cur != 0) return(0);
2323
2324 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002325}
2326
2327/**
2328 * xmlValidateNmtokensValue:
2329 * @value: an Mntokens value
2330 *
2331 * Validate that the given value match Nmtokens production
2332 *
2333 * [ VC: Name Token ]
2334 *
2335 * returns 1 if valid or 0 otherwise
2336 */
2337
2338int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002339xmlValidateNmtokensValue(const xmlChar *value) {
2340 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002341
2342 if (value == NULL) return(0);
2343 cur = value;
2344
Daniel Veillardcf461992000-03-14 18:30:20 +00002345 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002346 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2347 (*cur != '.') && (*cur != '-') &&
2348 (*cur != '_') && (*cur != ':') &&
2349 (!IS_COMBINING(*cur)) &&
2350 (!IS_EXTENDER(*cur)))
2351 return(0);
2352
2353 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2354 (*cur == '.') || (*cur == '-') ||
2355 (*cur == '_') || (*cur == ':') ||
2356 (IS_COMBINING(*cur)) ||
2357 (IS_EXTENDER(*cur)))
2358 cur++;
2359
2360 while (IS_BLANK(*cur)) {
2361 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002362 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002363
2364 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2365 (*cur != '.') && (*cur != '-') &&
2366 (*cur != '_') && (*cur != ':') &&
2367 (!IS_COMBINING(*cur)) &&
2368 (!IS_EXTENDER(*cur)))
2369 return(0);
2370
2371 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2372 (*cur == '.') || (*cur == '-') ||
2373 (*cur == '_') || (*cur == ':') ||
2374 (IS_COMBINING(*cur)) ||
2375 (IS_EXTENDER(*cur)))
2376 cur++;
2377 }
2378
2379 if (*cur != 0) return(0);
2380
2381 return(1);
2382}
2383
2384/**
2385 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002386 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002387 * @doc: a document instance
2388 * @nota: a notation definition
2389 *
2390 * Try to validate a single notation definition
2391 * basically it does the following checks as described by the
2392 * XML-1.0 recommendation:
2393 * - it seems that no validity constraing exist on notation declarations
2394 * But this function get called anyway ...
2395 *
2396 * returns 1 if valid or 0 otherwise
2397 */
2398
2399int
2400xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2401 xmlNotationPtr nota) {
2402 int ret = 1;
2403
2404 return(ret);
2405}
2406
2407/**
2408 * xmlValidateAttributeValue:
2409 * @type: an attribute type
2410 * @value: an attribute value
2411 *
2412 * Validate that the given attribute value match the proper production
2413 *
2414 * [ VC: ID ]
2415 * Values of type ID must match the Name production....
2416 *
2417 * [ VC: IDREF ]
2418 * Values of type IDREF must match the Name production, and values
2419 * of type IDREFS must match Names ...
2420 *
2421 * [ VC: Entity Name ]
2422 * Values of type ENTITY must match the Name production, values
2423 * of type ENTITIES must match Names ...
2424 *
2425 * [ VC: Name Token ]
2426 * Values of type NMTOKEN must match the Nmtoken production; values
2427 * of type NMTOKENS must match Nmtokens.
2428 *
2429 * returns 1 if valid or 0 otherwise
2430 */
2431
2432int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002433xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002434 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002435 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002436 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002437 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002438 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002439 case XML_ATTRIBUTE_IDREF:
2440 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002441 case XML_ATTRIBUTE_NOTATION:
2442 return(xmlValidateNameValue(value));
2443 case XML_ATTRIBUTE_NMTOKENS:
2444 case XML_ATTRIBUTE_ENUMERATION:
2445 return(xmlValidateNmtokensValue(value));
2446 case XML_ATTRIBUTE_NMTOKEN:
2447 return(xmlValidateNmtokenValue(value));
2448 case XML_ATTRIBUTE_CDATA:
2449 break;
2450 }
2451 return(1);
2452}
2453
2454/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002455 * xmlValidateAttributeValue2:
2456 * @ctxt: the validation context
2457 * @doc: the document
2458 * @name: the attribute name (used for error reporting only)
2459 * @type: the attribute type
2460 * @value: the attribute value
2461 *
2462 * Validate that the given attribute value match a given type.
2463 * This typically cannot be done before having finished parsing
2464 * the subsets.
2465 *
2466 * [ VC: IDREF ]
2467 * Values of type IDREF must match one of the declared IDs
2468 * Values of type IDREFS must match a sequence of the declared IDs
2469 * each Name must match the value of an ID attribute on some element
2470 * in the XML document; i.e. IDREF values must match the value of
2471 * some ID attribute
2472 *
2473 * [ VC: Entity Name ]
2474 * Values of type ENTITY must match one declared entity
2475 * Values of type ENTITIES must match a sequence of declared entities
2476 *
2477 * [ VC: Notation Attributes ]
2478 * all notation names in the declaration must be declared.
2479 *
2480 * returns 1 if valid or 0 otherwise
2481 */
2482
2483int
2484xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2485 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2486 int ret = 1;
2487 switch (type) {
2488 case XML_ATTRIBUTE_IDREFS:
2489 case XML_ATTRIBUTE_IDREF:
2490 case XML_ATTRIBUTE_ID:
2491 case XML_ATTRIBUTE_NMTOKENS:
2492 case XML_ATTRIBUTE_ENUMERATION:
2493 case XML_ATTRIBUTE_NMTOKEN:
2494 case XML_ATTRIBUTE_CDATA:
2495 break;
2496 case XML_ATTRIBUTE_ENTITY: {
2497 xmlEntityPtr ent;
2498
2499 ent = xmlGetDocEntity(doc, value);
2500 if (ent == NULL) {
2501 VERROR(ctxt->userData,
2502 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2503 name, value);
2504 ret = 0;
2505 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2506 VERROR(ctxt->userData,
2507 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2508 name, value);
2509 ret = 0;
2510 }
2511 break;
2512 }
2513 case XML_ATTRIBUTE_ENTITIES: {
2514 xmlChar *dup, *nam = NULL, *cur, save;
2515 xmlEntityPtr ent;
2516
2517 dup = xmlStrdup(value);
2518 if (dup == NULL)
2519 return(0);
2520 cur = dup;
2521 while (*cur != 0) {
2522 nam = cur;
2523 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2524 save = *cur;
2525 *cur = 0;
2526 ent = xmlGetDocEntity(doc, nam);
2527 if (ent == NULL) {
2528 VERROR(ctxt->userData,
2529 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2530 name, nam);
2531 ret = 0;
2532 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2533 VERROR(ctxt->userData,
2534 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2535 name, nam);
2536 ret = 0;
2537 }
2538 if (save == 0)
2539 break;
2540 *cur = save;
2541 while (IS_BLANK(*cur)) cur++;
2542 }
2543 xmlFree(dup);
2544 break;
2545 }
2546 case XML_ATTRIBUTE_NOTATION: {
2547 xmlNotationPtr nota;
2548
2549 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2550 if ((nota == NULL) && (doc->extSubset != NULL))
2551 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2552
2553 if (nota == NULL) {
2554 VERROR(ctxt->userData,
2555 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2556 name, value);
2557 ret = 0;
2558 }
2559 break;
2560 }
2561 }
2562 return(ret);
2563}
2564
2565/**
2566 * xmlValidNormalizeAttributeValue:
2567 * @doc: the document
2568 * @elem: the parent
2569 * @name: the attribute name
2570 * @value: the attribute value
2571 *
2572 * Does the validation related extra step of the normalization of attribute
2573 * values:
2574 *
2575 * If the declared value is not CDATA, then the XML processor must further
2576 * process the normalized attribute value by discarding any leading and
2577 * trailing space (#x20) characters, and by replacing sequences of space
2578 * (#x20) characters by single space (#x20) character.
2579 *
2580 * returns a new normalized string if normalization is needed, NULL otherwise
2581 * the caller must free the returned value.
2582 */
2583
2584xmlChar *
2585xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2586 const xmlChar *name, const xmlChar *value) {
2587 xmlChar *ret, *dst;
2588 const xmlChar *src;
2589 xmlAttributePtr attrDecl;
2590
2591 if (doc == NULL) return(NULL);
2592 if (elem == NULL) return(NULL);
2593 if (name == NULL) return(NULL);
2594 if (value == NULL) return(NULL);
2595
2596 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2597 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2598 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2599
2600 if (attrDecl == NULL)
2601 return(NULL);
2602 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2603 return(NULL);
2604
2605 ret = xmlStrdup(value);
2606 if (ret == NULL)
2607 return(NULL);
2608 src = value;
2609 dst = ret;
2610 while (*src == 0x20) src++;
2611 while (*src != 0) {
2612 if (*src == 0x20) {
2613 while (*src == 0x20) src++;
2614 if (*src != 0)
2615 *dst++ = 0x20;
2616 } else {
2617 *dst++ = *src++;
2618 }
2619 }
2620 *dst = 0;
2621 return(ret);
2622}
2623
2624/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002625 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002626 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002627 * @doc: a document instance
2628 * @attr: an attribute definition
2629 *
2630 * Try to validate a single attribute definition
2631 * basically it does the following checks as described by the
2632 * XML-1.0 recommendation:
2633 * - [ VC: Attribute Default Legal ]
2634 * - [ VC: Enumeration ]
2635 * - [ VC: ID Attribute Default ]
2636 *
2637 * The ID/IDREF uniqueness and matching are done separately
2638 *
2639 * returns 1 if valid or 0 otherwise
2640 */
2641
2642int
2643xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2644 xmlAttributePtr attr) {
2645 int ret = 1;
2646 int val;
2647 CHECK_DTD;
2648 if(attr == NULL) return(1);
2649
2650 /* Attribute Default Legal */
2651 /* Enumeration */
2652 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002653 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002654 if (val == 0) {
2655 VERROR(ctxt->userData,
2656 "Syntax of default value for attribute %s on %s is not valid\n",
2657 attr->name, attr->elem);
2658 }
2659 ret &= val;
2660 }
2661
2662 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002663 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002664 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2665 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2666 VERROR(ctxt->userData,
2667 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2668 attr->name, attr->elem);
2669 ret = 0;
2670 }
2671
Daniel Veillardb96e6431999-08-29 21:02:19 +00002672 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002673 if (attr->atype == XML_ATTRIBUTE_ID) {
2674 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002675
2676 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002677 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002678 attr->elem);
2679 if (elem != NULL) {
2680 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002681 } else {
2682 xmlAttributeTablePtr table;
2683 int i;
2684
2685 /*
2686 * The attribute may be declared in the internal subset and the
2687 * element in the external subset.
2688 */
2689 nbId = 0;
2690 table = doc->intSubset->attributes;
2691 if (table != NULL) {
2692 for (i = 0;i < table->nb_attributes;i++) {
2693 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2694 (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2695 nbId++;
2696 }
2697 }
2698 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002699 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002700 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002701 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002702 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2703 attr->elem, nbId, attr->name);
2704 } else if (doc->extSubset != NULL) {
2705 int extId = 0;
2706 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2707 if (elem != NULL) {
2708 extId = xmlScanIDAttributeDecl(NULL, elem);
2709 }
2710 if (extId > 1) {
2711 VERROR(ctxt->userData,
2712 "Element %s has %d ID attribute defined in the external subset : %s\n",
2713 attr->elem, extId, attr->name);
2714 } else if (extId + nbId > 1) {
2715 VERROR(ctxt->userData,
2716"Element %s has ID attributes defined in the internal and external subset : %s\n",
2717 attr->elem, attr->name);
2718 }
2719 }
2720 }
2721
2722 /* Validity Constraint: Enumeration */
2723 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2724 xmlEnumerationPtr tree = attr->tree;
2725 while (tree != NULL) {
2726 if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2727 tree = tree->next;
2728 }
2729 if (tree == NULL) {
2730 VERROR(ctxt->userData,
2731"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2732 attr->defaultValue, attr->name, attr->elem);
2733 ret = 0;
2734 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002735 }
2736
2737 return(ret);
2738}
2739
2740/**
2741 * xmlValidateElementDecl:
2742 * @ctxt: the validation context
2743 * @doc: a document instance
2744 * @elem: an element definition
2745 *
2746 * Try to validate a single element definition
2747 * basically it does the following checks as described by the
2748 * XML-1.0 recommendation:
2749 * - [ VC: One ID per Element Type ]
2750 * - [ VC: No Duplicate Types ]
2751 * - [ VC: Unique Element Type Declaration ]
2752 *
2753 * returns 1 if valid or 0 otherwise
2754 */
2755
2756int
2757xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2758 xmlElementPtr elem) {
2759 int ret = 1;
2760 xmlElementPtr tst;
2761
2762 CHECK_DTD;
2763
2764 if (elem == NULL) return(1);
2765
2766 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00002767 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002768 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002769 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002770
2771 cur = elem->content;
2772 while (cur != NULL) {
2773 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2774 if (cur->c1 == NULL) break;
2775 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2776 name = cur->c1->name;
2777 next = cur->c2;
2778 while (next != NULL) {
2779 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2780 if (!xmlStrcmp(next->name, name)) {
2781 VERROR(ctxt->userData,
2782 "Definition of %s has duplicate references of %s\n",
2783 elem->name, name);
2784 ret = 0;
2785 }
2786 break;
2787 }
2788 if (next->c1 == NULL) break;
2789 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2790 if (!xmlStrcmp(next->c1->name, name)) {
2791 VERROR(ctxt->userData,
2792 "Definition of %s has duplicate references of %s\n",
2793 elem->name, name);
2794 ret = 0;
2795 }
2796 next = next->c2;
2797 }
2798 }
2799 cur = cur->c2;
2800 }
2801 }
2802
2803 /* VC: Unique Element Type Declaration */
2804 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2805 if ((tst != NULL ) && (tst != elem)) {
2806 VERROR(ctxt->userData, "Redefinition of element %s\n",
2807 elem->name);
2808 ret = 0;
2809 }
2810 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2811 if ((tst != NULL ) && (tst != elem)) {
2812 VERROR(ctxt->userData, "Redefinition of element %s\n",
2813 elem->name);
2814 ret = 0;
2815 }
2816
2817 /* One ID per Element Type */
2818 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2819 ret = 0;
2820 }
2821 return(ret);
2822}
2823
2824/**
2825 * xmlValidateOneAttribute:
2826 * @ctxt: the validation context
2827 * @doc: a document instance
2828 * @elem: an element instance
2829 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00002830 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002831 *
2832 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00002833 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00002834 * XML-1.0 recommendation:
2835 * - [ VC: Attribute Value Type ]
2836 * - [ VC: Fixed Attribute Default ]
2837 * - [ VC: Entity Name ]
2838 * - [ VC: Name Token ]
2839 * - [ VC: ID ]
2840 * - [ VC: IDREF ]
2841 * - [ VC: Entity Name ]
2842 * - [ VC: Notation Attributes ]
2843 *
2844 * The ID/IDREF uniqueness and matching are done separately
2845 *
2846 * returns 1 if valid or 0 otherwise
2847 */
2848
2849int
2850xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002851 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002852 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002853 xmlAttributePtr attrDecl;
2854 int val;
2855 int ret = 1;
2856
2857 CHECK_DTD;
2858 if ((elem == NULL) || (elem->name == NULL)) return(0);
2859 if ((attr == NULL) || (attr->name == NULL)) return(0);
2860
2861 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2862 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2863 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2864
2865
2866 /* Validity Constraint: Attribute Value Type */
2867 if (attrDecl == NULL) {
2868 VERROR(ctxt->userData,
2869 "No declaration for attribute %s on element %s\n",
2870 attr->name, elem->name);
2871 return(0);
2872 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002873 attr->atype = attrDecl->atype;
2874
2875 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002876 if (val == 0) {
2877 VERROR(ctxt->userData,
2878 "Syntax of value for attribute %s on %s is not valid\n",
2879 attr->name, elem->name);
2880 ret = 0;
2881 }
2882
Daniel Veillardcf461992000-03-14 18:30:20 +00002883 /* Validity constraint: Fixed Attribute Default */
2884 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
2885 if (xmlStrcmp(value, attrDecl->defaultValue)) {
2886 VERROR(ctxt->userData,
2887 "Value for attribute %s on %s is differnt from default \"%s\"\n",
2888 attr->name, elem->name, attrDecl->defaultValue);
2889 ret = 0;
2890 }
2891 }
2892
Daniel Veillardb96e6431999-08-29 21:02:19 +00002893 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00002894 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002895 xmlAddID(ctxt, doc, value, attr);
2896 }
2897
Daniel Veillardcf461992000-03-14 18:30:20 +00002898 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
2899 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002900 xmlAddRef(ctxt, doc, value, attr);
2901 }
2902
Daniel Veillardb05deb71999-08-10 19:04:08 +00002903 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00002904 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002905 xmlEnumerationPtr tree = attrDecl->tree;
2906 xmlNotationPtr nota;
2907
2908 /* First check that the given NOTATION was declared */
2909 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2910 if (nota == NULL)
2911 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2912
2913 if (nota == NULL) {
2914 VERROR(ctxt->userData,
2915 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2916 value, attr->name, elem->name);
2917 ret = 0;
2918 }
2919
2920 /* Second, verify that it's among the list */
2921 while (tree != NULL) {
2922 if (!xmlStrcmp(tree->name, value)) break;
2923 tree = tree->next;
2924 }
2925 if (tree == NULL) {
2926 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002927"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00002928 value, attr->name, elem->name);
2929 ret = 0;
2930 }
2931 }
2932
2933 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00002934 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002935 xmlEnumerationPtr tree = attrDecl->tree;
2936 while (tree != NULL) {
2937 if (!xmlStrcmp(tree->name, value)) break;
2938 tree = tree->next;
2939 }
2940 if (tree == NULL) {
2941 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00002942 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00002943 value, attr->name, elem->name);
2944 ret = 0;
2945 }
2946 }
2947
2948 /* Fixed Attribute Default */
2949 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2950 (xmlStrcmp(attrDecl->defaultValue, value))) {
2951 VERROR(ctxt->userData,
2952 "Value for attribute %s on %s must be \"%s\"\n",
2953 attr->name, elem->name, attrDecl->defaultValue);
2954 ret = 0;
2955 }
2956
Daniel Veillardcf461992000-03-14 18:30:20 +00002957 /* Extra check for the attribute value */
2958 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
2959 attrDecl->atype, value);
2960
Daniel Veillardb05deb71999-08-10 19:04:08 +00002961 return(ret);
2962}
2963
2964int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2965 xmlElementContentPtr cont);
2966
2967/**
2968 * xmlValidateElementTypeExpr:
2969 * @ctxt: the validation context
2970 * @child: pointer to the child list
2971 * @cont: pointer to the content declaration
2972 *
2973 * Try to validate the content of an element of type element
2974 * but don't handle the occurence factor
2975 *
2976 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2977 * also update child value in-situ.
2978 */
2979
2980int
2981xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2982 xmlElementContentPtr cont) {
2983 xmlNodePtr cur;
2984 int ret = 1;
2985
2986 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002987 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002988 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002989 if ((*child)->type == XML_ENTITY_REF_NODE) {
2990 /*
2991 * If there is an entity declared an it's not empty
2992 * Push the current node on the stack and process with the
2993 * entity content.
2994 */
2995 if (((*child)->children != NULL) &&
2996 ((*child)->children->children != NULL)) {
2997 nodeVPush(ctxt, *child);
2998 *child = (*child)->children->children;
2999 } else
3000 *child = (*child)->next;
3001 continue;
3002 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003003 if ((*child)->type == XML_PI_NODE) {
3004 *child = (*child)->next;
3005 continue;
3006 }
3007 if ((*child)->type == XML_COMMENT_NODE) {
3008 *child = (*child)->next;
3009 continue;
3010 }
3011 else if ((*child)->type != XML_ELEMENT_NODE) {
3012 return(-1);
3013 }
3014 break;
3015 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003016 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003017 switch (cont->type) {
3018 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003019 if (*child == NULL) return(0);
3020 if ((*child)->type == XML_TEXT_NODE) return(1);
3021 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003022 case XML_ELEMENT_CONTENT_ELEMENT:
3023 if (*child == NULL) return(0);
3024 ret = (!xmlStrcmp((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003025 if (ret == 1) {
3026 while ((*child)->next == NULL) {
3027 if (((*child)->parent != NULL) &&
3028 ((*child)->parent->type == XML_ENTITY_DECL)) {
3029 *child = nodeVPop(ctxt);
3030 } else
3031 break;
3032 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003033 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003034 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003035 return(ret);
3036 case XML_ELEMENT_CONTENT_OR:
3037 cur = *child;
3038 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3039 if (ret == -1) return(-1);
3040 if (ret == 1) {
3041 return(1);
3042 }
3043 /* rollback and retry the other path */
3044 *child = cur;
3045 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3046 if (ret == -1) return(-1);
3047 if (ret == 0) {
3048 *child = cur;
3049 return(0);
3050 }
3051 return(1);
3052 case XML_ELEMENT_CONTENT_SEQ:
3053 cur = *child;
3054 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3055 if (ret == -1) return(-1);
3056 if (ret == 0) {
3057 *child = cur;
3058 return(0);
3059 }
3060 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3061 if (ret == -1) return(-1);
3062 if (ret == 0) {
3063 *child = cur;
3064 return(0);
3065 }
3066 return(1);
3067 }
3068 return(ret);
3069}
3070
3071/**
3072 * xmlValidateElementTypeElement:
3073 * @ctxt: the validation context
3074 * @child: pointer to the child list
3075 * @cont: pointer to the content declaration
3076 *
3077 * Try to validate the content of an element of type element
3078 * yeah, Yet Another Regexp Implementation, and recursive
3079 *
3080 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3081 * also update child and content values in-situ.
3082 */
3083
3084int
3085xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3086 xmlElementContentPtr cont) {
3087 xmlNodePtr cur;
3088 int ret = 1;
3089
3090 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003091
3092 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003093 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003094 if ((*child)->type == XML_ENTITY_REF_NODE) {
3095 /*
3096 * If there is an entity declared an it's not empty
3097 * Push the current node on the stack and process with the
3098 * entity content.
3099 */
3100 if (((*child)->children != NULL) &&
3101 ((*child)->children->children != NULL)) {
3102 nodeVPush(ctxt, *child);
3103 *child = (*child)->children->children;
3104 } else
3105 *child = (*child)->next;
3106 continue;
3107 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003108 if ((*child)->type == XML_PI_NODE) {
3109 *child = (*child)->next;
3110 continue;
3111 }
3112 if ((*child)->type == XML_COMMENT_NODE) {
3113 *child = (*child)->next;
3114 continue;
3115 }
3116 else if ((*child)->type != XML_ELEMENT_NODE) {
3117 return(-1);
3118 }
3119 break;
3120 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003121 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003122 cur = *child;
3123 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3124 if (ret == -1) return(-1);
3125 switch (cont->ocur) {
3126 case XML_ELEMENT_CONTENT_ONCE:
3127 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003128 /* skip ignorable elems */
3129 while ((*child != NULL) &&
3130 (((*child)->type == XML_PI_NODE) ||
3131 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003132 while ((*child)->next == NULL) {
3133 if (((*child)->parent != NULL) &&
3134 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3135 *child = (*child)->parent;
3136 } else
3137 break;
3138 }
3139 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003140 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003141 return(1);
3142 }
3143 *child = cur;
3144 return(0);
3145 case XML_ELEMENT_CONTENT_OPT:
3146 if (ret == 0) {
3147 *child = cur;
3148 return(1);
3149 }
3150 break;
3151 case XML_ELEMENT_CONTENT_MULT:
3152 if (ret == 0) {
3153 *child = cur;
3154 break;
3155 }
3156 /* no break on purpose */
3157 case XML_ELEMENT_CONTENT_PLUS:
3158 if (ret == 0) {
3159 *child = cur;
3160 return(0);
3161 }
3162 do {
3163 cur = *child;
3164 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3165 } while (ret == 1);
3166 if (ret == -1) return(-1);
3167 *child = cur;
3168 break;
3169 }
3170 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003171 if ((*child)->type == XML_ENTITY_REF_NODE) {
3172 /*
3173 * If there is an entity declared an it's not empty
3174 * Push the current node on the stack and process with the
3175 * entity content.
3176 */
3177 if (((*child)->children != NULL) &&
3178 ((*child)->children->children != NULL)) {
3179 nodeVPush(ctxt, *child);
3180 *child = (*child)->children->children;
3181 } else
3182 *child = (*child)->next;
3183 continue;
3184 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003185 if ((*child)->type == XML_PI_NODE) {
3186 *child = (*child)->next;
3187 continue;
3188 }
3189 if ((*child)->type == XML_COMMENT_NODE) {
3190 *child = (*child)->next;
3191 continue;
3192 }
3193 else if ((*child)->type != XML_ELEMENT_NODE) {
3194 return(-1);
3195 }
3196 break;
3197 }
3198 return(1);
3199}
3200
3201/**
3202 * xmlSprintfElementChilds:
3203 * @buf: an output buffer
3204 * @content: An element
3205 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3206 *
3207 * This will dump the list of childs to the buffer
3208 * Intended just for the debug routine
3209 */
3210void
3211xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3212 xmlNodePtr cur;
3213
3214 if (node == NULL) return;
3215 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003216 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003217 while (cur != NULL) {
3218 switch (cur->type) {
3219 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003220 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003221 if (cur->next != NULL)
3222 strcat(buf, " ");
3223 break;
3224 case XML_TEXT_NODE:
3225 case XML_CDATA_SECTION_NODE:
3226 case XML_ENTITY_REF_NODE:
3227 strcat(buf, "CDATA");
3228 if (cur->next != NULL)
3229 strcat(buf, " ");
3230 break;
3231 case XML_ATTRIBUTE_NODE:
3232 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003233 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003234 case XML_DOCUMENT_TYPE_NODE:
3235 case XML_DOCUMENT_FRAG_NODE:
3236 case XML_NOTATION_NODE:
3237 strcat(buf, "???");
3238 if (cur->next != NULL)
3239 strcat(buf, " ");
3240 break;
3241 case XML_ENTITY_NODE:
3242 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003243 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003244 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003245 case XML_ELEMENT_DECL:
3246 case XML_ATTRIBUTE_DECL:
3247 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003248 break;
3249 }
3250 cur = cur->next;
3251 }
3252 if (glob) strcat(buf, ")");
3253}
3254
3255
3256/**
3257 * xmlValidateOneElement:
3258 * @ctxt: the validation context
3259 * @doc: a document instance
3260 * @elem: an element instance
3261 *
3262 * Try to validate a single element and it's attributes,
3263 * basically it does the following checks as described by the
3264 * XML-1.0 recommendation:
3265 * - [ VC: Element Valid ]
3266 * - [ VC: Required Attribute ]
3267 * Then call xmlValidateOneAttribute() for each attribute present.
3268 *
3269 * The ID/IDREF checkings are done separately
3270 *
3271 * returns 1 if valid or 0 otherwise
3272 */
3273
3274int
3275xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3276 xmlNodePtr elem) {
3277 xmlElementPtr elemDecl;
3278 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003279 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003280 xmlNodePtr child;
3281 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003282 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003283
3284 CHECK_DTD;
3285
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003286 if (elem == NULL) return(0);
3287 if (elem->type == XML_TEXT_NODE) {
3288 }
3289 switch (elem->type) {
3290 case XML_ATTRIBUTE_NODE:
3291 VERROR(ctxt->userData,
3292 "Attribute element not expected here\n");
3293 return(0);
3294 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003295 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003296 VERROR(ctxt->userData, "Text element has childs !\n");
3297 return(0);
3298 }
3299 if (elem->properties != NULL) {
3300 VERROR(ctxt->userData, "Text element has attributes !\n");
3301 return(0);
3302 }
3303 if (elem->ns != NULL) {
3304 VERROR(ctxt->userData, "Text element has namespace !\n");
3305 return(0);
3306 }
3307 if (elem->ns != NULL) {
3308 VERROR(ctxt->userData,
3309 "Text element carries namespace definitions !\n");
3310 return(0);
3311 }
3312 if (elem->content == NULL) {
3313 VERROR(ctxt->userData,
3314 "Text element has no content !\n");
3315 return(0);
3316 }
3317 return(1);
3318 case XML_CDATA_SECTION_NODE:
3319 case XML_ENTITY_REF_NODE:
3320 case XML_PI_NODE:
3321 case XML_COMMENT_NODE:
3322 return(1);
3323 case XML_ENTITY_NODE:
3324 VERROR(ctxt->userData,
3325 "Entity element not expected here\n");
3326 return(0);
3327 case XML_NOTATION_NODE:
3328 VERROR(ctxt->userData,
3329 "Notation element not expected here\n");
3330 return(0);
3331 case XML_DOCUMENT_NODE:
3332 case XML_DOCUMENT_TYPE_NODE:
3333 case XML_DOCUMENT_FRAG_NODE:
3334 VERROR(ctxt->userData,
3335 "Document element not expected here\n");
3336 return(0);
3337 case XML_HTML_DOCUMENT_NODE:
3338 VERROR(ctxt->userData,
3339 "\n");
3340 return(0);
3341 case XML_ELEMENT_NODE:
3342 break;
3343 default:
3344 VERROR(ctxt->userData,
3345 "unknown element type %d\n", elem->type);
3346 return(0);
3347 }
3348 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003349
3350 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3351 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3352 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3353 if (elemDecl == NULL) {
3354 VERROR(ctxt->userData, "No declaration for element %s\n",
3355 elem->name);
3356 return(0);
3357 }
3358
3359 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003360 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003361 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003362 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003363 VERROR(ctxt->userData,
3364 "Element %s was declared EMPTY this one has content\n",
3365 elem->name);
3366 ret = 0;
3367 }
3368 break;
3369 case XML_ELEMENT_TYPE_ANY:
3370 /* I don't think anything is required then */
3371 break;
3372 case XML_ELEMENT_TYPE_MIXED:
3373 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003374 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003375 while (child != NULL) {
3376 if (child->type == XML_ELEMENT_NODE) {
3377 name = child->name;
3378 cont = elemDecl->content;
3379 while (cont != NULL) {
3380 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3381 if (!xmlStrcmp(cont->name, name)) break;
3382 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3383 (cont->c1 != NULL) &&
3384 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3385 if (!xmlStrcmp(cont->c1->name, name)) break;
3386 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3387 (cont->c1 == NULL) ||
3388 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3389 /* Internal error !!! */
3390 fprintf(stderr, "Internal: MIXED struct bad\n");
3391 break;
3392 }
3393 cont = cont->c2;
3394 }
3395 if (cont == NULL) {
3396 VERROR(ctxt->userData,
3397 "Element %s is not declared in %s list of possible childs\n",
3398 name, elem->name);
3399 ret = 0;
3400 }
3401 }
3402 child = child->next;
3403 }
3404 break;
3405 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003406 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003407 cont = elemDecl->content;
3408 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3409 if ((ret == 0) || (child != NULL)) {
3410 char expr[1000];
3411 char list[2000];
3412
3413 expr[0] = 0;
3414 xmlSprintfElementContent(expr, cont, 1);
3415 list[0] = 0;
3416 xmlSprintfElementChilds(list, elem, 1);
3417
3418 VERROR(ctxt->userData,
3419 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3420 elem->name, expr, list);
3421 ret = 0;
3422 }
3423 break;
3424 }
3425
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003426 /* [ VC: Required Attribute ] */
3427 attr = elemDecl->attributes;
3428 while (attr != NULL) {
3429 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3430 xmlAttrPtr attrib;
3431 int qualified = -1;
3432
3433 attrib = elem->properties;
3434 while (attrib != NULL) {
3435 if (!xmlStrcmp(attrib->name, attr->name)) {
3436 if (attr->prefix != NULL) {
3437 xmlNsPtr nameSpace = attrib->ns;
3438
3439 if (nameSpace == NULL)
3440 nameSpace = elem->ns;
3441 /*
3442 * qualified names handling is problematic, having a
3443 * different prefix should be possible but DTDs don't
3444 * allow to define the URI instead of the prefix :-(
3445 */
3446 if (nameSpace == NULL) {
3447 if (qualified < 0)
3448 qualified = 0;
3449 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3450 if (qualified < 1)
3451 qualified = 1;
3452 } else
3453 goto found;
3454 } else {
3455 /*
3456 * We should allow applications to define namespaces
3457 * for their application even if the DTD doesn't
3458 * carry one, otherwise, basically we would always
3459 * break.
3460 */
3461 goto found;
3462 }
3463 }
3464 attrib = attrib->next;
3465 }
3466 if (qualified == -1) {
3467 if (attr->prefix == NULL) {
3468 VERROR(ctxt->userData,
3469 "Element %s doesn't carry attribute %s\n",
3470 elem->name, attr->name);
3471 } else {
3472 VERROR(ctxt->userData,
3473 "Element %s doesn't carry attribute %s:%s\n",
3474 elem->name, attr->prefix,attr->name);
3475 }
3476 } else if (qualified == 0) {
3477 VWARNING(ctxt->userData,
3478 "Element %s required attribute %s:%s has no prefix\n",
3479 elem->name, attr->prefix,attr->name);
3480 } else if (qualified == 1) {
3481 VWARNING(ctxt->userData,
3482 "Element %s required attribute %s:%s has different prefix\n",
3483 elem->name, attr->prefix,attr->name);
3484 }
3485 }
3486found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003487 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003488 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003489 return(ret);
3490}
3491
3492/**
3493 * xmlValidateRoot:
3494 * @ctxt: the validation context
3495 * @doc: a document instance
3496 *
3497 * Try to validate a the root element
3498 * basically it does the following check as described by the
3499 * XML-1.0 recommendation:
3500 * - [ VC: Root Element Type ]
3501 * it doesn't try to recurse or apply other check to the element
3502 *
3503 * returns 1 if valid or 0 otherwise
3504 */
3505
3506int
3507xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003508 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003509 if (doc == NULL) return(0);
3510
3511 if ((doc->intSubset == NULL) ||
3512 (doc->intSubset->name == NULL)) {
3513 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3514 return(0);
3515 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003516 root = xmlDocGetRootElement(doc);
3517 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003518 VERROR(ctxt->userData, "Not valid: no root element\n");
3519 return(0);
3520 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003521 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardda07c342000-01-25 18:31:22 +00003522 if ((xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) ||
3523 (xmlStrcmp(root->name, BAD_CAST "html"))) {
3524 VERROR(ctxt->userData,
3525 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3526 root->name, doc->intSubset->name);
3527 return(0);
3528 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003529 }
3530 return(1);
3531}
3532
3533
3534/**
3535 * xmlValidateElement:
3536 * @ctxt: the validation context
3537 * @doc: a document instance
3538 * @elem: an element instance
3539 *
3540 * Try to validate the subtree under an element
3541 *
3542 * returns 1 if valid or 0 otherwise
3543 */
3544
3545int
3546xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003547 xmlNodePtr child;
3548 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003549 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003550 int ret = 1;
3551
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003552 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003553 CHECK_DTD;
3554
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003555 ret &= xmlValidateOneElement(ctxt, doc, elem);
3556 attr = elem->properties;
3557 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003558 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003559 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3560 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003561 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003562 attr= attr->next;
3563 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003564 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003565 while (child != NULL) {
3566 ret &= xmlValidateElement(ctxt, doc, child);
3567 child = child->next;
3568 }
3569
3570 return(ret);
3571}
3572
3573/**
3574 * xmlValidateDocumentFinal:
3575 * @ctxt: the validation context
3576 * @doc: a document instance
3577 *
3578 * Does the final step for the document validation once all the
3579 * incremental validation steps have been completed
3580 *
3581 * basically it does the following checks described by the XML Rec
3582 *
3583 *
3584 * returns 1 if valid or 0 otherwise
3585 */
3586
3587int
3588xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3589 int ret = 1, i;
3590 xmlRefTablePtr table;
3591 xmlAttrPtr id;
3592
3593 if (doc == NULL) {
3594 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3595 return(0);
3596 }
3597
3598 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003599 * Check all the NOTATION/NOTATIONS attributes
3600 */
3601 /*
3602 * Check all the ENTITY/ENTITIES attributes definition for validity
3603 */
3604 /*
3605 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003606 */
3607 table = doc->refs;
3608 if (table != NULL) {
3609 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003610 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3611 id = xmlGetID(doc, table->table[i]->value);
3612 if (id == NULL) {
3613 VERROR(ctxt->userData,
3614 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3615 table->table[i]->attr->name, table->table[i]->value);
3616 ret = 0;
3617 }
3618 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
3619 xmlChar *dup, *name = NULL, *cur, save;
3620
3621 dup = xmlStrdup(table->table[i]->value);
3622 if (dup == NULL)
3623 return(0);
3624 cur = dup;
3625 while (*cur != 0) {
3626 name = cur;
3627 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3628 save = *cur;
3629 *cur = 0;
3630 id = xmlGetID(doc, name);
3631 if (id == NULL) {
3632 VERROR(ctxt->userData,
3633 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3634 table->table[i]->attr->name, name);
3635 ret = 0;
3636 }
3637 if (save == 0)
3638 break;
3639 *cur = save;
3640 while (IS_BLANK(*cur)) cur++;
3641 }
3642 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003643 }
3644 }
3645 }
3646 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003647}
3648
3649/**
3650 * xmlValidateDtd:
3651 * @ctxt: the validation context
3652 * @doc: a document instance
3653 * @dtd: a dtd instance
3654 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003655 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003656 *
3657 * basically it does check all the definitions in the DtD.
3658 *
3659 * returns 1 if valid or 0 otherwise
3660 */
3661
3662int
3663xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003664 int ret;
3665 xmlDtdPtr oldExt;
3666 xmlNodePtr root;
3667
3668 if (dtd == NULL) return(0);
3669 if (doc == NULL) return(0);
3670 oldExt = doc->extSubset;
3671 doc->extSubset = dtd;
3672 ret = xmlValidateRoot(ctxt, doc);
3673 if (ret == 0) {
3674 doc->extSubset = oldExt;
3675 return(ret);
3676 }
3677 root = xmlDocGetRootElement(doc);
3678 ret = xmlValidateElement(ctxt, doc, root);
3679 ret &= xmlValidateDocumentFinal(ctxt, doc);
3680 doc->extSubset = oldExt;
3681 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003682}
3683
3684/**
Daniel Veillardcf461992000-03-14 18:30:20 +00003685 * xmlValidateDtdFinal:
3686 * @ctxt: the validation context
3687 * @doc: a document instance
3688 *
3689 * Does the final step for the dtds validation once all the
3690 * subsets have been parsed
3691 *
3692 * basically it does the following checks described by the XML Rec
3693 * - check that ENTITY and ENTITIES type attributes default or
3694 * possible values matches one of the defined entities.
3695 * - check that NOTATION type attributes default or
3696 * possible values matches one of the defined notations.
3697 *
3698 * returns 1 if valid or 0 otherwise
3699 */
3700
3701int
3702xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3703 int ret = 1, i;
3704 xmlDtdPtr dtd;
3705 xmlAttributeTablePtr table;
3706 xmlAttributePtr cur;
3707
3708 if (doc == NULL) return(0);
3709 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3710 return(0);
3711 dtd = doc->intSubset;
3712 if ((dtd != NULL) && (dtd->attributes != NULL)) {
3713 table = dtd->attributes;
3714
3715 for (i = 0;i < table->nb_attributes;i++) {
3716 cur = table->table[i];
3717 switch (cur->atype) {
3718 case XML_ATTRIBUTE_CDATA:
3719 case XML_ATTRIBUTE_ID:
3720 case XML_ATTRIBUTE_IDREF :
3721 case XML_ATTRIBUTE_IDREFS:
3722 case XML_ATTRIBUTE_NMTOKEN:
3723 case XML_ATTRIBUTE_NMTOKENS:
3724 case XML_ATTRIBUTE_ENUMERATION:
3725 break;
3726 case XML_ATTRIBUTE_ENTITY:
3727 case XML_ATTRIBUTE_ENTITIES:
3728 case XML_ATTRIBUTE_NOTATION:
3729 if (cur->defaultValue != NULL) {
3730 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
3731 cur->atype, cur->defaultValue);
3732 }
3733 if (cur->tree != NULL) {
3734 xmlEnumerationPtr tree = cur->tree;
3735 while (tree != NULL) {
3736 ret &= xmlValidateAttributeValue2(ctxt, doc,
3737 cur->name, cur->atype, tree->name);
3738 tree = tree->next;
3739 }
3740 }
3741 }
3742 }
3743 }
3744 dtd = doc->extSubset;
3745 if ((dtd != NULL) && (dtd->attributes != NULL)) {
3746 table = dtd->attributes;
3747
3748 for (i = 0;i < table->nb_attributes;i++) {
3749 cur = table->table[i];
3750 switch (cur->atype) {
3751 case XML_ATTRIBUTE_CDATA:
3752 case XML_ATTRIBUTE_ID:
3753 case XML_ATTRIBUTE_IDREF :
3754 case XML_ATTRIBUTE_IDREFS:
3755 case XML_ATTRIBUTE_NMTOKEN:
3756 case XML_ATTRIBUTE_NMTOKENS:
3757 case XML_ATTRIBUTE_ENUMERATION:
3758 break;
3759 case XML_ATTRIBUTE_ENTITY:
3760 case XML_ATTRIBUTE_ENTITIES:
3761 case XML_ATTRIBUTE_NOTATION:
3762 if (cur->defaultValue != NULL) {
3763 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
3764 cur->atype, cur->defaultValue);
3765 }
3766 if (cur->tree != NULL) {
3767 xmlEnumerationPtr tree = cur->tree;
3768 while (tree != NULL) {
3769 ret &= xmlValidateAttributeValue2(ctxt, doc,
3770 cur->name, cur->atype, tree->name);
3771 tree = tree->next;
3772 }
3773 }
3774 }
3775 }
3776 }
3777 return(ret);
3778}
3779
3780/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00003781 * xmlValidateDocument:
3782 * @ctxt: the validation context
3783 * @doc: a document instance
3784 *
3785 * Try to validate the document instance
3786 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003787 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00003788 * i.e. validates the internal and external subset (if present)
3789 * and validate the document tree.
3790 *
3791 * returns 1 if valid or 0 otherwise
3792 */
3793
3794int
3795xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003796 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003797 xmlNodePtr root;
3798
3799 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3800 return(0);
3801 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
3802 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
3803 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
3804 doc->intSubset->SystemID);
3805 if (doc->extSubset == NULL) {
3806 if (doc->intSubset->SystemID != NULL) {
3807 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003808 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003809 doc->intSubset->SystemID);
3810 } else {
3811 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003812 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003813 doc->intSubset->ExternalID);
3814 }
3815 return(0);
3816 }
3817 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003818
Daniel Veillardcf461992000-03-14 18:30:20 +00003819 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003820 if (!xmlValidateRoot(ctxt, doc)) return(0);
3821
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003822 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00003823 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003824 ret &= xmlValidateDocumentFinal(ctxt, doc);
3825 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003826}
3827
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003828
3829/************************************************************************
3830 * *
3831 * Routines for dynamic validation editing *
3832 * *
3833 ************************************************************************/
3834
3835/**
3836 * xmlValidGetPotentialChildren:
3837 * @ctree: an element content tree
3838 * @list: an array to store the list of child names
3839 * @len: a pointer to the number of element in the list
3840 * @max: the size of the array
3841 *
3842 * Build/extend a list of potential children allowed by the content tree
3843 *
3844 * returns the number of element in the list, or -1 in case of error.
3845 */
3846
3847int
3848xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
3849 int *len, int max) {
3850 int i;
3851
3852 if ((ctree == NULL) || (list == NULL) || (len == NULL))
3853 return(-1);
3854 if (*len >= max) return(*len);
3855
3856 switch (ctree->type) {
3857 case XML_ELEMENT_CONTENT_PCDATA:
3858 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00003859 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
3860 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003861 break;
3862 case XML_ELEMENT_CONTENT_ELEMENT:
3863 for (i = 0; i < *len;i++)
3864 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
3865 list[(*len)++] = ctree->name;
3866 break;
3867 case XML_ELEMENT_CONTENT_SEQ:
3868 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3869 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3870 break;
3871 case XML_ELEMENT_CONTENT_OR:
3872 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3873 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3874 break;
3875 }
3876
3877 return(*len);
3878}
3879
3880/**
3881 * xmlValidGetValidElements:
3882 * @prev: an element to insert after
3883 * @next: an element to insert next
3884 * @list: an array to store the list of child names
3885 * @max: the size of the array
3886 *
3887 * This function returns the list of authorized children to insert
3888 * within an existing tree while respecting the validity constraints
3889 * forced by the Dtd. The insertion point is defined using @prev and
3890 * @next in the following ways:
3891 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3892 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3893 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3894 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3895 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
3896 *
3897 * pointers to the element names are inserted at the beginning of the array
3898 * and do not need to be freed.
3899 *
3900 * returns the number of element in the list, or -1 in case of error. If
3901 * the function returns the value @max the caller is invited to grow the
3902 * receiving array and retry.
3903 */
3904
3905int
3906xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3907 int max) {
3908 int nb_valid_elements = 0;
3909 const xmlChar *elements[256];
3910 int nb_elements = 0, i;
3911
3912 xmlNode *ref_node;
3913 xmlNode *parent;
3914 xmlNode *test_node;
3915
3916 xmlNode *prev_next;
3917 xmlNode *next_prev;
3918 xmlNode *parent_childs;
3919 xmlNode *parent_last;
3920
3921 xmlElement *element_desc;
3922
3923 if (prev == NULL && next == NULL)
3924 return(-1);
3925
3926 if (list == NULL) return(-1);
3927 if (max <= 0) return(-1);
3928
3929 nb_valid_elements = 0;
3930 ref_node = prev ? prev : next;
3931 parent = ref_node->parent;
3932
3933 /*
3934 * Retrieves the parent element declaration
3935 */
3936 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3937 parent->name);
3938 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3939 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3940 parent->name);
3941 if (element_desc == NULL) return(-1);
3942
3943 /*
3944 * Do a backup of the current tree structure
3945 */
3946 prev_next = prev ? prev->next : NULL;
3947 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00003948 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003949 parent_last = parent->last;
3950
3951 /*
3952 * Creates a dummy node and insert it into the tree
3953 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003954 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003955 test_node->doc = ref_node->doc;
3956 test_node->parent = parent;
3957 test_node->prev = prev;
3958 test_node->next = next;
3959
3960 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00003961 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003962
3963 if (next) next->prev = test_node;
3964 else parent->last = test_node;
3965
3966 /*
3967 * Insert each potential child node and check if the parent is
3968 * still valid
3969 */
3970 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
3971 elements, &nb_elements, 256);
3972
3973 for (i = 0;i < nb_elements;i++) {
3974 test_node->name = elements[i];
3975 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
3976 int j;
3977
3978 for (j = 0; j < nb_valid_elements;j++)
3979 if (!xmlStrcmp(elements[i], list[j])) break;
3980 list[nb_valid_elements++] = elements[i];
3981 if (nb_valid_elements >= max) break;
3982 }
3983 }
3984
3985 /*
3986 * Restore the tree structure
3987 */
3988 if (prev) prev->next = prev_next;
3989 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00003990 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003991 parent->last = parent_last;
3992
3993 return(nb_valid_elements);
3994}