blob: a7ea860249c0ae336a4deef1fab7bf4f1cd7c76b [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
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include "valid.h"
14#include "parser.h"
Daniel Veillardb05deb71999-08-10 19:04:08 +000015#include "parserInternals.h"
16
17#define VERROR \
18 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
19
20#define VWARNING \
21 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
22
23#define CHECK_DTD \
24 if (doc == NULL) return(0); \
25 else if (doc->intSubset == NULL) return(0)
26
27xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name);
28xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000029
30/****************************************************************
31 * *
32 * Util functions for data allocation/deallocation *
33 * *
34 ****************************************************************/
35
36/**
37 * xmlNewElementContent:
38 * @name: the subelement name or NULL
39 * @type: the type of element content decl
40 *
41 * Allocate an element content structure.
42 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000043 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000044 */
45xmlElementContentPtr
46xmlNewElementContent(CHAR *name, int type) {
47 xmlElementContentPtr ret;
48
49 switch(type) {
50 case XML_ELEMENT_CONTENT_ELEMENT:
51 if (name == NULL) {
52 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
53 }
54 break;
55 case XML_ELEMENT_CONTENT_PCDATA:
56 case XML_ELEMENT_CONTENT_SEQ:
57 case XML_ELEMENT_CONTENT_OR:
58 if (name != NULL) {
59 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
60 }
61 break;
62 default:
63 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
64 exit(1);
65 }
66 ret = (xmlElementContentPtr) malloc(sizeof(xmlElementContent));
67 if (ret == NULL) {
68 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
69 return(NULL);
70 }
71 ret->type = type;
72 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +000073 if (name != NULL)
74 ret->name = xmlStrdup(name);
75 else
76 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +000077 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000078 return(ret);
79}
80
81/**
Daniel Veillard3b9def11999-01-31 22:15:06 +000082 * xmlCopyElementContent:
83 * @content: An element content pointer.
84 *
85 * Build a copy of an element content description.
86 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000087 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +000088 */
89xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +000090xmlCopyElementContent(xmlElementContentPtr cur) {
91 xmlElementContentPtr ret;
92
93 if (cur == NULL) return(NULL);
94 ret = xmlNewElementContent((CHAR *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +000095 if (ret == NULL) {
96 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
97 return(NULL);
98 }
99 ret->ocur = cur->ocur;
100 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
101 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000102 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000103}
104
105/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000106 * xmlFreeElementContent:
107 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000108 *
109 * Free an element content structure. This is a recursive call !
110 */
111void
112xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000113 if (cur == NULL) return;
114 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
115 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
116 if (cur->name != NULL) free((CHAR *) cur->name);
117 memset(cur, -1, sizeof(xmlElementContent));
118 free(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000119}
120
Daniel Veillard1899e851999-02-01 12:18:54 +0000121/**
122 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000123 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000124 * @content: An element table
125 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
126 *
127 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000128 */
129void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000130xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000131 if (content == NULL) return;
132
Daniel Veillard5099ae81999-04-21 20:12:07 +0000133 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000134 switch (content->type) {
135 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000136 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000137 break;
138 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000139 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000140 break;
141 case XML_ELEMENT_CONTENT_SEQ:
142 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
143 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000144 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000145 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000146 xmlDumpElementContent(buf, content->c1, 0);
147 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000148 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000149 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000150 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000151 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000152 break;
153 case XML_ELEMENT_CONTENT_OR:
154 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
155 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000156 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000157 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000158 xmlDumpElementContent(buf, content->c1, 0);
159 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000160 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000161 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000162 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000163 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000164 break;
165 default:
166 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
167 content->type);
168 }
169 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000170 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000171 switch (content->ocur) {
172 case XML_ELEMENT_CONTENT_ONCE:
173 break;
174 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000175 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000176 break;
177 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000178 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000179 break;
180 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000181 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000182 break;
183 }
184}
185
Daniel Veillardb05deb71999-08-10 19:04:08 +0000186/**
187 * xmlSprintfElementContent:
188 * @buf: an output buffer
189 * @content: An element table
190 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
191 *
192 * This will dump the content of the element content definition
193 * Intended just for the debug routine
194 */
195void
196xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
197 if (content == NULL) return;
198 if (glob) strcat(buf, "(");
199 switch (content->type) {
200 case XML_ELEMENT_CONTENT_PCDATA:
201 strcat(buf, "#PCDATA");
202 break;
203 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000204 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000205 break;
206 case XML_ELEMENT_CONTENT_SEQ:
207 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
208 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
209 xmlSprintfElementContent(buf, content->c1, 1);
210 else
211 xmlSprintfElementContent(buf, content->c1, 0);
212 strcat(buf, " , ");
213 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
214 xmlSprintfElementContent(buf, content->c2, 1);
215 else
216 xmlSprintfElementContent(buf, content->c2, 0);
217 break;
218 case XML_ELEMENT_CONTENT_OR:
219 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
220 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
221 xmlSprintfElementContent(buf, content->c1, 1);
222 else
223 xmlSprintfElementContent(buf, content->c1, 0);
224 strcat(buf, " | ");
225 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
226 xmlSprintfElementContent(buf, content->c2, 1);
227 else
228 xmlSprintfElementContent(buf, content->c2, 0);
229 break;
230 }
231 if (glob)
232 strcat(buf, ")");
233 switch (content->ocur) {
234 case XML_ELEMENT_CONTENT_ONCE:
235 break;
236 case XML_ELEMENT_CONTENT_OPT:
237 strcat(buf, "?");
238 break;
239 case XML_ELEMENT_CONTENT_MULT:
240 strcat(buf, "*");
241 break;
242 case XML_ELEMENT_CONTENT_PLUS:
243 strcat(buf, "+");
244 break;
245 }
246}
247
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000248/****************************************************************
249 * *
250 * Registration of DTD declarations *
251 * *
252 ****************************************************************/
253
Daniel Veillard3b9def11999-01-31 22:15:06 +0000254/**
255 * xmlCreateElementTable:
256 *
257 * create and initialize an empty element hash table.
258 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000259 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000260 */
261xmlElementTablePtr
262xmlCreateElementTable(void) {
263 xmlElementTablePtr ret;
264
265 ret = (xmlElementTablePtr)
266 malloc(sizeof(xmlElementTable));
267 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000268 fprintf(stderr, "xmlCreateElementTable : malloc(%ld) failed\n",
269 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000270 return(NULL);
271 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000272 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000273 ret->nb_elements = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000274 ret->table = (xmlElementPtr *)
275 malloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000276 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000277 fprintf(stderr, "xmlCreateElementTable : malloc(%ld) failed\n",
278 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000279 free(ret);
280 return(NULL);
281 }
282 return(ret);
283}
284
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000285
286/**
287 * xmlAddElementDecl:
Daniel Veillard1e346af1999-02-22 10:33:01 +0000288 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000289 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000290 * @type: the element type
291 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000292 *
293 * Register a new element declaration
294 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000295 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000296 */
297xmlElementPtr
Daniel Veillardb05deb71999-08-10 19:04:08 +0000298xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
299 int type, xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000300 xmlElementPtr ret, cur;
301 xmlElementTablePtr table;
302 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000303
304 if (dtd == NULL) {
305 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
306 return(NULL);
307 }
308 if (name == NULL) {
309 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
310 return(NULL);
311 }
312 switch (type) {
313 case XML_ELEMENT_TYPE_EMPTY:
314 if (content != NULL) {
315 fprintf(stderr,
316 "xmlAddElementDecl: content != NULL for EMPTY\n");
317 return(NULL);
318 }
319 break;
320 case XML_ELEMENT_TYPE_ANY:
321 if (content != NULL) {
322 fprintf(stderr,
323 "xmlAddElementDecl: content != NULL for ANY\n");
324 return(NULL);
325 }
326 break;
327 case XML_ELEMENT_TYPE_MIXED:
328 if (content == NULL) {
329 fprintf(stderr,
330 "xmlAddElementDecl: content == NULL for MIXED\n");
331 return(NULL);
332 }
333 break;
334 case XML_ELEMENT_TYPE_ELEMENT:
335 if (content == NULL) {
336 fprintf(stderr,
337 "xmlAddElementDecl: content == NULL for ELEMENT\n");
338 return(NULL);
339 }
340 break;
341 default:
342 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
343 return(NULL);
344 }
345
346 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000347 * Create the Element table if needed.
348 */
349 table = dtd->elements;
350 if (table == NULL)
351 table = dtd->elements = xmlCreateElementTable();
352 if (table == NULL) {
353 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
354 return(NULL);
355 }
356
357 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000358 * Validity Check:
359 * Search the DTD for previous declarations of the ELEMENT
360 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000361 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000362 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000363 if (!xmlStrcmp(cur->name, name)) {
364 /*
365 * The element is already defined in this Dtd.
366 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000367 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000368 return(NULL);
369 }
370 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000371
372 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000373 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000374 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000375 if (table->nb_elements >= table->max_elements) {
376 /*
377 * need more elements.
378 */
379 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000380 table->table = (xmlElementPtr *)
381 realloc(table->table, table->max_elements * sizeof(xmlElementPtr));
382 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000383 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
384 return(NULL);
385 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000386 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000387 ret = (xmlElementPtr) malloc(sizeof(xmlElement));
388 if (ret == NULL) {
389 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
390 return(NULL);
391 }
392 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000393
394 /*
395 * fill the structure.
396 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000397 ret->type = type;
398 ret->name = xmlStrdup(name);
Daniel Veillard14fff061999-06-22 21:49:07 +0000399 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000400 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000401 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000402
403 return(ret);
404}
405
Daniel Veillard3b9def11999-01-31 22:15:06 +0000406/**
407 * xmlFreeElement:
408 * @elem: An element
409 *
410 * Deallocate the memory used by an element definition
411 */
412void
413xmlFreeElement(xmlElementPtr elem) {
414 if (elem == NULL) return;
415 xmlFreeElementContent(elem->content);
416 if (elem->name != NULL)
417 free((CHAR *) elem->name);
418 memset(elem, -1, sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000419 free(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000420}
421
422/**
423 * xmlFreeElementTable:
424 * @table: An element table
425 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000426 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000427 */
428void
429xmlFreeElementTable(xmlElementTablePtr table) {
430 int i;
431
432 if (table == NULL) return;
433
434 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000435 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000436 }
437 free(table->table);
438 free(table);
439}
440
441/**
442 * xmlCopyElementTable:
443 * @table: An element table
444 *
445 * Build a copy of an element table.
446 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000447 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000448 */
449xmlElementTablePtr
450xmlCopyElementTable(xmlElementTablePtr table) {
451 xmlElementTablePtr ret;
452 xmlElementPtr cur, ent;
453 int i;
454
455 ret = (xmlElementTablePtr) malloc(sizeof(xmlElementTable));
456 if (ret == NULL) {
457 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
458 return(NULL);
459 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000460 ret->table = (xmlElementPtr *) malloc(table->max_elements *
461 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000462 if (ret->table == NULL) {
463 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
464 free(ret);
465 return(NULL);
466 }
467 ret->max_elements = table->max_elements;
468 ret->nb_elements = table->nb_elements;
469 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000470 cur = (xmlElementPtr) malloc(sizeof(xmlElement));
471 if (cur == NULL) {
472 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
473 free(ret);
474 free(ret->table);
475 return(NULL);
476 }
477 ret->table[i] = cur;
478 ent = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000479 cur->type = ent->type;
480 if (ent->name != NULL)
481 cur->name = xmlStrdup(ent->name);
482 else
483 cur->name = NULL;
484 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000485 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000486 }
487 return(ret);
488}
489
490/**
491 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000492 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000493 * @table: An element table
494 *
495 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000496 */
497void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000498xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000499 int i;
500 xmlElementPtr cur;
501
502 if (table == NULL) return;
503
504 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000505 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000506 switch (cur->type) {
507 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000508 xmlBufferWriteChar(buf, "<!ELEMENT ");
509 xmlBufferWriteCHAR(buf, cur->name);
510 xmlBufferWriteChar(buf, " EMPTY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000511 break;
512 case XML_ELEMENT_TYPE_ANY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000513 xmlBufferWriteChar(buf, "<!ELEMENT ");
514 xmlBufferWriteCHAR(buf, cur->name);
515 xmlBufferWriteChar(buf, " ANY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000516 break;
517 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000518 xmlBufferWriteChar(buf, "<!ELEMENT ");
519 xmlBufferWriteCHAR(buf, cur->name);
520 xmlBufferWriteChar(buf, " ");
521 xmlDumpElementContent(buf, cur->content, 1);
522 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000523 break;
524 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000525 xmlBufferWriteChar(buf, "<!ELEMENT ");
526 xmlBufferWriteCHAR(buf, cur->name);
527 xmlBufferWriteChar(buf, " ");
528 xmlDumpElementContent(buf, cur->content, 1);
529 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000530 break;
531 default:
532 fprintf(stderr,
533 "xmlDumpElementTable: internal: unknown type %d\n",
534 cur->type);
535 }
536 }
537}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000538
539/**
540 * xmlCreateEnumeration:
541 * @name: the enumeration name or NULL
542 *
543 * create and initialize an enumeration attribute node.
544 *
545 * Returns the xmlEnumerationPtr just created or NULL in case
546 * of error.
547 */
548xmlEnumerationPtr
549xmlCreateEnumeration(CHAR *name) {
550 xmlEnumerationPtr ret;
551
552 ret = (xmlEnumerationPtr) malloc(sizeof(xmlEnumeration));
553 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000554 fprintf(stderr, "xmlCreateEnumeration : malloc(%ld) failed\n",
555 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000556 return(NULL);
557 }
558
559 if (name != NULL)
560 ret->name = xmlStrdup(name);
561 else
562 ret->name = NULL;
563 ret->next = NULL;
564 return(ret);
565}
566
567/**
568 * xmlFreeEnumeration:
569 * @cur: the tree to free.
570 *
571 * free an enumeration attribute node (recursive).
572 */
573void
574xmlFreeEnumeration(xmlEnumerationPtr cur) {
575 if (cur == NULL) return;
576
577 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
578
579 if (cur->name != NULL) free((CHAR *) cur->name);
580 memset(cur, -1, sizeof(xmlEnumeration));
581 free(cur);
582}
583
584/**
585 * xmlCopyEnumeration:
586 * @cur: the tree to copy.
587 *
588 * Copy an enumeration attribute node (recursive).
589 *
590 * Returns the xmlEnumerationPtr just created or NULL in case
591 * of error.
592 */
593xmlEnumerationPtr
594xmlCopyEnumeration(xmlEnumerationPtr cur) {
595 xmlEnumerationPtr ret;
596
597 if (cur == NULL) return(NULL);
598 ret = xmlCreateEnumeration((CHAR *) cur->name);
599
600 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
601 else ret->next = NULL;
602
603 return(ret);
604}
605
606/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000607 * xmlDumpEnumeration:
608 * @buf: the XML buffer output
609 * @enum: An enumeration
610 *
611 * This will dump the content of the enumeration
612 */
613void
614xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
615 if (cur == NULL) return;
616
617 xmlBufferWriteCHAR(buf, cur->name);
618 if (cur->next == NULL)
619 xmlBufferWriteChar(buf, ")");
620 else {
621 xmlBufferWriteChar(buf, " | ");
622 xmlDumpEnumeration(buf, cur->next);
623 }
624}
625
626/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000627 * xmlCreateAttributeTable:
628 *
629 * create and initialize an empty attribute hash table.
630 *
631 * Returns the xmlAttributeTablePtr just created or NULL in case
632 * of error.
633 */
634xmlAttributeTablePtr
635xmlCreateAttributeTable(void) {
636 xmlAttributeTablePtr ret;
637
638 ret = (xmlAttributeTablePtr)
639 malloc(sizeof(xmlAttributeTable));
640 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000641 fprintf(stderr, "xmlCreateAttributeTable : malloc(%ld) failed\n",
642 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000643 return(NULL);
644 }
645 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
646 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000647 ret->table = (xmlAttributePtr *)
648 malloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000649 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000650 fprintf(stderr, "xmlCreateAttributeTable : malloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000651 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000652 free(ret);
653 return(NULL);
654 }
655 return(ret);
656}
657
Daniel Veillardb05deb71999-08-10 19:04:08 +0000658/**
659 * xmlScanAttributeDecl:
660 * @dtd: pointer to the DTD
661 * @elem: the element name
662 *
663 * When inserting a new element scan the DtD for existing attributes
664 * for taht element and initialize the Attribute chain
665 *
666 * Returns the pointer to the first attribute decl in the chain,
667 * possibly NULL.
668 */
669xmlAttributePtr
670xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem) {
671 xmlAttributePtr ret = NULL;
672 xmlAttributeTablePtr table;
673 int i;
674
675 if (dtd == NULL) {
676 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
677 return(NULL);
678 }
679 if (elem == NULL) {
680 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
681 return(NULL);
682 }
683 table = dtd->attributes;
684 if (table == NULL)
685 return(NULL);
686
687 for (i = 0;i < table->nb_attributes;i++) {
688 if (!xmlStrcmp(table->table[i]->elem, elem)) {
689 table->table[i]->next = ret;
690 ret = table->table[i];
691 }
692 }
693 return(ret);
694}
695
696/**
697 * xmlScanIDAttributeDecl:
698 * @ctxt: the validation context
699 * @elem: the element name
700 *
701 * Veryfy that the element don't have too many ID attributes
702 * declared.
703 *
704 * Returns the number of ID attributes found.
705 */
706int
707xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
708 xmlAttributePtr cur;
709 int ret = 0;
710
711 if (elem == NULL) return(0);
712 cur = elem->attributes;
713 while (cur != NULL) {
714 if (cur->type == XML_ATTRIBUTE_ID) {
715 ret ++;
716 if (ret > 1)
717 VERROR(ctxt->userData,
718 "Element %s has too may ID attributes defined : %s\n",
719 elem->name, cur->name);
720 }
721 cur = cur->next;
722 }
723 return(ret);
724}
725
Daniel Veillard1e346af1999-02-22 10:33:01 +0000726
727/**
728 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000729 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000730 * @dtd: pointer to the DTD
731 * @elem: the element name
732 * @name: the attribute name
733 * @type: the attribute type
734 * @def: the attribute default type
735 * @defaultValue: the attribute default value
736 * @tree: if it's an enumeration, the associated list
737 *
738 * Register a new attribute declaration
739 *
740 * Returns NULL if not, othervise the entity
741 */
742xmlAttributePtr
Daniel Veillardb05deb71999-08-10 19:04:08 +0000743xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *elem,
744 const CHAR *name, int type, int def,
745 const CHAR *defaultValue, xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000746 xmlAttributePtr ret, cur;
747 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000748 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000749 int i;
750
751 if (dtd == NULL) {
752 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
753 return(NULL);
754 }
755 if (name == NULL) {
756 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
757 return(NULL);
758 }
759 if (elem == NULL) {
760 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
761 return(NULL);
762 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000763 /*
764 * Check the type and possibly the default value.
765 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000766 switch (type) {
767 case XML_ATTRIBUTE_CDATA:
768 break;
769 case XML_ATTRIBUTE_ID:
770 break;
771 case XML_ATTRIBUTE_IDREF:
772 break;
773 case XML_ATTRIBUTE_IDREFS:
774 break;
775 case XML_ATTRIBUTE_ENTITY:
776 break;
777 case XML_ATTRIBUTE_ENTITIES:
778 break;
779 case XML_ATTRIBUTE_NMTOKEN:
780 break;
781 case XML_ATTRIBUTE_NMTOKENS:
782 break;
783 case XML_ATTRIBUTE_ENUMERATION:
784 break;
785 case XML_ATTRIBUTE_NOTATION:
786 break;
787 default:
788 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
789 return(NULL);
790 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000791 if ((defaultValue != NULL) &&
792 (!xmlValidateAttributeValue(type, defaultValue))) {
793 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
794 elem, name, defaultValue);
795 defaultValue = NULL;
796 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000797
798 /*
799 * Create the Attribute table if needed.
800 */
801 table = dtd->attributes;
802 if (table == NULL)
803 table = dtd->attributes = xmlCreateAttributeTable();
804 if (table == NULL) {
805 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
806 return(NULL);
807 }
808
809 /*
810 * Validity Check:
811 * Search the DTD for previous declarations of the ATTLIST
812 */
813 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000814 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +0000815 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
816 /*
817 * The attribute is already defined in this Dtd.
818 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000819 VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
820 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000821 }
822 }
823
824 /*
825 * Grow the table, if needed.
826 */
827 if (table->nb_attributes >= table->max_attributes) {
828 /*
829 * need more attributes.
830 */
831 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000832 table->table = (xmlAttributePtr *)
833 realloc(table->table, table->max_attributes *
834 sizeof(xmlAttributePtr));
835 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000836 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
837 return(NULL);
838 }
839 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000840 ret = (xmlAttributePtr) malloc(sizeof(xmlAttribute));
841 if (ret == NULL) {
842 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
843 return(NULL);
844 }
845 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000846
847 /*
848 * fill the structure.
849 */
850 ret->type = type;
851 ret->name = xmlStrdup(name);
852 ret->elem = xmlStrdup(elem);
853 ret->def = def;
854 ret->tree = tree;
855 if (defaultValue != NULL)
856 ret->defaultValue = xmlStrdup(defaultValue);
857 else
858 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000859 elemDef = xmlGetDtdElementDesc(dtd, elem);
860 if (elemDef != NULL) {
861 if ((type == XML_ATTRIBUTE_ID) &&
862 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
863 VERROR(ctxt->userData,
864 "Element %s has too may ID attributes defined : %s\n",
865 elem, name);
866 ret->next = elemDef->attributes;
867 elemDef->attributes = ret;
868 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000869 table->nb_attributes++;
870
871 return(ret);
872}
873
874/**
875 * xmlFreeAttribute:
876 * @elem: An attribute
877 *
878 * Deallocate the memory used by an attribute definition
879 */
880void
881xmlFreeAttribute(xmlAttributePtr attr) {
882 if (attr == NULL) return;
883 if (attr->tree != NULL)
884 xmlFreeEnumeration(attr->tree);
885 if (attr->elem != NULL)
886 free((CHAR *) attr->elem);
887 if (attr->name != NULL)
888 free((CHAR *) attr->name);
889 if (attr->defaultValue != NULL)
890 free((CHAR *) attr->defaultValue);
891 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000892 free(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000893}
894
895/**
896 * xmlFreeAttributeTable:
897 * @table: An attribute table
898 *
899 * Deallocate the memory used by an entities hash table.
900 */
901void
902xmlFreeAttributeTable(xmlAttributeTablePtr table) {
903 int i;
904
905 if (table == NULL) return;
906
907 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000908 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000909 }
910 free(table->table);
911 free(table);
912}
913
914/**
915 * xmlCopyAttributeTable:
916 * @table: An attribute table
917 *
918 * Build a copy of an attribute table.
919 *
920 * Returns the new xmlAttributeTablePtr or NULL in case of error.
921 */
922xmlAttributeTablePtr
923xmlCopyAttributeTable(xmlAttributeTablePtr table) {
924 xmlAttributeTablePtr ret;
925 xmlAttributePtr cur, attr;
926 int i;
927
928 ret = (xmlAttributeTablePtr) malloc(sizeof(xmlAttributeTable));
929 if (ret == NULL) {
930 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
931 return(NULL);
932 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000933 ret->table = (xmlAttributePtr *) malloc(table->max_attributes *
934 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000935 if (ret->table == NULL) {
936 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
937 free(ret);
938 return(NULL);
939 }
940 ret->max_attributes = table->max_attributes;
941 ret->nb_attributes = table->nb_attributes;
942 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000943 attr = table->table[i];
944 cur = (xmlAttributePtr) malloc(sizeof(xmlAttribute));
945 if (cur == NULL) {
946 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
947 free(ret);
948 free(ret->table);
949 return(NULL);
950 }
951 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000952 cur->type = attr->type;
953 cur->def = attr->def;
954 cur->tree = xmlCopyEnumeration(attr->tree);
955 if (attr->elem != NULL)
956 cur->elem = xmlStrdup(attr->elem);
957 else
958 cur->elem = NULL;
959 if (attr->name != NULL)
960 cur->name = xmlStrdup(attr->name);
961 else
962 cur->name = NULL;
963 if (attr->defaultValue != NULL)
964 cur->defaultValue = xmlStrdup(attr->defaultValue);
965 else
966 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000967 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000968 }
969 return(ret);
970}
971
972/**
973 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000974 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +0000975 * @table: An attribute table
976 *
977 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +0000978 */
979void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000980xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000981 int i;
982 xmlAttributePtr cur;
983
984 if (table == NULL) return;
985
986 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000987 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +0000988 xmlBufferWriteChar(buf, "<!ATTLIST ");
989 xmlBufferWriteCHAR(buf, cur->elem);
990 xmlBufferWriteChar(buf, " ");
991 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000992 switch (cur->type) {
993 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000994 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +0000995 break;
996 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000997 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +0000998 break;
999 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001000 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001001 break;
1002 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001003 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001004 break;
1005 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001006 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001007 break;
1008 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001009 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001010 break;
1011 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001012 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001013 break;
1014 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001015 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001016 break;
1017 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001018 xmlBufferWriteChar(buf, " (");
1019 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001020 break;
1021 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001022 xmlBufferWriteChar(buf, " NOTATION (");
1023 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001024 break;
1025 default:
1026 fprintf(stderr,
1027 "xmlDumpAttributeTable: internal: unknown type %d\n",
1028 cur->type);
1029 }
1030 switch (cur->def) {
1031 case XML_ATTRIBUTE_NONE:
1032 break;
1033 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001034 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001035 break;
1036 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001037 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001038 break;
1039 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001040 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001041 break;
1042 default:
1043 fprintf(stderr,
1044 "xmlDumpAttributeTable: internal: unknown default %d\n",
1045 cur->def);
1046 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001047 if (cur->defaultValue != NULL) {
1048 xmlBufferWriteChar(buf, " ");
1049 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1050 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001051 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001052 }
1053}
1054
1055/************************************************************************
1056 * *
1057 * NOTATIONs *
1058 * *
1059 ************************************************************************/
1060/**
1061 * xmlCreateNotationTable:
1062 *
1063 * create and initialize an empty notation hash table.
1064 *
1065 * Returns the xmlNotationTablePtr just created or NULL in case
1066 * of error.
1067 */
1068xmlNotationTablePtr
1069xmlCreateNotationTable(void) {
1070 xmlNotationTablePtr ret;
1071
1072 ret = (xmlNotationTablePtr)
1073 malloc(sizeof(xmlNotationTable));
1074 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001075 fprintf(stderr, "xmlCreateNotationTable : malloc(%ld) failed\n",
1076 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001077 return(NULL);
1078 }
1079 ret->max_notations = XML_MIN_NOTATION_TABLE;
1080 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001081 ret->table = (xmlNotationPtr *)
1082 malloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001083 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001084 fprintf(stderr, "xmlCreateNotationTable : malloc(%ld) failed\n",
1085 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001086 free(ret);
1087 return(NULL);
1088 }
1089 return(ret);
1090}
1091
1092
1093/**
1094 * xmlAddNotationDecl:
1095 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001096 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001097 * @name: the entity name
1098 * @PublicID: the public identifier or NULL
1099 * @SystemID: the system identifier or NULL
1100 *
1101 * Register a new notation declaration
1102 *
1103 * Returns NULL if not, othervise the entity
1104 */
1105xmlNotationPtr
Daniel Veillardb05deb71999-08-10 19:04:08 +00001106xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
1107 const CHAR *PublicID, const CHAR *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001108 xmlNotationPtr ret, cur;
1109 xmlNotationTablePtr table;
1110 int i;
1111
1112 if (dtd == NULL) {
1113 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1114 return(NULL);
1115 }
1116 if (name == NULL) {
1117 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1118 return(NULL);
1119 }
1120 if ((PublicID == NULL) && (SystemID == NULL)) {
1121 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1122 }
1123
1124 /*
1125 * Create the Notation table if needed.
1126 */
1127 table = dtd->notations;
1128 if (table == NULL)
1129 table = dtd->notations = xmlCreateNotationTable();
1130 if (table == NULL) {
1131 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1132 return(NULL);
1133 }
1134
1135 /*
1136 * Validity Check:
1137 * Search the DTD for previous declarations of the ATTLIST
1138 */
1139 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001140 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001141 if (!xmlStrcmp(cur->name, name)) {
1142 /*
1143 * The notation is already defined in this Dtd.
1144 */
1145 fprintf(stderr,
1146 "xmlAddNotationDecl: %s already defined\n", name);
1147 }
1148 }
1149
1150 /*
1151 * Grow the table, if needed.
1152 */
1153 if (table->nb_notations >= table->max_notations) {
1154 /*
1155 * need more notations.
1156 */
1157 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001158 table->table = (xmlNotationPtr *)
1159 realloc(table->table, table->max_notations *
1160 sizeof(xmlNotationPtr));
1161 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001162 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1163 return(NULL);
1164 }
1165 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001166 ret = (xmlNotationPtr) malloc(sizeof(xmlNotation));
1167 if (ret == NULL) {
1168 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1169 return(NULL);
1170 }
1171 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001172
1173 /*
1174 * fill the structure.
1175 */
1176 ret->name = xmlStrdup(name);
1177 if (SystemID != NULL)
1178 ret->SystemID = xmlStrdup(SystemID);
1179 else
1180 ret->SystemID = NULL;
1181 if (PublicID != NULL)
1182 ret->PublicID = xmlStrdup(PublicID);
1183 else
1184 ret->PublicID = NULL;
1185 table->nb_notations++;
1186
1187 return(ret);
1188}
1189
1190/**
1191 * xmlFreeNotation:
1192 * @not: A notation
1193 *
1194 * Deallocate the memory used by an notation definition
1195 */
1196void
1197xmlFreeNotation(xmlNotationPtr nota) {
1198 if (nota == NULL) return;
1199 if (nota->name != NULL)
1200 free((CHAR *) nota->name);
1201 if (nota->PublicID != NULL)
1202 free((CHAR *) nota->PublicID);
1203 if (nota->SystemID != NULL)
1204 free((CHAR *) nota->SystemID);
1205 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001206 free(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001207}
1208
1209/**
1210 * xmlFreeNotationTable:
1211 * @table: An notation table
1212 *
1213 * Deallocate the memory used by an entities hash table.
1214 */
1215void
1216xmlFreeNotationTable(xmlNotationTablePtr table) {
1217 int i;
1218
1219 if (table == NULL) return;
1220
1221 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001222 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001223 }
1224 free(table->table);
1225 free(table);
1226}
1227
1228/**
1229 * xmlCopyNotationTable:
1230 * @table: A notation table
1231 *
1232 * Build a copy of a notation table.
1233 *
1234 * Returns the new xmlNotationTablePtr or NULL in case of error.
1235 */
1236xmlNotationTablePtr
1237xmlCopyNotationTable(xmlNotationTablePtr table) {
1238 xmlNotationTablePtr ret;
1239 xmlNotationPtr cur, nota;
1240 int i;
1241
1242 ret = (xmlNotationTablePtr) malloc(sizeof(xmlNotationTable));
1243 if (ret == NULL) {
1244 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1245 return(NULL);
1246 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001247 ret->table = (xmlNotationPtr *) malloc(table->max_notations *
1248 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001249 if (ret->table == NULL) {
1250 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1251 free(ret);
1252 return(NULL);
1253 }
1254 ret->max_notations = table->max_notations;
1255 ret->nb_notations = table->nb_notations;
1256 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001257 cur = (xmlNotationPtr) malloc(sizeof(xmlNotation));
1258 if (cur == NULL) {
1259 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1260 free(ret);
1261 free(ret->table);
1262 return(NULL);
1263 }
1264 ret->table[i] = cur;
1265 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001266 if (nota->name != NULL)
1267 cur->name = xmlStrdup(nota->name);
1268 else
1269 cur->name = NULL;
1270 if (nota->PublicID != NULL)
1271 cur->PublicID = xmlStrdup(nota->PublicID);
1272 else
1273 cur->PublicID = NULL;
1274 if (nota->SystemID != NULL)
1275 cur->SystemID = xmlStrdup(nota->SystemID);
1276 else
1277 cur->SystemID = NULL;
1278 }
1279 return(ret);
1280}
1281
1282/**
1283 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001284 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001285 * @table: A notation table
1286 *
1287 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001288 */
1289void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001290xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001291 int i;
1292 xmlNotationPtr cur;
1293
1294 if (table == NULL) return;
1295
1296 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001297 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001298 xmlBufferWriteChar(buf, "<!NOTATION ");
1299 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001300 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001301 xmlBufferWriteChar(buf, " PUBLIC ");
1302 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001303 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001304 xmlBufferWriteChar(buf, " ");
1305 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001306 }
1307 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001308 xmlBufferWriteChar(buf, " SYSTEM ");
1309 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001310 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001311 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001312 }
1313}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001314
1315/************************************************************************
1316 * *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001317 * NOTATIONs *
1318 * *
1319 ************************************************************************/
1320/**
1321 * xmlCreateIDTable:
1322 *
1323 * create and initialize an empty id hash table.
1324 *
1325 * Returns the xmlIDTablePtr just created or NULL in case
1326 * of error.
1327 */
1328xmlIDTablePtr
1329xmlCreateIDTable(void) {
1330 xmlIDTablePtr ret;
1331
1332 ret = (xmlIDTablePtr)
1333 malloc(sizeof(xmlIDTable));
1334 if (ret == NULL) {
1335 fprintf(stderr, "xmlCreateIDTable : malloc(%ld) failed\n",
1336 (long)sizeof(xmlIDTable));
1337 return(NULL);
1338 }
1339 ret->max_ids = XML_MIN_NOTATION_TABLE;
1340 ret->nb_ids = 0;
1341 ret->table = (xmlIDPtr *)
1342 malloc(ret->max_ids * sizeof(xmlIDPtr));
1343 if (ret == NULL) {
1344 fprintf(stderr, "xmlCreateIDTable : malloc(%ld) failed\n",
1345 ret->max_ids * (long)sizeof(xmlID));
1346 free(ret);
1347 return(NULL);
1348 }
1349 return(ret);
1350}
1351
1352
1353/**
1354 * xmlAddID:
1355 * @ctxt: the validation context
1356 * @doc: pointer to the document
1357 * @value: the value name
1358 * @attr: the attribute holding the ID
1359 *
1360 * Register a new id declaration
1361 *
1362 * Returns NULL if not, othervise the new xmlIDPtr
1363 */
1364xmlIDPtr
1365xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
1366 xmlAttrPtr attr) {
1367 xmlIDPtr ret, cur;
1368 xmlIDTablePtr table;
1369 int i;
1370
1371 if (doc == NULL) {
1372 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1373 return(NULL);
1374 }
1375 if (value == NULL) {
1376 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1377 return(NULL);
1378 }
1379 if (attr == NULL) {
1380 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1381 return(NULL);
1382 }
1383
1384 /*
1385 * Create the ID table if needed.
1386 */
1387 table = doc->ids;
1388 if (table == NULL)
1389 table = doc->ids = xmlCreateIDTable();
1390 if (table == NULL) {
1391 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1392 return(NULL);
1393 }
1394
1395 /*
1396 * Validity Check:
1397 * Search the DTD for previous declarations of the ATTLIST
1398 */
1399 for (i = 0;i < table->nb_ids;i++) {
1400 cur = table->table[i];
1401 if (!xmlStrcmp(cur->value, value)) {
1402 /*
1403 * The id is already defined in this Dtd.
1404 */
1405 VERROR(ctxt->userData, "ID %s already defined\n", value);
1406 return(NULL);
1407 }
1408 }
1409
1410 /*
1411 * Grow the table, if needed.
1412 */
1413 if (table->nb_ids >= table->max_ids) {
1414 /*
1415 * need more ids.
1416 */
1417 table->max_ids *= 2;
1418 table->table = (xmlIDPtr *)
1419 realloc(table->table, table->max_ids *
1420 sizeof(xmlIDPtr));
1421 if (table->table == NULL) {
1422 fprintf(stderr, "xmlAddID: out of memory\n");
1423 return(NULL);
1424 }
1425 }
1426 ret = (xmlIDPtr) malloc(sizeof(xmlID));
1427 if (ret == NULL) {
1428 fprintf(stderr, "xmlAddID: out of memory\n");
1429 return(NULL);
1430 }
1431 table->table[table->nb_ids] = ret;
1432
1433 /*
1434 * fill the structure.
1435 */
1436 ret->value = xmlStrdup(value);
1437 ret->attr = attr;
1438 table->nb_ids++;
1439
1440 return(ret);
1441}
1442
1443/**
1444 * xmlFreeID:
1445 * @not: A id
1446 *
1447 * Deallocate the memory used by an id definition
1448 */
1449void
1450xmlFreeID(xmlIDPtr id) {
1451 if (id == NULL) return;
1452 if (id->value != NULL)
1453 free((CHAR *) id->value);
1454 memset(id, -1, sizeof(xmlID));
1455 free(id);
1456}
1457
1458/**
1459 * xmlFreeIDTable:
1460 * @table: An id table
1461 *
1462 * Deallocate the memory used by an ID hash table.
1463 */
1464void
1465xmlFreeIDTable(xmlIDTablePtr table) {
1466 int i;
1467
1468 if (table == NULL) return;
1469
1470 for (i = 0;i < table->nb_ids;i++) {
1471 xmlFreeID(table->table[i]);
1472 }
1473 free(table->table);
1474 free(table);
1475}
1476
1477/**
1478 * xmlIsID
1479 * @doc: the document
1480 * @elem: the element carrying the attribute
1481 * @attr: the attribute
1482 *
1483 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1484 * then this is simple, otherwise we use an heuristic: name ID (upper
1485 * or lowercase).
1486 *
1487 * Returns 0 or 1 depending on the lookup result
1488 */
1489int
1490xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1491 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1492 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1493 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1494 (attr->name[2] == 0)) return(1);
1495 } else {
1496 xmlAttributePtr attrDecl;
1497
1498 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1499 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1500 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1501 attr->name);
1502
Daniel Veillardb96e6431999-08-29 21:02:19 +00001503 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001504 return(1);
1505 }
1506 return(0);
1507}
1508
Daniel Veillardb96e6431999-08-29 21:02:19 +00001509/**
1510 * xmlGetID:
1511 * @doc: pointer to the document
1512 * @ID: the ID value
1513 *
1514 * Search the attribute declaring the given ID
1515 *
1516 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1517 */
1518xmlAttrPtr
1519xmlGetID(xmlDocPtr doc, const CHAR *ID) {
1520 xmlIDPtr cur;
1521 xmlIDTablePtr table;
1522 int i;
1523
1524 if (doc == NULL) {
1525 fprintf(stderr, "xmlGetID: doc == NULL\n");
1526 return(NULL);
1527 }
1528
1529 if (ID == NULL) {
1530 fprintf(stderr, "xmlGetID: ID == NULL\n");
1531 return(NULL);
1532 }
1533
1534 table = doc->ids;
1535 if (table == NULL)
1536 return(NULL);
1537
1538 /*
1539 * Search the ID list.
1540 */
1541 for (i = 0;i < table->nb_ids;i++) {
1542 cur = table->table[i];
1543 if (!xmlStrcmp(cur->value, ID)) {
1544 return(cur->attr);
1545 }
1546 }
1547 return(NULL);
1548}
1549
Daniel Veillard991e63d1999-08-15 23:32:28 +00001550/************************************************************************
1551 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001552 * Routines for validity checking *
1553 * *
1554 ************************************************************************/
1555
1556/**
1557 * xmlGetDtdElementDesc:
1558 * @dtd: a pointer to the DtD to search
1559 * @name: the element name
1560 *
1561 * Search the Dtd for the description of this element
1562 *
1563 * returns the xmlElementPtr if found or NULL
1564 */
1565
1566xmlElementPtr
1567xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
1568 xmlElementTablePtr table;
1569 xmlElementPtr cur;
1570 int i;
1571
1572 if (dtd == NULL) return(NULL);
1573 if (dtd->elements == NULL) return(NULL);
1574 table = dtd->elements;
1575
1576 for (i = 0;i < table->nb_elements;i++) {
1577 cur = table->table[i];
1578 if (!xmlStrcmp(cur->name, name))
1579 return(cur);
1580 }
1581 return(NULL);
1582}
1583
1584/**
1585 * xmlGetDtdAttrDesc:
1586 * @dtd: a pointer to the DtD to search
1587 * @elem: the element name
1588 * @name: the attribute name
1589 *
1590 * Search the Dtd for the description of this attribute on
1591 * this element.
1592 *
1593 * returns the xmlAttributePtr if found or NULL
1594 */
1595
1596xmlAttributePtr
1597xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
1598 xmlAttributeTablePtr table;
1599 xmlAttributePtr cur;
1600 int i;
1601
1602 if (dtd == NULL) return(NULL);
1603 if (dtd->attributes == NULL) return(NULL);
1604 table = dtd->attributes;
1605
1606 for (i = 0;i < table->nb_attributes;i++) {
1607 cur = table->table[i];
1608 if ((!xmlStrcmp(cur->name, name)) &&
1609 (!xmlStrcmp(cur->elem, elem)))
1610 return(cur);
1611 }
1612 return(NULL);
1613}
1614
1615/**
1616 * xmlGetDtdNotationDesc:
1617 * @dtd: a pointer to the DtD to search
1618 * @name: the notation name
1619 *
1620 * Search the Dtd for the description of this notation
1621 *
1622 * returns the xmlNotationPtr if found or NULL
1623 */
1624
1625xmlNotationPtr
1626xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
1627 xmlNotationTablePtr table;
1628 xmlNotationPtr cur;
1629 int i;
1630
1631 if (dtd == NULL) return(NULL);
1632 if (dtd->notations == NULL) return(NULL);
1633 table = dtd->notations;
1634
1635 for (i = 0;i < table->nb_notations;i++) {
1636 cur = table->table[i];
1637 if (!xmlStrcmp(cur->name, name))
1638 return(cur);
1639 }
1640 return(NULL);
1641}
1642
1643/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001644 * xmlValidateNotationUse:
1645 * @ctxt: the validation context
1646 * @doc: the document
1647 * @notationName: the notation name to check
1648 *
1649 * Validate that the given mame match a notation declaration.
1650 * - [ VC: Notation Declared ]
1651 *
1652 * returns 1 if valid or 0 otherwise
1653 */
1654
1655int
1656xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1657 const CHAR *notationName) {
1658 xmlNotationPtr notaDecl;
1659 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1660
1661 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1662 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1663 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1664
1665 if (notaDecl == NULL) {
1666 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1667 notationName);
1668 return(0);
1669 }
1670 return(1);
1671}
1672
1673/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001674 * xmlIsMixedElement
1675 * @doc: the document
1676 * @name: the element name
1677 *
1678 * Search in the DtDs whether an element accept Mixed content (or ANY)
1679 * basically if it is supposed to accept text childs
1680 *
1681 * returns 0 if no, 1 if yes, and -1 if no element description is available
1682 */
1683
1684int
1685xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
1686 xmlElementPtr elemDecl;
1687
1688 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1689
1690 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1691 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1692 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1693 if (elemDecl == NULL) return(-1);
1694 switch (elemDecl->type) {
1695 case XML_ELEMENT_TYPE_ELEMENT:
1696 return(0);
1697 case XML_ELEMENT_TYPE_EMPTY:
1698 /*
1699 * return 1 for EMPTY since we want VC error to pop up
1700 * on <empty> </empty> for example
1701 */
1702 case XML_ELEMENT_TYPE_ANY:
1703 case XML_ELEMENT_TYPE_MIXED:
1704 return(1);
1705 }
1706 return(1);
1707}
1708
1709/**
1710 * xmlValidateNameValue:
1711 * @value: an Name value
1712 *
1713 * Validate that the given value match Name production
1714 *
1715 * returns 1 if valid or 0 otherwise
1716 */
1717
1718int
1719xmlValidateNameValue(const CHAR *value) {
1720 const CHAR *cur;
1721
1722 if (value == NULL) return(0);
1723 cur = value;
1724
1725 if (!IS_LETTER(*cur) && (*cur != '_') &&
1726 (*cur != ':')) {
1727 return(0);
1728 }
1729
1730 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1731 (*cur == '.') || (*cur == '-') ||
1732 (*cur == '_') || (*cur == ':') ||
1733 (IS_COMBINING(*cur)) ||
1734 (IS_EXTENDER(*cur)))
1735 cur++;
1736
1737 if (*cur != 0) return(0);
1738
1739 return(1);
1740}
1741
1742/**
1743 * xmlValidateNamesValue:
1744 * @value: an Names value
1745 *
1746 * Validate that the given value match Names production
1747 *
1748 * returns 1 if valid or 0 otherwise
1749 */
1750
1751int
1752xmlValidateNamesValue(const CHAR *value) {
1753 const CHAR *cur;
1754
1755 if (value == NULL) return(0);
1756 cur = value;
1757
1758 if (!IS_LETTER(*cur) && (*cur != '_') &&
1759 (*cur != ':')) {
1760 return(0);
1761 }
1762
1763 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1764 (*cur == '.') || (*cur == '-') ||
1765 (*cur == '_') || (*cur == ':') ||
1766 (IS_COMBINING(*cur)) ||
1767 (IS_EXTENDER(*cur)))
1768 cur++;
1769
1770 while (IS_BLANK(*cur)) {
1771 while (IS_BLANK(*cur)) cur++;
1772
1773 if (!IS_LETTER(*cur) && (*cur != '_') &&
1774 (*cur != ':')) {
1775 return(0);
1776 }
1777
1778 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1779 (*cur == '.') || (*cur == '-') ||
1780 (*cur == '_') || (*cur == ':') ||
1781 (IS_COMBINING(*cur)) ||
1782 (IS_EXTENDER(*cur)))
1783 cur++;
1784 }
1785
1786 if (*cur != 0) return(0);
1787
1788 return(1);
1789}
1790
1791/**
1792 * xmlValidateNmtokenValue:
1793 * @value: an Mntoken value
1794 *
1795 * Validate that the given value match Nmtoken production
1796 *
1797 * [ VC: Name Token ]
1798 *
1799 * returns 1 if valid or 0 otherwise
1800 */
1801
1802int
1803xmlValidateNmtokenValue(const CHAR *value) {
1804 const CHAR *cur;
1805
1806 if (value == NULL) return(0);
1807 cur = value;
1808
1809 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1810 (*cur != '.') && (*cur != '-') &&
1811 (*cur != '_') && (*cur != ':') &&
1812 (!IS_COMBINING(*cur)) &&
1813 (!IS_EXTENDER(*cur)))
1814 return(0);
1815
1816 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1817 (*cur == '.') || (*cur == '-') ||
1818 (*cur == '_') || (*cur == ':') ||
1819 (IS_COMBINING(*cur)) ||
1820 (IS_EXTENDER(*cur)))
1821 cur++;
1822
1823 if (*cur != 0) return(0);
1824
1825 return(1);
1826 return(1);
1827}
1828
1829/**
1830 * xmlValidateNmtokensValue:
1831 * @value: an Mntokens value
1832 *
1833 * Validate that the given value match Nmtokens production
1834 *
1835 * [ VC: Name Token ]
1836 *
1837 * returns 1 if valid or 0 otherwise
1838 */
1839
1840int
1841xmlValidateNmtokensValue(const CHAR *value) {
1842 const CHAR *cur;
1843
1844 if (value == NULL) return(0);
1845 cur = value;
1846
1847 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1848 (*cur != '.') && (*cur != '-') &&
1849 (*cur != '_') && (*cur != ':') &&
1850 (!IS_COMBINING(*cur)) &&
1851 (!IS_EXTENDER(*cur)))
1852 return(0);
1853
1854 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1855 (*cur == '.') || (*cur == '-') ||
1856 (*cur == '_') || (*cur == ':') ||
1857 (IS_COMBINING(*cur)) ||
1858 (IS_EXTENDER(*cur)))
1859 cur++;
1860
1861 while (IS_BLANK(*cur)) {
1862 while (IS_BLANK(*cur)) cur++;
1863
1864 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1865 (*cur != '.') && (*cur != '-') &&
1866 (*cur != '_') && (*cur != ':') &&
1867 (!IS_COMBINING(*cur)) &&
1868 (!IS_EXTENDER(*cur)))
1869 return(0);
1870
1871 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1872 (*cur == '.') || (*cur == '-') ||
1873 (*cur == '_') || (*cur == ':') ||
1874 (IS_COMBINING(*cur)) ||
1875 (IS_EXTENDER(*cur)))
1876 cur++;
1877 }
1878
1879 if (*cur != 0) return(0);
1880
1881 return(1);
1882}
1883
1884/**
1885 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001886 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00001887 * @doc: a document instance
1888 * @nota: a notation definition
1889 *
1890 * Try to validate a single notation definition
1891 * basically it does the following checks as described by the
1892 * XML-1.0 recommendation:
1893 * - it seems that no validity constraing exist on notation declarations
1894 * But this function get called anyway ...
1895 *
1896 * returns 1 if valid or 0 otherwise
1897 */
1898
1899int
1900xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1901 xmlNotationPtr nota) {
1902 int ret = 1;
1903
1904 return(ret);
1905}
1906
1907/**
1908 * xmlValidateAttributeValue:
1909 * @type: an attribute type
1910 * @value: an attribute value
1911 *
1912 * Validate that the given attribute value match the proper production
1913 *
1914 * [ VC: ID ]
1915 * Values of type ID must match the Name production....
1916 *
1917 * [ VC: IDREF ]
1918 * Values of type IDREF must match the Name production, and values
1919 * of type IDREFS must match Names ...
1920 *
1921 * [ VC: Entity Name ]
1922 * Values of type ENTITY must match the Name production, values
1923 * of type ENTITIES must match Names ...
1924 *
1925 * [ VC: Name Token ]
1926 * Values of type NMTOKEN must match the Nmtoken production; values
1927 * of type NMTOKENS must match Nmtokens.
1928 *
1929 * returns 1 if valid or 0 otherwise
1930 */
1931
1932int
1933xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
1934 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001935 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001936 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001937 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001938 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001939 case XML_ATTRIBUTE_IDREF:
1940 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001941 case XML_ATTRIBUTE_NOTATION:
1942 return(xmlValidateNameValue(value));
1943 case XML_ATTRIBUTE_NMTOKENS:
1944 case XML_ATTRIBUTE_ENUMERATION:
1945 return(xmlValidateNmtokensValue(value));
1946 case XML_ATTRIBUTE_NMTOKEN:
1947 return(xmlValidateNmtokenValue(value));
1948 case XML_ATTRIBUTE_CDATA:
1949 break;
1950 }
1951 return(1);
1952}
1953
1954/**
1955 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001956 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00001957 * @doc: a document instance
1958 * @attr: an attribute definition
1959 *
1960 * Try to validate a single attribute definition
1961 * basically it does the following checks as described by the
1962 * XML-1.0 recommendation:
1963 * - [ VC: Attribute Default Legal ]
1964 * - [ VC: Enumeration ]
1965 * - [ VC: ID Attribute Default ]
1966 *
1967 * The ID/IDREF uniqueness and matching are done separately
1968 *
1969 * returns 1 if valid or 0 otherwise
1970 */
1971
1972int
1973xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1974 xmlAttributePtr attr) {
1975 int ret = 1;
1976 int val;
1977 CHECK_DTD;
1978 if(attr == NULL) return(1);
1979
1980 /* Attribute Default Legal */
1981 /* Enumeration */
1982 if (attr->defaultValue != NULL) {
1983 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
1984 if (val == 0) {
1985 VERROR(ctxt->userData,
1986 "Syntax of default value for attribute %s on %s is not valid\n",
1987 attr->name, attr->elem);
1988 }
1989 ret &= val;
1990 }
1991
1992 /* ID Attribute Default */
1993 if ((attr->type == XML_ATTRIBUTE_ID)&&
1994 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
1995 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
1996 VERROR(ctxt->userData,
1997 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
1998 attr->name, attr->elem);
1999 ret = 0;
2000 }
2001
Daniel Veillardb96e6431999-08-29 21:02:19 +00002002 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002003 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2004 int nbId = 0;
2005
2006 /* the trick is taht we parse DtD as their own internal subset */
2007 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2008 attr->elem);
2009 if (elem != NULL) {
2010 nbId = xmlScanIDAttributeDecl(NULL, elem);
2011 }
2012 if (nbId >= 1)
2013 VERROR(ctxt->userData,
2014 "Element %s has ID attribute defined in the external subset : %s\n",
2015 attr->elem, attr->name);
2016 }
2017
2018 return(ret);
2019}
2020
2021/**
2022 * xmlValidateElementDecl:
2023 * @ctxt: the validation context
2024 * @doc: a document instance
2025 * @elem: an element definition
2026 *
2027 * Try to validate a single element definition
2028 * basically it does the following checks as described by the
2029 * XML-1.0 recommendation:
2030 * - [ VC: One ID per Element Type ]
2031 * - [ VC: No Duplicate Types ]
2032 * - [ VC: Unique Element Type Declaration ]
2033 *
2034 * returns 1 if valid or 0 otherwise
2035 */
2036
2037int
2038xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2039 xmlElementPtr elem) {
2040 int ret = 1;
2041 xmlElementPtr tst;
2042
2043 CHECK_DTD;
2044
2045 if (elem == NULL) return(1);
2046
2047 /* No Duplicate Types */
2048 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2049 xmlElementContentPtr cur, next;
2050 const CHAR *name;
2051
2052 cur = elem->content;
2053 while (cur != NULL) {
2054 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2055 if (cur->c1 == NULL) break;
2056 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2057 name = cur->c1->name;
2058 next = cur->c2;
2059 while (next != NULL) {
2060 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2061 if (!xmlStrcmp(next->name, name)) {
2062 VERROR(ctxt->userData,
2063 "Definition of %s has duplicate references of %s\n",
2064 elem->name, name);
2065 ret = 0;
2066 }
2067 break;
2068 }
2069 if (next->c1 == NULL) break;
2070 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2071 if (!xmlStrcmp(next->c1->name, name)) {
2072 VERROR(ctxt->userData,
2073 "Definition of %s has duplicate references of %s\n",
2074 elem->name, name);
2075 ret = 0;
2076 }
2077 next = next->c2;
2078 }
2079 }
2080 cur = cur->c2;
2081 }
2082 }
2083
2084 /* VC: Unique Element Type Declaration */
2085 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2086 if ((tst != NULL ) && (tst != elem)) {
2087 VERROR(ctxt->userData, "Redefinition of element %s\n",
2088 elem->name);
2089 ret = 0;
2090 }
2091 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2092 if ((tst != NULL ) && (tst != elem)) {
2093 VERROR(ctxt->userData, "Redefinition of element %s\n",
2094 elem->name);
2095 ret = 0;
2096 }
2097
2098 /* One ID per Element Type */
2099 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2100 ret = 0;
2101 }
2102 return(ret);
2103}
2104
2105/**
2106 * xmlValidateOneAttribute:
2107 * @ctxt: the validation context
2108 * @doc: a document instance
2109 * @elem: an element instance
2110 * @attr: an attribute instance
2111 *
2112 * Try to validate a single attribute for an element
2113 * basically it * does the following checks as described by the
2114 * XML-1.0 recommendation:
2115 * - [ VC: Attribute Value Type ]
2116 * - [ VC: Fixed Attribute Default ]
2117 * - [ VC: Entity Name ]
2118 * - [ VC: Name Token ]
2119 * - [ VC: ID ]
2120 * - [ VC: IDREF ]
2121 * - [ VC: Entity Name ]
2122 * - [ VC: Notation Attributes ]
2123 *
2124 * The ID/IDREF uniqueness and matching are done separately
2125 *
2126 * returns 1 if valid or 0 otherwise
2127 */
2128
2129int
2130xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2131 xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002132 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002133 xmlAttributePtr attrDecl;
2134 int val;
2135 int ret = 1;
2136
2137 CHECK_DTD;
2138 if ((elem == NULL) || (elem->name == NULL)) return(0);
2139 if ((attr == NULL) || (attr->name == NULL)) return(0);
2140
2141 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2142 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2143 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2144
2145
2146 /* Validity Constraint: Attribute Value Type */
2147 if (attrDecl == NULL) {
2148 VERROR(ctxt->userData,
2149 "No declaration for attribute %s on element %s\n",
2150 attr->name, elem->name);
2151 return(0);
2152 }
2153 val = xmlValidateAttributeValue(attrDecl->type, value);
2154 if (val == 0) {
2155 VERROR(ctxt->userData,
2156 "Syntax of value for attribute %s on %s is not valid\n",
2157 attr->name, elem->name);
2158 ret = 0;
2159 }
2160
Daniel Veillardb96e6431999-08-29 21:02:19 +00002161 /* Validity Constraint: ID uniqueness */
2162 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2163 xmlAddID(ctxt, doc, value, attr);
2164 }
2165
Daniel Veillardb05deb71999-08-10 19:04:08 +00002166 /* Validity Constraint: Notation Attributes */
2167 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2168 xmlEnumerationPtr tree = attrDecl->tree;
2169 xmlNotationPtr nota;
2170
2171 /* First check that the given NOTATION was declared */
2172 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2173 if (nota == NULL)
2174 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2175
2176 if (nota == NULL) {
2177 VERROR(ctxt->userData,
2178 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2179 value, attr->name, elem->name);
2180 ret = 0;
2181 }
2182
2183 /* Second, verify that it's among the list */
2184 while (tree != NULL) {
2185 if (!xmlStrcmp(tree->name, value)) break;
2186 tree = tree->next;
2187 }
2188 if (tree == NULL) {
2189 VERROR(ctxt->userData,
2190 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2191 value, attr->name, elem->name);
2192 ret = 0;
2193 }
2194 }
2195
2196 /* Validity Constraint: Enumeration */
2197 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2198 xmlEnumerationPtr tree = attrDecl->tree;
2199 while (tree != NULL) {
2200 if (!xmlStrcmp(tree->name, value)) break;
2201 tree = tree->next;
2202 }
2203 if (tree == NULL) {
2204 VERROR(ctxt->userData,
2205 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2206 value, attr->name, elem->name);
2207 ret = 0;
2208 }
2209 }
2210
2211 /* Fixed Attribute Default */
2212 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2213 (xmlStrcmp(attrDecl->defaultValue, value))) {
2214 VERROR(ctxt->userData,
2215 "Value for attribute %s on %s must be \"%s\"\n",
2216 attr->name, elem->name, attrDecl->defaultValue);
2217 ret = 0;
2218 }
2219
Daniel Veillardb96e6431999-08-29 21:02:19 +00002220 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002221 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2222 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2223 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2224 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002225 return(0);
2226 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002227 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002228 return(ret);
2229}
2230
2231int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2232 xmlElementContentPtr cont);
2233
2234/**
2235 * xmlValidateElementTypeExpr:
2236 * @ctxt: the validation context
2237 * @child: pointer to the child list
2238 * @cont: pointer to the content declaration
2239 *
2240 * Try to validate the content of an element of type element
2241 * but don't handle the occurence factor
2242 *
2243 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2244 * also update child value in-situ.
2245 */
2246
2247int
2248xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2249 xmlElementContentPtr cont) {
2250 xmlNodePtr cur;
2251 int ret = 1;
2252
2253 if (cont == NULL) return(-1);
2254 while (*child != NULL) {
2255 if ((*child)->type == XML_PI_NODE) {
2256 *child = (*child)->next;
2257 continue;
2258 }
2259 if ((*child)->type == XML_COMMENT_NODE) {
2260 *child = (*child)->next;
2261 continue;
2262 }
2263 else if ((*child)->type != XML_ELEMENT_NODE) {
2264 return(-1);
2265 }
2266 break;
2267 }
2268 switch (cont->type) {
2269 case XML_ELEMENT_CONTENT_PCDATA:
2270 /* Internal error !!! */
2271 fprintf(stderr, "Internal: MIXED struct bad\n");
2272 return(-1);
2273 case XML_ELEMENT_CONTENT_ELEMENT:
2274 if (*child == NULL) return(0);
2275 ret = (!xmlStrcmp((*child)->name, cont->name));
2276 if (ret == 1)
2277 *child = (*child)->next;
2278 return(ret);
2279 case XML_ELEMENT_CONTENT_OR:
2280 cur = *child;
2281 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2282 if (ret == -1) return(-1);
2283 if (ret == 1) {
2284 return(1);
2285 }
2286 /* rollback and retry the other path */
2287 *child = cur;
2288 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2289 if (ret == -1) return(-1);
2290 if (ret == 0) {
2291 *child = cur;
2292 return(0);
2293 }
2294 return(1);
2295 case XML_ELEMENT_CONTENT_SEQ:
2296 cur = *child;
2297 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2298 if (ret == -1) return(-1);
2299 if (ret == 0) {
2300 *child = cur;
2301 return(0);
2302 }
2303 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2304 if (ret == -1) return(-1);
2305 if (ret == 0) {
2306 *child = cur;
2307 return(0);
2308 }
2309 return(1);
2310 }
2311 return(ret);
2312}
2313
2314/**
2315 * xmlValidateElementTypeElement:
2316 * @ctxt: the validation context
2317 * @child: pointer to the child list
2318 * @cont: pointer to the content declaration
2319 *
2320 * Try to validate the content of an element of type element
2321 * yeah, Yet Another Regexp Implementation, and recursive
2322 *
2323 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2324 * also update child and content values in-situ.
2325 */
2326
2327int
2328xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2329 xmlElementContentPtr cont) {
2330 xmlNodePtr cur;
2331 int ret = 1;
2332
2333 if (cont == NULL) return(-1);
2334 while (*child != NULL) {
2335 if ((*child)->type == XML_PI_NODE) {
2336 *child = (*child)->next;
2337 continue;
2338 }
2339 if ((*child)->type == XML_COMMENT_NODE) {
2340 *child = (*child)->next;
2341 continue;
2342 }
2343 else if ((*child)->type != XML_ELEMENT_NODE) {
2344 return(-1);
2345 }
2346 break;
2347 }
2348 cur = *child;
2349 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2350 if (ret == -1) return(-1);
2351 switch (cont->ocur) {
2352 case XML_ELEMENT_CONTENT_ONCE:
2353 if (ret == 1) {
2354 return(1);
2355 }
2356 *child = cur;
2357 return(0);
2358 case XML_ELEMENT_CONTENT_OPT:
2359 if (ret == 0) {
2360 *child = cur;
2361 return(1);
2362 }
2363 break;
2364 case XML_ELEMENT_CONTENT_MULT:
2365 if (ret == 0) {
2366 *child = cur;
2367 break;
2368 }
2369 /* no break on purpose */
2370 case XML_ELEMENT_CONTENT_PLUS:
2371 if (ret == 0) {
2372 *child = cur;
2373 return(0);
2374 }
2375 do {
2376 cur = *child;
2377 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2378 } while (ret == 1);
2379 if (ret == -1) return(-1);
2380 *child = cur;
2381 break;
2382 }
2383 while (*child != NULL) {
2384 if ((*child)->type == XML_PI_NODE) {
2385 *child = (*child)->next;
2386 continue;
2387 }
2388 if ((*child)->type == XML_COMMENT_NODE) {
2389 *child = (*child)->next;
2390 continue;
2391 }
2392 else if ((*child)->type != XML_ELEMENT_NODE) {
2393 return(-1);
2394 }
2395 break;
2396 }
2397 return(1);
2398}
2399
2400/**
2401 * xmlSprintfElementChilds:
2402 * @buf: an output buffer
2403 * @content: An element
2404 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2405 *
2406 * This will dump the list of childs to the buffer
2407 * Intended just for the debug routine
2408 */
2409void
2410xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2411 xmlNodePtr cur;
2412
2413 if (node == NULL) return;
2414 if (glob) strcat(buf, "(");
2415 cur = node->childs;
2416 while (cur != NULL) {
2417 switch (cur->type) {
2418 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002419 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002420 if (cur->next != NULL)
2421 strcat(buf, " ");
2422 break;
2423 case XML_TEXT_NODE:
2424 case XML_CDATA_SECTION_NODE:
2425 case XML_ENTITY_REF_NODE:
2426 strcat(buf, "CDATA");
2427 if (cur->next != NULL)
2428 strcat(buf, " ");
2429 break;
2430 case XML_ATTRIBUTE_NODE:
2431 case XML_DOCUMENT_NODE:
2432 case XML_DOCUMENT_TYPE_NODE:
2433 case XML_DOCUMENT_FRAG_NODE:
2434 case XML_NOTATION_NODE:
2435 strcat(buf, "???");
2436 if (cur->next != NULL)
2437 strcat(buf, " ");
2438 break;
2439 case XML_ENTITY_NODE:
2440 case XML_PI_NODE:
2441 case XML_COMMENT_NODE:
2442 break;
2443 }
2444 cur = cur->next;
2445 }
2446 if (glob) strcat(buf, ")");
2447}
2448
2449
2450/**
2451 * xmlValidateOneElement:
2452 * @ctxt: the validation context
2453 * @doc: a document instance
2454 * @elem: an element instance
2455 *
2456 * Try to validate a single element and it's attributes,
2457 * basically it does the following checks as described by the
2458 * XML-1.0 recommendation:
2459 * - [ VC: Element Valid ]
2460 * - [ VC: Required Attribute ]
2461 * Then call xmlValidateOneAttribute() for each attribute present.
2462 *
2463 * The ID/IDREF checkings are done separately
2464 *
2465 * returns 1 if valid or 0 otherwise
2466 */
2467
2468int
2469xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2470 xmlNodePtr elem) {
2471 xmlElementPtr elemDecl;
2472 xmlElementContentPtr cont;
2473 xmlNodePtr child;
2474 int ret = 1;
2475 const CHAR *name;
2476
2477 CHECK_DTD;
2478
2479 if ((elem == NULL) || (elem->name == NULL)) return(0);
2480
2481 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2482 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2483 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2484 if (elemDecl == NULL) {
2485 VERROR(ctxt->userData, "No declaration for element %s\n",
2486 elem->name);
2487 return(0);
2488 }
2489
2490 /* Check taht the element content matches the definition */
2491 switch (elemDecl->type) {
2492 case XML_ELEMENT_TYPE_EMPTY:
2493 if (elem->childs != NULL) {
2494 VERROR(ctxt->userData,
2495 "Element %s was declared EMPTY this one has content\n",
2496 elem->name);
2497 ret = 0;
2498 }
2499 break;
2500 case XML_ELEMENT_TYPE_ANY:
2501 /* I don't think anything is required then */
2502 break;
2503 case XML_ELEMENT_TYPE_MIXED:
2504 /* Hum, this start to get messy */
2505 child = elem->childs;
2506 while (child != NULL) {
2507 if (child->type == XML_ELEMENT_NODE) {
2508 name = child->name;
2509 cont = elemDecl->content;
2510 while (cont != NULL) {
2511 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2512 if (!xmlStrcmp(cont->name, name)) break;
2513 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2514 (cont->c1 != NULL) &&
2515 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2516 if (!xmlStrcmp(cont->c1->name, name)) break;
2517 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2518 (cont->c1 == NULL) ||
2519 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2520 /* Internal error !!! */
2521 fprintf(stderr, "Internal: MIXED struct bad\n");
2522 break;
2523 }
2524 cont = cont->c2;
2525 }
2526 if (cont == NULL) {
2527 VERROR(ctxt->userData,
2528 "Element %s is not declared in %s list of possible childs\n",
2529 name, elem->name);
2530 ret = 0;
2531 }
2532 }
2533 child = child->next;
2534 }
2535 break;
2536 case XML_ELEMENT_TYPE_ELEMENT:
2537 child = elem->childs;
2538 cont = elemDecl->content;
2539 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2540 if ((ret == 0) || (child != NULL)) {
2541 char expr[1000];
2542 char list[2000];
2543
2544 expr[0] = 0;
2545 xmlSprintfElementContent(expr, cont, 1);
2546 list[0] = 0;
2547 xmlSprintfElementChilds(list, elem, 1);
2548
2549 VERROR(ctxt->userData,
2550 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2551 elem->name, expr, list);
2552 ret = 0;
2553 }
2554 break;
2555 }
2556
Daniel Veillardb96e6431999-08-29 21:02:19 +00002557 /* TODO - [ VC: Required Attribute ] */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002558 return(ret);
2559}
2560
2561/**
2562 * xmlValidateRoot:
2563 * @ctxt: the validation context
2564 * @doc: a document instance
2565 *
2566 * Try to validate a the root element
2567 * basically it does the following check as described by the
2568 * XML-1.0 recommendation:
2569 * - [ VC: Root Element Type ]
2570 * it doesn't try to recurse or apply other check to the element
2571 *
2572 * returns 1 if valid or 0 otherwise
2573 */
2574
2575int
2576xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2577 if (doc == NULL) return(0);
2578
2579 if ((doc->intSubset == NULL) ||
2580 (doc->intSubset->name == NULL)) {
2581 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2582 return(0);
2583 }
2584 if ((doc->root == NULL) || (doc->root->name == NULL)) {
2585 VERROR(ctxt->userData, "Not valid: no root element\n");
2586 return(0);
2587 }
2588 if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2589 VERROR(ctxt->userData,
2590 "Not valid: root and DtD name do not match %s and %s\n",
2591 doc->root->name, doc->intSubset->name);
2592 return(0);
2593 }
2594 return(1);
2595}
2596
2597
2598/**
2599 * xmlValidateElement:
2600 * @ctxt: the validation context
2601 * @doc: a document instance
2602 * @elem: an element instance
2603 *
2604 * Try to validate the subtree under an element
2605 *
2606 * returns 1 if valid or 0 otherwise
2607 */
2608
2609int
2610xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
2611 CHECK_DTD;
2612
2613 return(1);
2614}
2615
2616/**
2617 * xmlValidateDtd:
2618 * @ctxt: the validation context
2619 * @doc: a document instance
2620 * @dtd: a dtd instance
2621 *
2622 * Try to validate the dtd instance
2623 *
2624 * basically it does check all the definitions in the DtD.
2625 *
2626 * returns 1 if valid or 0 otherwise
2627 */
2628
2629int
2630xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
2631 return(1);
2632}
2633
2634/**
2635 * xmlValidateDocument:
2636 * @ctxt: the validation context
2637 * @doc: a document instance
2638 *
2639 * Try to validate the document instance
2640 *
2641 * basically it does the all the checks described by the
2642 * i.e. validates the internal and external subset (if present)
2643 * and validate the document tree.
2644 *
2645 * returns 1 if valid or 0 otherwise
2646 */
2647
2648int
2649xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2650 if (!xmlValidateRoot(ctxt, doc)) return(0);
2651
2652 return(1);
2653}
2654