blob: 25ad9d53d5555a268ff8cc2eb740a3fde970fe3e [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:
204 strcat(buf, content->name);
205 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 }
763 /* TODO: Lacks verifications !!! */
764 switch (type) {
765 case XML_ATTRIBUTE_CDATA:
766 break;
767 case XML_ATTRIBUTE_ID:
768 break;
769 case XML_ATTRIBUTE_IDREF:
770 break;
771 case XML_ATTRIBUTE_IDREFS:
772 break;
773 case XML_ATTRIBUTE_ENTITY:
774 break;
775 case XML_ATTRIBUTE_ENTITIES:
776 break;
777 case XML_ATTRIBUTE_NMTOKEN:
778 break;
779 case XML_ATTRIBUTE_NMTOKENS:
780 break;
781 case XML_ATTRIBUTE_ENUMERATION:
782 break;
783 case XML_ATTRIBUTE_NOTATION:
784 break;
785 default:
786 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
787 return(NULL);
788 }
789
790 /*
791 * Create the Attribute table if needed.
792 */
793 table = dtd->attributes;
794 if (table == NULL)
795 table = dtd->attributes = xmlCreateAttributeTable();
796 if (table == NULL) {
797 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
798 return(NULL);
799 }
800
801 /*
802 * Validity Check:
803 * Search the DTD for previous declarations of the ATTLIST
804 */
805 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000806 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +0000807 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
808 /*
809 * The attribute is already defined in this Dtd.
810 */
811 fprintf(stderr,
812 "xmlAddAttributeDecl: %s already defined\n", name);
813 }
814 }
815
816 /*
817 * Grow the table, if needed.
818 */
819 if (table->nb_attributes >= table->max_attributes) {
820 /*
821 * need more attributes.
822 */
823 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000824 table->table = (xmlAttributePtr *)
825 realloc(table->table, table->max_attributes *
826 sizeof(xmlAttributePtr));
827 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000828 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
829 return(NULL);
830 }
831 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000832 ret = (xmlAttributePtr) malloc(sizeof(xmlAttribute));
833 if (ret == NULL) {
834 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
835 return(NULL);
836 }
837 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000838
839 /*
840 * fill the structure.
841 */
842 ret->type = type;
843 ret->name = xmlStrdup(name);
844 ret->elem = xmlStrdup(elem);
845 ret->def = def;
846 ret->tree = tree;
847 if (defaultValue != NULL)
848 ret->defaultValue = xmlStrdup(defaultValue);
849 else
850 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000851 elemDef = xmlGetDtdElementDesc(dtd, elem);
852 if (elemDef != NULL) {
853 if ((type == XML_ATTRIBUTE_ID) &&
854 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
855 VERROR(ctxt->userData,
856 "Element %s has too may ID attributes defined : %s\n",
857 elem, name);
858 ret->next = elemDef->attributes;
859 elemDef->attributes = ret;
860 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000861 table->nb_attributes++;
862
863 return(ret);
864}
865
866/**
867 * xmlFreeAttribute:
868 * @elem: An attribute
869 *
870 * Deallocate the memory used by an attribute definition
871 */
872void
873xmlFreeAttribute(xmlAttributePtr attr) {
874 if (attr == NULL) return;
875 if (attr->tree != NULL)
876 xmlFreeEnumeration(attr->tree);
877 if (attr->elem != NULL)
878 free((CHAR *) attr->elem);
879 if (attr->name != NULL)
880 free((CHAR *) attr->name);
881 if (attr->defaultValue != NULL)
882 free((CHAR *) attr->defaultValue);
883 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000884 free(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000885}
886
887/**
888 * xmlFreeAttributeTable:
889 * @table: An attribute table
890 *
891 * Deallocate the memory used by an entities hash table.
892 */
893void
894xmlFreeAttributeTable(xmlAttributeTablePtr table) {
895 int i;
896
897 if (table == NULL) return;
898
899 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000900 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000901 }
902 free(table->table);
903 free(table);
904}
905
906/**
907 * xmlCopyAttributeTable:
908 * @table: An attribute table
909 *
910 * Build a copy of an attribute table.
911 *
912 * Returns the new xmlAttributeTablePtr or NULL in case of error.
913 */
914xmlAttributeTablePtr
915xmlCopyAttributeTable(xmlAttributeTablePtr table) {
916 xmlAttributeTablePtr ret;
917 xmlAttributePtr cur, attr;
918 int i;
919
920 ret = (xmlAttributeTablePtr) malloc(sizeof(xmlAttributeTable));
921 if (ret == NULL) {
922 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
923 return(NULL);
924 }
Daniel Veillardb05deb71999-08-10 19:04:08 +0000925 ret->table = (xmlAttributePtr *) malloc(table->max_attributes *
926 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000927 if (ret->table == NULL) {
928 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
929 free(ret);
930 return(NULL);
931 }
932 ret->max_attributes = table->max_attributes;
933 ret->nb_attributes = table->nb_attributes;
934 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000935 attr = table->table[i];
936 cur = (xmlAttributePtr) malloc(sizeof(xmlAttribute));
937 if (cur == NULL) {
938 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
939 free(ret);
940 free(ret->table);
941 return(NULL);
942 }
943 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000944 cur->type = attr->type;
945 cur->def = attr->def;
946 cur->tree = xmlCopyEnumeration(attr->tree);
947 if (attr->elem != NULL)
948 cur->elem = xmlStrdup(attr->elem);
949 else
950 cur->elem = NULL;
951 if (attr->name != NULL)
952 cur->name = xmlStrdup(attr->name);
953 else
954 cur->name = NULL;
955 if (attr->defaultValue != NULL)
956 cur->defaultValue = xmlStrdup(attr->defaultValue);
957 else
958 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000959 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000960 }
961 return(ret);
962}
963
964/**
965 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000966 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +0000967 * @table: An attribute table
968 *
969 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +0000970 */
971void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000972xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000973 int i;
974 xmlAttributePtr cur;
975
976 if (table == NULL) return;
977
978 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000979 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +0000980 xmlBufferWriteChar(buf, "<!ATTLIST ");
981 xmlBufferWriteCHAR(buf, cur->elem);
982 xmlBufferWriteChar(buf, " ");
983 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000984 switch (cur->type) {
985 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000986 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +0000987 break;
988 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000989 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +0000990 break;
991 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000992 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +0000993 break;
994 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000995 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +0000996 break;
997 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000998 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +0000999 break;
1000 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001001 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001002 break;
1003 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001004 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001005 break;
1006 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001007 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001008 break;
1009 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001010 xmlBufferWriteChar(buf, " (");
1011 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001012 break;
1013 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001014 xmlBufferWriteChar(buf, " NOTATION (");
1015 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001016 break;
1017 default:
1018 fprintf(stderr,
1019 "xmlDumpAttributeTable: internal: unknown type %d\n",
1020 cur->type);
1021 }
1022 switch (cur->def) {
1023 case XML_ATTRIBUTE_NONE:
1024 break;
1025 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001026 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001027 break;
1028 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001029 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001030 break;
1031 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001032 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001033 break;
1034 default:
1035 fprintf(stderr,
1036 "xmlDumpAttributeTable: internal: unknown default %d\n",
1037 cur->def);
1038 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001039 if (cur->defaultValue != NULL) {
1040 xmlBufferWriteChar(buf, " ");
1041 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1042 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001043 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001044 }
1045}
1046
1047/************************************************************************
1048 * *
1049 * NOTATIONs *
1050 * *
1051 ************************************************************************/
1052/**
1053 * xmlCreateNotationTable:
1054 *
1055 * create and initialize an empty notation hash table.
1056 *
1057 * Returns the xmlNotationTablePtr just created or NULL in case
1058 * of error.
1059 */
1060xmlNotationTablePtr
1061xmlCreateNotationTable(void) {
1062 xmlNotationTablePtr ret;
1063
1064 ret = (xmlNotationTablePtr)
1065 malloc(sizeof(xmlNotationTable));
1066 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001067 fprintf(stderr, "xmlCreateNotationTable : malloc(%ld) failed\n",
1068 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001069 return(NULL);
1070 }
1071 ret->max_notations = XML_MIN_NOTATION_TABLE;
1072 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001073 ret->table = (xmlNotationPtr *)
1074 malloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001075 if (ret == NULL) {
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001076 fprintf(stderr, "xmlCreateNotationTable : malloc(%ld) failed\n",
1077 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001078 free(ret);
1079 return(NULL);
1080 }
1081 return(ret);
1082}
1083
1084
1085/**
1086 * xmlAddNotationDecl:
1087 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001088 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001089 * @name: the entity name
1090 * @PublicID: the public identifier or NULL
1091 * @SystemID: the system identifier or NULL
1092 *
1093 * Register a new notation declaration
1094 *
1095 * Returns NULL if not, othervise the entity
1096 */
1097xmlNotationPtr
Daniel Veillardb05deb71999-08-10 19:04:08 +00001098xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
1099 const CHAR *PublicID, const CHAR *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001100 xmlNotationPtr ret, cur;
1101 xmlNotationTablePtr table;
1102 int i;
1103
1104 if (dtd == NULL) {
1105 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1106 return(NULL);
1107 }
1108 if (name == NULL) {
1109 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1110 return(NULL);
1111 }
1112 if ((PublicID == NULL) && (SystemID == NULL)) {
1113 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1114 }
1115
1116 /*
1117 * Create the Notation table if needed.
1118 */
1119 table = dtd->notations;
1120 if (table == NULL)
1121 table = dtd->notations = xmlCreateNotationTable();
1122 if (table == NULL) {
1123 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1124 return(NULL);
1125 }
1126
1127 /*
1128 * Validity Check:
1129 * Search the DTD for previous declarations of the ATTLIST
1130 */
1131 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001132 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001133 if (!xmlStrcmp(cur->name, name)) {
1134 /*
1135 * The notation is already defined in this Dtd.
1136 */
1137 fprintf(stderr,
1138 "xmlAddNotationDecl: %s already defined\n", name);
1139 }
1140 }
1141
1142 /*
1143 * Grow the table, if needed.
1144 */
1145 if (table->nb_notations >= table->max_notations) {
1146 /*
1147 * need more notations.
1148 */
1149 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001150 table->table = (xmlNotationPtr *)
1151 realloc(table->table, table->max_notations *
1152 sizeof(xmlNotationPtr));
1153 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001154 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1155 return(NULL);
1156 }
1157 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001158 ret = (xmlNotationPtr) malloc(sizeof(xmlNotation));
1159 if (ret == NULL) {
1160 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1161 return(NULL);
1162 }
1163 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001164
1165 /*
1166 * fill the structure.
1167 */
1168 ret->name = xmlStrdup(name);
1169 if (SystemID != NULL)
1170 ret->SystemID = xmlStrdup(SystemID);
1171 else
1172 ret->SystemID = NULL;
1173 if (PublicID != NULL)
1174 ret->PublicID = xmlStrdup(PublicID);
1175 else
1176 ret->PublicID = NULL;
1177 table->nb_notations++;
1178
1179 return(ret);
1180}
1181
1182/**
1183 * xmlFreeNotation:
1184 * @not: A notation
1185 *
1186 * Deallocate the memory used by an notation definition
1187 */
1188void
1189xmlFreeNotation(xmlNotationPtr nota) {
1190 if (nota == NULL) return;
1191 if (nota->name != NULL)
1192 free((CHAR *) nota->name);
1193 if (nota->PublicID != NULL)
1194 free((CHAR *) nota->PublicID);
1195 if (nota->SystemID != NULL)
1196 free((CHAR *) nota->SystemID);
1197 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001198 free(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001199}
1200
1201/**
1202 * xmlFreeNotationTable:
1203 * @table: An notation table
1204 *
1205 * Deallocate the memory used by an entities hash table.
1206 */
1207void
1208xmlFreeNotationTable(xmlNotationTablePtr table) {
1209 int i;
1210
1211 if (table == NULL) return;
1212
1213 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001214 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001215 }
1216 free(table->table);
1217 free(table);
1218}
1219
1220/**
1221 * xmlCopyNotationTable:
1222 * @table: A notation table
1223 *
1224 * Build a copy of a notation table.
1225 *
1226 * Returns the new xmlNotationTablePtr or NULL in case of error.
1227 */
1228xmlNotationTablePtr
1229xmlCopyNotationTable(xmlNotationTablePtr table) {
1230 xmlNotationTablePtr ret;
1231 xmlNotationPtr cur, nota;
1232 int i;
1233
1234 ret = (xmlNotationTablePtr) malloc(sizeof(xmlNotationTable));
1235 if (ret == NULL) {
1236 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1237 return(NULL);
1238 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001239 ret->table = (xmlNotationPtr *) malloc(table->max_notations *
1240 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001241 if (ret->table == NULL) {
1242 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1243 free(ret);
1244 return(NULL);
1245 }
1246 ret->max_notations = table->max_notations;
1247 ret->nb_notations = table->nb_notations;
1248 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001249 cur = (xmlNotationPtr) malloc(sizeof(xmlNotation));
1250 if (cur == NULL) {
1251 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1252 free(ret);
1253 free(ret->table);
1254 return(NULL);
1255 }
1256 ret->table[i] = cur;
1257 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001258 if (nota->name != NULL)
1259 cur->name = xmlStrdup(nota->name);
1260 else
1261 cur->name = NULL;
1262 if (nota->PublicID != NULL)
1263 cur->PublicID = xmlStrdup(nota->PublicID);
1264 else
1265 cur->PublicID = NULL;
1266 if (nota->SystemID != NULL)
1267 cur->SystemID = xmlStrdup(nota->SystemID);
1268 else
1269 cur->SystemID = NULL;
1270 }
1271 return(ret);
1272}
1273
1274/**
1275 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001276 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001277 * @table: A notation table
1278 *
1279 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001280 */
1281void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001282xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001283 int i;
1284 xmlNotationPtr cur;
1285
1286 if (table == NULL) return;
1287
1288 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001289 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001290 xmlBufferWriteChar(buf, "<!NOTATION ");
1291 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001292 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001293 xmlBufferWriteChar(buf, " PUBLIC ");
1294 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001295 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001296 xmlBufferWriteChar(buf, " ");
1297 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001298 }
1299 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001300 xmlBufferWriteChar(buf, " SYSTEM ");
1301 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001302 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001303 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001304 }
1305}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001306
1307/************************************************************************
1308 * *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001309 * NOTATIONs *
1310 * *
1311 ************************************************************************/
1312/**
1313 * xmlCreateIDTable:
1314 *
1315 * create and initialize an empty id hash table.
1316 *
1317 * Returns the xmlIDTablePtr just created or NULL in case
1318 * of error.
1319 */
1320xmlIDTablePtr
1321xmlCreateIDTable(void) {
1322 xmlIDTablePtr ret;
1323
1324 ret = (xmlIDTablePtr)
1325 malloc(sizeof(xmlIDTable));
1326 if (ret == NULL) {
1327 fprintf(stderr, "xmlCreateIDTable : malloc(%ld) failed\n",
1328 (long)sizeof(xmlIDTable));
1329 return(NULL);
1330 }
1331 ret->max_ids = XML_MIN_NOTATION_TABLE;
1332 ret->nb_ids = 0;
1333 ret->table = (xmlIDPtr *)
1334 malloc(ret->max_ids * sizeof(xmlIDPtr));
1335 if (ret == NULL) {
1336 fprintf(stderr, "xmlCreateIDTable : malloc(%ld) failed\n",
1337 ret->max_ids * (long)sizeof(xmlID));
1338 free(ret);
1339 return(NULL);
1340 }
1341 return(ret);
1342}
1343
1344
1345/**
1346 * xmlAddID:
1347 * @ctxt: the validation context
1348 * @doc: pointer to the document
1349 * @value: the value name
1350 * @attr: the attribute holding the ID
1351 *
1352 * Register a new id declaration
1353 *
1354 * Returns NULL if not, othervise the new xmlIDPtr
1355 */
1356xmlIDPtr
1357xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
1358 xmlAttrPtr attr) {
1359 xmlIDPtr ret, cur;
1360 xmlIDTablePtr table;
1361 int i;
1362
1363 if (doc == NULL) {
1364 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1365 return(NULL);
1366 }
1367 if (value == NULL) {
1368 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1369 return(NULL);
1370 }
1371 if (attr == NULL) {
1372 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1373 return(NULL);
1374 }
1375
1376 /*
1377 * Create the ID table if needed.
1378 */
1379 table = doc->ids;
1380 if (table == NULL)
1381 table = doc->ids = xmlCreateIDTable();
1382 if (table == NULL) {
1383 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1384 return(NULL);
1385 }
1386
1387 /*
1388 * Validity Check:
1389 * Search the DTD for previous declarations of the ATTLIST
1390 */
1391 for (i = 0;i < table->nb_ids;i++) {
1392 cur = table->table[i];
1393 if (!xmlStrcmp(cur->value, value)) {
1394 /*
1395 * The id is already defined in this Dtd.
1396 */
1397 VERROR(ctxt->userData, "ID %s already defined\n", value);
1398 return(NULL);
1399 }
1400 }
1401
1402 /*
1403 * Grow the table, if needed.
1404 */
1405 if (table->nb_ids >= table->max_ids) {
1406 /*
1407 * need more ids.
1408 */
1409 table->max_ids *= 2;
1410 table->table = (xmlIDPtr *)
1411 realloc(table->table, table->max_ids *
1412 sizeof(xmlIDPtr));
1413 if (table->table == NULL) {
1414 fprintf(stderr, "xmlAddID: out of memory\n");
1415 return(NULL);
1416 }
1417 }
1418 ret = (xmlIDPtr) malloc(sizeof(xmlID));
1419 if (ret == NULL) {
1420 fprintf(stderr, "xmlAddID: out of memory\n");
1421 return(NULL);
1422 }
1423 table->table[table->nb_ids] = ret;
1424
1425 /*
1426 * fill the structure.
1427 */
1428 ret->value = xmlStrdup(value);
1429 ret->attr = attr;
1430 table->nb_ids++;
1431
1432 return(ret);
1433}
1434
1435/**
1436 * xmlFreeID:
1437 * @not: A id
1438 *
1439 * Deallocate the memory used by an id definition
1440 */
1441void
1442xmlFreeID(xmlIDPtr id) {
1443 if (id == NULL) return;
1444 if (id->value != NULL)
1445 free((CHAR *) id->value);
1446 memset(id, -1, sizeof(xmlID));
1447 free(id);
1448}
1449
1450/**
1451 * xmlFreeIDTable:
1452 * @table: An id table
1453 *
1454 * Deallocate the memory used by an ID hash table.
1455 */
1456void
1457xmlFreeIDTable(xmlIDTablePtr table) {
1458 int i;
1459
1460 if (table == NULL) return;
1461
1462 for (i = 0;i < table->nb_ids;i++) {
1463 xmlFreeID(table->table[i]);
1464 }
1465 free(table->table);
1466 free(table);
1467}
1468
1469/**
1470 * xmlIsID
1471 * @doc: the document
1472 * @elem: the element carrying the attribute
1473 * @attr: the attribute
1474 *
1475 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1476 * then this is simple, otherwise we use an heuristic: name ID (upper
1477 * or lowercase).
1478 *
1479 * Returns 0 or 1 depending on the lookup result
1480 */
1481int
1482xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1483 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1484 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1485 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1486 (attr->name[2] == 0)) return(1);
1487 } else {
1488 xmlAttributePtr attrDecl;
1489
1490 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1491 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1492 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1493 attr->name);
1494
1495 if ((attrDecl == NULL) || (attrDecl->type == XML_ATTRIBUTE_ID))
1496 return(1);
1497 }
1498 return(0);
1499}
1500
1501/************************************************************************
1502 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001503 * Routines for validity checking *
1504 * *
1505 ************************************************************************/
1506
1507/**
1508 * xmlGetDtdElementDesc:
1509 * @dtd: a pointer to the DtD to search
1510 * @name: the element name
1511 *
1512 * Search the Dtd for the description of this element
1513 *
1514 * returns the xmlElementPtr if found or NULL
1515 */
1516
1517xmlElementPtr
1518xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
1519 xmlElementTablePtr table;
1520 xmlElementPtr cur;
1521 int i;
1522
1523 if (dtd == NULL) return(NULL);
1524 if (dtd->elements == NULL) return(NULL);
1525 table = dtd->elements;
1526
1527 for (i = 0;i < table->nb_elements;i++) {
1528 cur = table->table[i];
1529 if (!xmlStrcmp(cur->name, name))
1530 return(cur);
1531 }
1532 return(NULL);
1533}
1534
1535/**
1536 * xmlGetDtdAttrDesc:
1537 * @dtd: a pointer to the DtD to search
1538 * @elem: the element name
1539 * @name: the attribute name
1540 *
1541 * Search the Dtd for the description of this attribute on
1542 * this element.
1543 *
1544 * returns the xmlAttributePtr if found or NULL
1545 */
1546
1547xmlAttributePtr
1548xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
1549 xmlAttributeTablePtr table;
1550 xmlAttributePtr cur;
1551 int i;
1552
1553 if (dtd == NULL) return(NULL);
1554 if (dtd->attributes == NULL) return(NULL);
1555 table = dtd->attributes;
1556
1557 for (i = 0;i < table->nb_attributes;i++) {
1558 cur = table->table[i];
1559 if ((!xmlStrcmp(cur->name, name)) &&
1560 (!xmlStrcmp(cur->elem, elem)))
1561 return(cur);
1562 }
1563 return(NULL);
1564}
1565
1566/**
1567 * xmlGetDtdNotationDesc:
1568 * @dtd: a pointer to the DtD to search
1569 * @name: the notation name
1570 *
1571 * Search the Dtd for the description of this notation
1572 *
1573 * returns the xmlNotationPtr if found or NULL
1574 */
1575
1576xmlNotationPtr
1577xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
1578 xmlNotationTablePtr table;
1579 xmlNotationPtr cur;
1580 int i;
1581
1582 if (dtd == NULL) return(NULL);
1583 if (dtd->notations == NULL) return(NULL);
1584 table = dtd->notations;
1585
1586 for (i = 0;i < table->nb_notations;i++) {
1587 cur = table->table[i];
1588 if (!xmlStrcmp(cur->name, name))
1589 return(cur);
1590 }
1591 return(NULL);
1592}
1593
1594/**
1595 * xmlIsMixedElement
1596 * @doc: the document
1597 * @name: the element name
1598 *
1599 * Search in the DtDs whether an element accept Mixed content (or ANY)
1600 * basically if it is supposed to accept text childs
1601 *
1602 * returns 0 if no, 1 if yes, and -1 if no element description is available
1603 */
1604
1605int
1606xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
1607 xmlElementPtr elemDecl;
1608
1609 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1610
1611 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1612 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1613 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1614 if (elemDecl == NULL) return(-1);
1615 switch (elemDecl->type) {
1616 case XML_ELEMENT_TYPE_ELEMENT:
1617 return(0);
1618 case XML_ELEMENT_TYPE_EMPTY:
1619 /*
1620 * return 1 for EMPTY since we want VC error to pop up
1621 * on <empty> </empty> for example
1622 */
1623 case XML_ELEMENT_TYPE_ANY:
1624 case XML_ELEMENT_TYPE_MIXED:
1625 return(1);
1626 }
1627 return(1);
1628}
1629
1630/**
1631 * xmlValidateNameValue:
1632 * @value: an Name value
1633 *
1634 * Validate that the given value match Name production
1635 *
1636 * returns 1 if valid or 0 otherwise
1637 */
1638
1639int
1640xmlValidateNameValue(const CHAR *value) {
1641 const CHAR *cur;
1642
1643 if (value == NULL) return(0);
1644 cur = value;
1645
1646 if (!IS_LETTER(*cur) && (*cur != '_') &&
1647 (*cur != ':')) {
1648 return(0);
1649 }
1650
1651 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1652 (*cur == '.') || (*cur == '-') ||
1653 (*cur == '_') || (*cur == ':') ||
1654 (IS_COMBINING(*cur)) ||
1655 (IS_EXTENDER(*cur)))
1656 cur++;
1657
1658 if (*cur != 0) return(0);
1659
1660 return(1);
1661}
1662
1663/**
1664 * xmlValidateNamesValue:
1665 * @value: an Names value
1666 *
1667 * Validate that the given value match Names production
1668 *
1669 * returns 1 if valid or 0 otherwise
1670 */
1671
1672int
1673xmlValidateNamesValue(const CHAR *value) {
1674 const CHAR *cur;
1675
1676 if (value == NULL) return(0);
1677 cur = value;
1678
1679 if (!IS_LETTER(*cur) && (*cur != '_') &&
1680 (*cur != ':')) {
1681 return(0);
1682 }
1683
1684 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1685 (*cur == '.') || (*cur == '-') ||
1686 (*cur == '_') || (*cur == ':') ||
1687 (IS_COMBINING(*cur)) ||
1688 (IS_EXTENDER(*cur)))
1689 cur++;
1690
1691 while (IS_BLANK(*cur)) {
1692 while (IS_BLANK(*cur)) cur++;
1693
1694 if (!IS_LETTER(*cur) && (*cur != '_') &&
1695 (*cur != ':')) {
1696 return(0);
1697 }
1698
1699 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1700 (*cur == '.') || (*cur == '-') ||
1701 (*cur == '_') || (*cur == ':') ||
1702 (IS_COMBINING(*cur)) ||
1703 (IS_EXTENDER(*cur)))
1704 cur++;
1705 }
1706
1707 if (*cur != 0) return(0);
1708
1709 return(1);
1710}
1711
1712/**
1713 * xmlValidateNmtokenValue:
1714 * @value: an Mntoken value
1715 *
1716 * Validate that the given value match Nmtoken production
1717 *
1718 * [ VC: Name Token ]
1719 *
1720 * returns 1 if valid or 0 otherwise
1721 */
1722
1723int
1724xmlValidateNmtokenValue(const CHAR *value) {
1725 const CHAR *cur;
1726
1727 if (value == NULL) return(0);
1728 cur = value;
1729
1730 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1731 (*cur != '.') && (*cur != '-') &&
1732 (*cur != '_') && (*cur != ':') &&
1733 (!IS_COMBINING(*cur)) &&
1734 (!IS_EXTENDER(*cur)))
1735 return(0);
1736
1737 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1738 (*cur == '.') || (*cur == '-') ||
1739 (*cur == '_') || (*cur == ':') ||
1740 (IS_COMBINING(*cur)) ||
1741 (IS_EXTENDER(*cur)))
1742 cur++;
1743
1744 if (*cur != 0) return(0);
1745
1746 return(1);
1747 return(1);
1748}
1749
1750/**
1751 * xmlValidateNmtokensValue:
1752 * @value: an Mntokens value
1753 *
1754 * Validate that the given value match Nmtokens production
1755 *
1756 * [ VC: Name Token ]
1757 *
1758 * returns 1 if valid or 0 otherwise
1759 */
1760
1761int
1762xmlValidateNmtokensValue(const CHAR *value) {
1763 const CHAR *cur;
1764
1765 if (value == NULL) return(0);
1766 cur = value;
1767
1768 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1769 (*cur != '.') && (*cur != '-') &&
1770 (*cur != '_') && (*cur != ':') &&
1771 (!IS_COMBINING(*cur)) &&
1772 (!IS_EXTENDER(*cur)))
1773 return(0);
1774
1775 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1776 (*cur == '.') || (*cur == '-') ||
1777 (*cur == '_') || (*cur == ':') ||
1778 (IS_COMBINING(*cur)) ||
1779 (IS_EXTENDER(*cur)))
1780 cur++;
1781
1782 while (IS_BLANK(*cur)) {
1783 while (IS_BLANK(*cur)) cur++;
1784
1785 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1786 (*cur != '.') && (*cur != '-') &&
1787 (*cur != '_') && (*cur != ':') &&
1788 (!IS_COMBINING(*cur)) &&
1789 (!IS_EXTENDER(*cur)))
1790 return(0);
1791
1792 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1793 (*cur == '.') || (*cur == '-') ||
1794 (*cur == '_') || (*cur == ':') ||
1795 (IS_COMBINING(*cur)) ||
1796 (IS_EXTENDER(*cur)))
1797 cur++;
1798 }
1799
1800 if (*cur != 0) return(0);
1801
1802 return(1);
1803}
1804
1805/**
1806 * xmlValidateNotationDecl:
1807 * @doc: a document instance
1808 * @nota: a notation definition
1809 *
1810 * Try to validate a single notation definition
1811 * basically it does the following checks as described by the
1812 * XML-1.0 recommendation:
1813 * - it seems that no validity constraing exist on notation declarations
1814 * But this function get called anyway ...
1815 *
1816 * returns 1 if valid or 0 otherwise
1817 */
1818
1819int
1820xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1821 xmlNotationPtr nota) {
1822 int ret = 1;
1823
1824 return(ret);
1825}
1826
1827/**
1828 * xmlValidateAttributeValue:
1829 * @type: an attribute type
1830 * @value: an attribute value
1831 *
1832 * Validate that the given attribute value match the proper production
1833 *
1834 * [ VC: ID ]
1835 * Values of type ID must match the Name production....
1836 *
1837 * [ VC: IDREF ]
1838 * Values of type IDREF must match the Name production, and values
1839 * of type IDREFS must match Names ...
1840 *
1841 * [ VC: Entity Name ]
1842 * Values of type ENTITY must match the Name production, values
1843 * of type ENTITIES must match Names ...
1844 *
1845 * [ VC: Name Token ]
1846 * Values of type NMTOKEN must match the Nmtoken production; values
1847 * of type NMTOKENS must match Nmtokens.
1848 *
1849 * returns 1 if valid or 0 otherwise
1850 */
1851
1852int
1853xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
1854 switch (type) {
1855 case XML_ATTRIBUTE_IDREFS:
1856 case XML_ATTRIBUTE_ENTITIES:
1857 return(xmlValidateNamesValue(value));
1858 case XML_ATTRIBUTE_IDREF:
1859 case XML_ATTRIBUTE_ID:
1860 case XML_ATTRIBUTE_ENTITY:
1861 case XML_ATTRIBUTE_NOTATION:
1862 return(xmlValidateNameValue(value));
1863 case XML_ATTRIBUTE_NMTOKENS:
1864 case XML_ATTRIBUTE_ENUMERATION:
1865 return(xmlValidateNmtokensValue(value));
1866 case XML_ATTRIBUTE_NMTOKEN:
1867 return(xmlValidateNmtokenValue(value));
1868 case XML_ATTRIBUTE_CDATA:
1869 break;
1870 }
1871 return(1);
1872}
1873
1874/**
1875 * xmlValidateAttributeDecl:
1876 * @doc: a document instance
1877 * @attr: an attribute definition
1878 *
1879 * Try to validate a single attribute definition
1880 * basically it does the following checks as described by the
1881 * XML-1.0 recommendation:
1882 * - [ VC: Attribute Default Legal ]
1883 * - [ VC: Enumeration ]
1884 * - [ VC: ID Attribute Default ]
1885 *
1886 * The ID/IDREF uniqueness and matching are done separately
1887 *
1888 * returns 1 if valid or 0 otherwise
1889 */
1890
1891int
1892xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1893 xmlAttributePtr attr) {
1894 int ret = 1;
1895 int val;
1896 CHECK_DTD;
1897 if(attr == NULL) return(1);
1898
1899 /* Attribute Default Legal */
1900 /* Enumeration */
1901 if (attr->defaultValue != NULL) {
1902 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
1903 if (val == 0) {
1904 VERROR(ctxt->userData,
1905 "Syntax of default value for attribute %s on %s is not valid\n",
1906 attr->name, attr->elem);
1907 }
1908 ret &= val;
1909 }
1910
1911 /* ID Attribute Default */
1912 if ((attr->type == XML_ATTRIBUTE_ID)&&
1913 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
1914 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
1915 VERROR(ctxt->userData,
1916 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
1917 attr->name, attr->elem);
1918 ret = 0;
1919 }
1920
1921 /* max ID per element */
1922 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
1923 int nbId = 0;
1924
1925 /* the trick is taht we parse DtD as their own internal subset */
1926 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
1927 attr->elem);
1928 if (elem != NULL) {
1929 nbId = xmlScanIDAttributeDecl(NULL, elem);
1930 }
1931 if (nbId >= 1)
1932 VERROR(ctxt->userData,
1933 "Element %s has ID attribute defined in the external subset : %s\n",
1934 attr->elem, attr->name);
1935 }
1936
1937 return(ret);
1938}
1939
1940/**
1941 * xmlValidateElementDecl:
1942 * @ctxt: the validation context
1943 * @doc: a document instance
1944 * @elem: an element definition
1945 *
1946 * Try to validate a single element definition
1947 * basically it does the following checks as described by the
1948 * XML-1.0 recommendation:
1949 * - [ VC: One ID per Element Type ]
1950 * - [ VC: No Duplicate Types ]
1951 * - [ VC: Unique Element Type Declaration ]
1952 *
1953 * returns 1 if valid or 0 otherwise
1954 */
1955
1956int
1957xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1958 xmlElementPtr elem) {
1959 int ret = 1;
1960 xmlElementPtr tst;
1961
1962 CHECK_DTD;
1963
1964 if (elem == NULL) return(1);
1965
1966 /* No Duplicate Types */
1967 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
1968 xmlElementContentPtr cur, next;
1969 const CHAR *name;
1970
1971 cur = elem->content;
1972 while (cur != NULL) {
1973 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
1974 if (cur->c1 == NULL) break;
1975 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
1976 name = cur->c1->name;
1977 next = cur->c2;
1978 while (next != NULL) {
1979 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
1980 if (!xmlStrcmp(next->name, name)) {
1981 VERROR(ctxt->userData,
1982 "Definition of %s has duplicate references of %s\n",
1983 elem->name, name);
1984 ret = 0;
1985 }
1986 break;
1987 }
1988 if (next->c1 == NULL) break;
1989 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
1990 if (!xmlStrcmp(next->c1->name, name)) {
1991 VERROR(ctxt->userData,
1992 "Definition of %s has duplicate references of %s\n",
1993 elem->name, name);
1994 ret = 0;
1995 }
1996 next = next->c2;
1997 }
1998 }
1999 cur = cur->c2;
2000 }
2001 }
2002
2003 /* VC: Unique Element Type Declaration */
2004 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2005 if ((tst != NULL ) && (tst != elem)) {
2006 VERROR(ctxt->userData, "Redefinition of element %s\n",
2007 elem->name);
2008 ret = 0;
2009 }
2010 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2011 if ((tst != NULL ) && (tst != elem)) {
2012 VERROR(ctxt->userData, "Redefinition of element %s\n",
2013 elem->name);
2014 ret = 0;
2015 }
2016
2017 /* One ID per Element Type */
2018 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2019 ret = 0;
2020 }
2021 return(ret);
2022}
2023
2024/**
2025 * xmlValidateOneAttribute:
2026 * @ctxt: the validation context
2027 * @doc: a document instance
2028 * @elem: an element instance
2029 * @attr: an attribute instance
2030 *
2031 * Try to validate a single attribute for an element
2032 * basically it * does the following checks as described by the
2033 * XML-1.0 recommendation:
2034 * - [ VC: Attribute Value Type ]
2035 * - [ VC: Fixed Attribute Default ]
2036 * - [ VC: Entity Name ]
2037 * - [ VC: Name Token ]
2038 * - [ VC: ID ]
2039 * - [ VC: IDREF ]
2040 * - [ VC: Entity Name ]
2041 * - [ VC: Notation Attributes ]
2042 *
2043 * The ID/IDREF uniqueness and matching are done separately
2044 *
2045 * returns 1 if valid or 0 otherwise
2046 */
2047
2048int
2049xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2050 xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
2051 xmlElementPtr elemDecl;
2052 xmlAttributePtr attrDecl;
2053 int val;
2054 int ret = 1;
2055
2056 CHECK_DTD;
2057 if ((elem == NULL) || (elem->name == NULL)) return(0);
2058 if ((attr == NULL) || (attr->name == NULL)) return(0);
2059
2060 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2061 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2062 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2063
2064
2065 /* Validity Constraint: Attribute Value Type */
2066 if (attrDecl == NULL) {
2067 VERROR(ctxt->userData,
2068 "No declaration for attribute %s on element %s\n",
2069 attr->name, elem->name);
2070 return(0);
2071 }
2072 val = xmlValidateAttributeValue(attrDecl->type, value);
2073 if (val == 0) {
2074 VERROR(ctxt->userData,
2075 "Syntax of value for attribute %s on %s is not valid\n",
2076 attr->name, elem->name);
2077 ret = 0;
2078 }
2079
2080 /* Validity Constraint: Notation Attributes */
2081 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2082 xmlEnumerationPtr tree = attrDecl->tree;
2083 xmlNotationPtr nota;
2084
2085 /* First check that the given NOTATION was declared */
2086 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2087 if (nota == NULL)
2088 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2089
2090 if (nota == NULL) {
2091 VERROR(ctxt->userData,
2092 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2093 value, attr->name, elem->name);
2094 ret = 0;
2095 }
2096
2097 /* Second, verify that it's among the list */
2098 while (tree != NULL) {
2099 if (!xmlStrcmp(tree->name, value)) break;
2100 tree = tree->next;
2101 }
2102 if (tree == NULL) {
2103 VERROR(ctxt->userData,
2104 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2105 value, attr->name, elem->name);
2106 ret = 0;
2107 }
2108 }
2109
2110 /* Validity Constraint: Enumeration */
2111 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2112 xmlEnumerationPtr tree = attrDecl->tree;
2113 while (tree != NULL) {
2114 if (!xmlStrcmp(tree->name, value)) break;
2115 tree = tree->next;
2116 }
2117 if (tree == NULL) {
2118 VERROR(ctxt->userData,
2119 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2120 value, attr->name, elem->name);
2121 ret = 0;
2122 }
2123 }
2124
2125 /* Fixed Attribute Default */
2126 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2127 (xmlStrcmp(attrDecl->defaultValue, value))) {
2128 VERROR(ctxt->userData,
2129 "Value for attribute %s on %s must be \"%s\"\n",
2130 attr->name, elem->name, attrDecl->defaultValue);
2131 ret = 0;
2132 }
2133
2134 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2135 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2136 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2137 if (elemDecl == NULL) {
2138 /* the error has or will be reported soon in xmlValidateOneElement */
2139 return(0);
2140 }
2141 return(ret);
2142}
2143
2144int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2145 xmlElementContentPtr cont);
2146
2147/**
2148 * xmlValidateElementTypeExpr:
2149 * @ctxt: the validation context
2150 * @child: pointer to the child list
2151 * @cont: pointer to the content declaration
2152 *
2153 * Try to validate the content of an element of type element
2154 * but don't handle the occurence factor
2155 *
2156 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2157 * also update child value in-situ.
2158 */
2159
2160int
2161xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2162 xmlElementContentPtr cont) {
2163 xmlNodePtr cur;
2164 int ret = 1;
2165
2166 if (cont == NULL) return(-1);
2167 while (*child != NULL) {
2168 if ((*child)->type == XML_PI_NODE) {
2169 *child = (*child)->next;
2170 continue;
2171 }
2172 if ((*child)->type == XML_COMMENT_NODE) {
2173 *child = (*child)->next;
2174 continue;
2175 }
2176 else if ((*child)->type != XML_ELEMENT_NODE) {
2177 return(-1);
2178 }
2179 break;
2180 }
2181 switch (cont->type) {
2182 case XML_ELEMENT_CONTENT_PCDATA:
2183 /* Internal error !!! */
2184 fprintf(stderr, "Internal: MIXED struct bad\n");
2185 return(-1);
2186 case XML_ELEMENT_CONTENT_ELEMENT:
2187 if (*child == NULL) return(0);
2188 ret = (!xmlStrcmp((*child)->name, cont->name));
2189 if (ret == 1)
2190 *child = (*child)->next;
2191 return(ret);
2192 case XML_ELEMENT_CONTENT_OR:
2193 cur = *child;
2194 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2195 if (ret == -1) return(-1);
2196 if (ret == 1) {
2197 return(1);
2198 }
2199 /* rollback and retry the other path */
2200 *child = cur;
2201 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2202 if (ret == -1) return(-1);
2203 if (ret == 0) {
2204 *child = cur;
2205 return(0);
2206 }
2207 return(1);
2208 case XML_ELEMENT_CONTENT_SEQ:
2209 cur = *child;
2210 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2211 if (ret == -1) return(-1);
2212 if (ret == 0) {
2213 *child = cur;
2214 return(0);
2215 }
2216 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2217 if (ret == -1) return(-1);
2218 if (ret == 0) {
2219 *child = cur;
2220 return(0);
2221 }
2222 return(1);
2223 }
2224 return(ret);
2225}
2226
2227/**
2228 * xmlValidateElementTypeElement:
2229 * @ctxt: the validation context
2230 * @child: pointer to the child list
2231 * @cont: pointer to the content declaration
2232 *
2233 * Try to validate the content of an element of type element
2234 * yeah, Yet Another Regexp Implementation, and recursive
2235 *
2236 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2237 * also update child and content values in-situ.
2238 */
2239
2240int
2241xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2242 xmlElementContentPtr cont) {
2243 xmlNodePtr cur;
2244 int ret = 1;
2245
2246 if (cont == NULL) return(-1);
2247 while (*child != NULL) {
2248 if ((*child)->type == XML_PI_NODE) {
2249 *child = (*child)->next;
2250 continue;
2251 }
2252 if ((*child)->type == XML_COMMENT_NODE) {
2253 *child = (*child)->next;
2254 continue;
2255 }
2256 else if ((*child)->type != XML_ELEMENT_NODE) {
2257 return(-1);
2258 }
2259 break;
2260 }
2261 cur = *child;
2262 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2263 if (ret == -1) return(-1);
2264 switch (cont->ocur) {
2265 case XML_ELEMENT_CONTENT_ONCE:
2266 if (ret == 1) {
2267 return(1);
2268 }
2269 *child = cur;
2270 return(0);
2271 case XML_ELEMENT_CONTENT_OPT:
2272 if (ret == 0) {
2273 *child = cur;
2274 return(1);
2275 }
2276 break;
2277 case XML_ELEMENT_CONTENT_MULT:
2278 if (ret == 0) {
2279 *child = cur;
2280 break;
2281 }
2282 /* no break on purpose */
2283 case XML_ELEMENT_CONTENT_PLUS:
2284 if (ret == 0) {
2285 *child = cur;
2286 return(0);
2287 }
2288 do {
2289 cur = *child;
2290 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2291 } while (ret == 1);
2292 if (ret == -1) return(-1);
2293 *child = cur;
2294 break;
2295 }
2296 while (*child != NULL) {
2297 if ((*child)->type == XML_PI_NODE) {
2298 *child = (*child)->next;
2299 continue;
2300 }
2301 if ((*child)->type == XML_COMMENT_NODE) {
2302 *child = (*child)->next;
2303 continue;
2304 }
2305 else if ((*child)->type != XML_ELEMENT_NODE) {
2306 return(-1);
2307 }
2308 break;
2309 }
2310 return(1);
2311}
2312
2313/**
2314 * xmlSprintfElementChilds:
2315 * @buf: an output buffer
2316 * @content: An element
2317 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2318 *
2319 * This will dump the list of childs to the buffer
2320 * Intended just for the debug routine
2321 */
2322void
2323xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2324 xmlNodePtr cur;
2325
2326 if (node == NULL) return;
2327 if (glob) strcat(buf, "(");
2328 cur = node->childs;
2329 while (cur != NULL) {
2330 switch (cur->type) {
2331 case XML_ELEMENT_NODE:
2332 strcat(buf, cur->name);
2333 if (cur->next != NULL)
2334 strcat(buf, " ");
2335 break;
2336 case XML_TEXT_NODE:
2337 case XML_CDATA_SECTION_NODE:
2338 case XML_ENTITY_REF_NODE:
2339 strcat(buf, "CDATA");
2340 if (cur->next != NULL)
2341 strcat(buf, " ");
2342 break;
2343 case XML_ATTRIBUTE_NODE:
2344 case XML_DOCUMENT_NODE:
2345 case XML_DOCUMENT_TYPE_NODE:
2346 case XML_DOCUMENT_FRAG_NODE:
2347 case XML_NOTATION_NODE:
2348 strcat(buf, "???");
2349 if (cur->next != NULL)
2350 strcat(buf, " ");
2351 break;
2352 case XML_ENTITY_NODE:
2353 case XML_PI_NODE:
2354 case XML_COMMENT_NODE:
2355 break;
2356 }
2357 cur = cur->next;
2358 }
2359 if (glob) strcat(buf, ")");
2360}
2361
2362
2363/**
2364 * xmlValidateOneElement:
2365 * @ctxt: the validation context
2366 * @doc: a document instance
2367 * @elem: an element instance
2368 *
2369 * Try to validate a single element and it's attributes,
2370 * basically it does the following checks as described by the
2371 * XML-1.0 recommendation:
2372 * - [ VC: Element Valid ]
2373 * - [ VC: Required Attribute ]
2374 * Then call xmlValidateOneAttribute() for each attribute present.
2375 *
2376 * The ID/IDREF checkings are done separately
2377 *
2378 * returns 1 if valid or 0 otherwise
2379 */
2380
2381int
2382xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2383 xmlNodePtr elem) {
2384 xmlElementPtr elemDecl;
2385 xmlElementContentPtr cont;
2386 xmlNodePtr child;
2387 int ret = 1;
2388 const CHAR *name;
2389
2390 CHECK_DTD;
2391
2392 if ((elem == NULL) || (elem->name == NULL)) return(0);
2393
2394 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2395 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2396 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2397 if (elemDecl == NULL) {
2398 VERROR(ctxt->userData, "No declaration for element %s\n",
2399 elem->name);
2400 return(0);
2401 }
2402
2403 /* Check taht the element content matches the definition */
2404 switch (elemDecl->type) {
2405 case XML_ELEMENT_TYPE_EMPTY:
2406 if (elem->childs != NULL) {
2407 VERROR(ctxt->userData,
2408 "Element %s was declared EMPTY this one has content\n",
2409 elem->name);
2410 ret = 0;
2411 }
2412 break;
2413 case XML_ELEMENT_TYPE_ANY:
2414 /* I don't think anything is required then */
2415 break;
2416 case XML_ELEMENT_TYPE_MIXED:
2417 /* Hum, this start to get messy */
2418 child = elem->childs;
2419 while (child != NULL) {
2420 if (child->type == XML_ELEMENT_NODE) {
2421 name = child->name;
2422 cont = elemDecl->content;
2423 while (cont != NULL) {
2424 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2425 if (!xmlStrcmp(cont->name, name)) break;
2426 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2427 (cont->c1 != NULL) &&
2428 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2429 if (!xmlStrcmp(cont->c1->name, name)) break;
2430 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2431 (cont->c1 == NULL) ||
2432 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2433 /* Internal error !!! */
2434 fprintf(stderr, "Internal: MIXED struct bad\n");
2435 break;
2436 }
2437 cont = cont->c2;
2438 }
2439 if (cont == NULL) {
2440 VERROR(ctxt->userData,
2441 "Element %s is not declared in %s list of possible childs\n",
2442 name, elem->name);
2443 ret = 0;
2444 }
2445 }
2446 child = child->next;
2447 }
2448 break;
2449 case XML_ELEMENT_TYPE_ELEMENT:
2450 child = elem->childs;
2451 cont = elemDecl->content;
2452 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2453 if ((ret == 0) || (child != NULL)) {
2454 char expr[1000];
2455 char list[2000];
2456
2457 expr[0] = 0;
2458 xmlSprintfElementContent(expr, cont, 1);
2459 list[0] = 0;
2460 xmlSprintfElementChilds(list, elem, 1);
2461
2462 VERROR(ctxt->userData,
2463 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2464 elem->name, expr, list);
2465 ret = 0;
2466 }
2467 break;
2468 }
2469
2470 return(ret);
2471}
2472
2473/**
2474 * xmlValidateRoot:
2475 * @ctxt: the validation context
2476 * @doc: a document instance
2477 *
2478 * Try to validate a the root element
2479 * basically it does the following check as described by the
2480 * XML-1.0 recommendation:
2481 * - [ VC: Root Element Type ]
2482 * it doesn't try to recurse or apply other check to the element
2483 *
2484 * returns 1 if valid or 0 otherwise
2485 */
2486
2487int
2488xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2489 if (doc == NULL) return(0);
2490
2491 if ((doc->intSubset == NULL) ||
2492 (doc->intSubset->name == NULL)) {
2493 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2494 return(0);
2495 }
2496 if ((doc->root == NULL) || (doc->root->name == NULL)) {
2497 VERROR(ctxt->userData, "Not valid: no root element\n");
2498 return(0);
2499 }
2500 if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2501 VERROR(ctxt->userData,
2502 "Not valid: root and DtD name do not match %s and %s\n",
2503 doc->root->name, doc->intSubset->name);
2504 return(0);
2505 }
2506 return(1);
2507}
2508
2509
2510/**
2511 * xmlValidateElement:
2512 * @ctxt: the validation context
2513 * @doc: a document instance
2514 * @elem: an element instance
2515 *
2516 * Try to validate the subtree under an element
2517 *
2518 * returns 1 if valid or 0 otherwise
2519 */
2520
2521int
2522xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
2523 CHECK_DTD;
2524
2525 return(1);
2526}
2527
2528/**
2529 * xmlValidateDtd:
2530 * @ctxt: the validation context
2531 * @doc: a document instance
2532 * @dtd: a dtd instance
2533 *
2534 * Try to validate the dtd instance
2535 *
2536 * basically it does check all the definitions in the DtD.
2537 *
2538 * returns 1 if valid or 0 otherwise
2539 */
2540
2541int
2542xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
2543 return(1);
2544}
2545
2546/**
2547 * xmlValidateDocument:
2548 * @ctxt: the validation context
2549 * @doc: a document instance
2550 *
2551 * Try to validate the document instance
2552 *
2553 * basically it does the all the checks described by the
2554 * i.e. validates the internal and external subset (if present)
2555 * and validate the document tree.
2556 *
2557 * returns 1 if valid or 0 otherwise
2558 */
2559
2560int
2561xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2562 if (!xmlValidateRoot(ctxt, doc)) return(0);
2563
2564 return(1);
2565}
2566