blob: b23824f3fa5adc74d7f54a8bd12563ac6f8c9f50 [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 * *
1309 * Routines for validity checking *
1310 * *
1311 ************************************************************************/
1312
1313/**
1314 * xmlGetDtdElementDesc:
1315 * @dtd: a pointer to the DtD to search
1316 * @name: the element name
1317 *
1318 * Search the Dtd for the description of this element
1319 *
1320 * returns the xmlElementPtr if found or NULL
1321 */
1322
1323xmlElementPtr
1324xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
1325 xmlElementTablePtr table;
1326 xmlElementPtr cur;
1327 int i;
1328
1329 if (dtd == NULL) return(NULL);
1330 if (dtd->elements == NULL) return(NULL);
1331 table = dtd->elements;
1332
1333 for (i = 0;i < table->nb_elements;i++) {
1334 cur = table->table[i];
1335 if (!xmlStrcmp(cur->name, name))
1336 return(cur);
1337 }
1338 return(NULL);
1339}
1340
1341/**
1342 * xmlGetDtdAttrDesc:
1343 * @dtd: a pointer to the DtD to search
1344 * @elem: the element name
1345 * @name: the attribute name
1346 *
1347 * Search the Dtd for the description of this attribute on
1348 * this element.
1349 *
1350 * returns the xmlAttributePtr if found or NULL
1351 */
1352
1353xmlAttributePtr
1354xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
1355 xmlAttributeTablePtr table;
1356 xmlAttributePtr cur;
1357 int i;
1358
1359 if (dtd == NULL) return(NULL);
1360 if (dtd->attributes == NULL) return(NULL);
1361 table = dtd->attributes;
1362
1363 for (i = 0;i < table->nb_attributes;i++) {
1364 cur = table->table[i];
1365 if ((!xmlStrcmp(cur->name, name)) &&
1366 (!xmlStrcmp(cur->elem, elem)))
1367 return(cur);
1368 }
1369 return(NULL);
1370}
1371
1372/**
1373 * xmlGetDtdNotationDesc:
1374 * @dtd: a pointer to the DtD to search
1375 * @name: the notation name
1376 *
1377 * Search the Dtd for the description of this notation
1378 *
1379 * returns the xmlNotationPtr if found or NULL
1380 */
1381
1382xmlNotationPtr
1383xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
1384 xmlNotationTablePtr table;
1385 xmlNotationPtr cur;
1386 int i;
1387
1388 if (dtd == NULL) return(NULL);
1389 if (dtd->notations == NULL) return(NULL);
1390 table = dtd->notations;
1391
1392 for (i = 0;i < table->nb_notations;i++) {
1393 cur = table->table[i];
1394 if (!xmlStrcmp(cur->name, name))
1395 return(cur);
1396 }
1397 return(NULL);
1398}
1399
1400/**
1401 * xmlIsMixedElement
1402 * @doc: the document
1403 * @name: the element name
1404 *
1405 * Search in the DtDs whether an element accept Mixed content (or ANY)
1406 * basically if it is supposed to accept text childs
1407 *
1408 * returns 0 if no, 1 if yes, and -1 if no element description is available
1409 */
1410
1411int
1412xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
1413 xmlElementPtr elemDecl;
1414
1415 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1416
1417 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1418 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1419 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1420 if (elemDecl == NULL) return(-1);
1421 switch (elemDecl->type) {
1422 case XML_ELEMENT_TYPE_ELEMENT:
1423 return(0);
1424 case XML_ELEMENT_TYPE_EMPTY:
1425 /*
1426 * return 1 for EMPTY since we want VC error to pop up
1427 * on <empty> </empty> for example
1428 */
1429 case XML_ELEMENT_TYPE_ANY:
1430 case XML_ELEMENT_TYPE_MIXED:
1431 return(1);
1432 }
1433 return(1);
1434}
1435
1436/**
1437 * xmlValidateNameValue:
1438 * @value: an Name value
1439 *
1440 * Validate that the given value match Name production
1441 *
1442 * returns 1 if valid or 0 otherwise
1443 */
1444
1445int
1446xmlValidateNameValue(const CHAR *value) {
1447 const CHAR *cur;
1448
1449 if (value == NULL) return(0);
1450 cur = value;
1451
1452 if (!IS_LETTER(*cur) && (*cur != '_') &&
1453 (*cur != ':')) {
1454 return(0);
1455 }
1456
1457 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1458 (*cur == '.') || (*cur == '-') ||
1459 (*cur == '_') || (*cur == ':') ||
1460 (IS_COMBINING(*cur)) ||
1461 (IS_EXTENDER(*cur)))
1462 cur++;
1463
1464 if (*cur != 0) return(0);
1465
1466 return(1);
1467}
1468
1469/**
1470 * xmlValidateNamesValue:
1471 * @value: an Names value
1472 *
1473 * Validate that the given value match Names production
1474 *
1475 * returns 1 if valid or 0 otherwise
1476 */
1477
1478int
1479xmlValidateNamesValue(const CHAR *value) {
1480 const CHAR *cur;
1481
1482 if (value == NULL) return(0);
1483 cur = value;
1484
1485 if (!IS_LETTER(*cur) && (*cur != '_') &&
1486 (*cur != ':')) {
1487 return(0);
1488 }
1489
1490 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1491 (*cur == '.') || (*cur == '-') ||
1492 (*cur == '_') || (*cur == ':') ||
1493 (IS_COMBINING(*cur)) ||
1494 (IS_EXTENDER(*cur)))
1495 cur++;
1496
1497 while (IS_BLANK(*cur)) {
1498 while (IS_BLANK(*cur)) cur++;
1499
1500 if (!IS_LETTER(*cur) && (*cur != '_') &&
1501 (*cur != ':')) {
1502 return(0);
1503 }
1504
1505 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1506 (*cur == '.') || (*cur == '-') ||
1507 (*cur == '_') || (*cur == ':') ||
1508 (IS_COMBINING(*cur)) ||
1509 (IS_EXTENDER(*cur)))
1510 cur++;
1511 }
1512
1513 if (*cur != 0) return(0);
1514
1515 return(1);
1516}
1517
1518/**
1519 * xmlValidateNmtokenValue:
1520 * @value: an Mntoken value
1521 *
1522 * Validate that the given value match Nmtoken production
1523 *
1524 * [ VC: Name Token ]
1525 *
1526 * returns 1 if valid or 0 otherwise
1527 */
1528
1529int
1530xmlValidateNmtokenValue(const CHAR *value) {
1531 const CHAR *cur;
1532
1533 if (value == NULL) return(0);
1534 cur = value;
1535
1536 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1537 (*cur != '.') && (*cur != '-') &&
1538 (*cur != '_') && (*cur != ':') &&
1539 (!IS_COMBINING(*cur)) &&
1540 (!IS_EXTENDER(*cur)))
1541 return(0);
1542
1543 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1544 (*cur == '.') || (*cur == '-') ||
1545 (*cur == '_') || (*cur == ':') ||
1546 (IS_COMBINING(*cur)) ||
1547 (IS_EXTENDER(*cur)))
1548 cur++;
1549
1550 if (*cur != 0) return(0);
1551
1552 return(1);
1553 return(1);
1554}
1555
1556/**
1557 * xmlValidateNmtokensValue:
1558 * @value: an Mntokens value
1559 *
1560 * Validate that the given value match Nmtokens production
1561 *
1562 * [ VC: Name Token ]
1563 *
1564 * returns 1 if valid or 0 otherwise
1565 */
1566
1567int
1568xmlValidateNmtokensValue(const CHAR *value) {
1569 const CHAR *cur;
1570
1571 if (value == NULL) return(0);
1572 cur = value;
1573
1574 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1575 (*cur != '.') && (*cur != '-') &&
1576 (*cur != '_') && (*cur != ':') &&
1577 (!IS_COMBINING(*cur)) &&
1578 (!IS_EXTENDER(*cur)))
1579 return(0);
1580
1581 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1582 (*cur == '.') || (*cur == '-') ||
1583 (*cur == '_') || (*cur == ':') ||
1584 (IS_COMBINING(*cur)) ||
1585 (IS_EXTENDER(*cur)))
1586 cur++;
1587
1588 while (IS_BLANK(*cur)) {
1589 while (IS_BLANK(*cur)) cur++;
1590
1591 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1592 (*cur != '.') && (*cur != '-') &&
1593 (*cur != '_') && (*cur != ':') &&
1594 (!IS_COMBINING(*cur)) &&
1595 (!IS_EXTENDER(*cur)))
1596 return(0);
1597
1598 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1599 (*cur == '.') || (*cur == '-') ||
1600 (*cur == '_') || (*cur == ':') ||
1601 (IS_COMBINING(*cur)) ||
1602 (IS_EXTENDER(*cur)))
1603 cur++;
1604 }
1605
1606 if (*cur != 0) return(0);
1607
1608 return(1);
1609}
1610
1611/**
1612 * xmlValidateNotationDecl:
1613 * @doc: a document instance
1614 * @nota: a notation definition
1615 *
1616 * Try to validate a single notation definition
1617 * basically it does the following checks as described by the
1618 * XML-1.0 recommendation:
1619 * - it seems that no validity constraing exist on notation declarations
1620 * But this function get called anyway ...
1621 *
1622 * returns 1 if valid or 0 otherwise
1623 */
1624
1625int
1626xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1627 xmlNotationPtr nota) {
1628 int ret = 1;
1629
1630 return(ret);
1631}
1632
1633/**
1634 * xmlValidateAttributeValue:
1635 * @type: an attribute type
1636 * @value: an attribute value
1637 *
1638 * Validate that the given attribute value match the proper production
1639 *
1640 * [ VC: ID ]
1641 * Values of type ID must match the Name production....
1642 *
1643 * [ VC: IDREF ]
1644 * Values of type IDREF must match the Name production, and values
1645 * of type IDREFS must match Names ...
1646 *
1647 * [ VC: Entity Name ]
1648 * Values of type ENTITY must match the Name production, values
1649 * of type ENTITIES must match Names ...
1650 *
1651 * [ VC: Name Token ]
1652 * Values of type NMTOKEN must match the Nmtoken production; values
1653 * of type NMTOKENS must match Nmtokens.
1654 *
1655 * returns 1 if valid or 0 otherwise
1656 */
1657
1658int
1659xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
1660 switch (type) {
1661 case XML_ATTRIBUTE_IDREFS:
1662 case XML_ATTRIBUTE_ENTITIES:
1663 return(xmlValidateNamesValue(value));
1664 case XML_ATTRIBUTE_IDREF:
1665 case XML_ATTRIBUTE_ID:
1666 case XML_ATTRIBUTE_ENTITY:
1667 case XML_ATTRIBUTE_NOTATION:
1668 return(xmlValidateNameValue(value));
1669 case XML_ATTRIBUTE_NMTOKENS:
1670 case XML_ATTRIBUTE_ENUMERATION:
1671 return(xmlValidateNmtokensValue(value));
1672 case XML_ATTRIBUTE_NMTOKEN:
1673 return(xmlValidateNmtokenValue(value));
1674 case XML_ATTRIBUTE_CDATA:
1675 break;
1676 }
1677 return(1);
1678}
1679
1680/**
1681 * xmlValidateAttributeDecl:
1682 * @doc: a document instance
1683 * @attr: an attribute definition
1684 *
1685 * Try to validate a single attribute definition
1686 * basically it does the following checks as described by the
1687 * XML-1.0 recommendation:
1688 * - [ VC: Attribute Default Legal ]
1689 * - [ VC: Enumeration ]
1690 * - [ VC: ID Attribute Default ]
1691 *
1692 * The ID/IDREF uniqueness and matching are done separately
1693 *
1694 * returns 1 if valid or 0 otherwise
1695 */
1696
1697int
1698xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1699 xmlAttributePtr attr) {
1700 int ret = 1;
1701 int val;
1702 CHECK_DTD;
1703 if(attr == NULL) return(1);
1704
1705 /* Attribute Default Legal */
1706 /* Enumeration */
1707 if (attr->defaultValue != NULL) {
1708 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
1709 if (val == 0) {
1710 VERROR(ctxt->userData,
1711 "Syntax of default value for attribute %s on %s is not valid\n",
1712 attr->name, attr->elem);
1713 }
1714 ret &= val;
1715 }
1716
1717 /* ID Attribute Default */
1718 if ((attr->type == XML_ATTRIBUTE_ID)&&
1719 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
1720 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
1721 VERROR(ctxt->userData,
1722 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
1723 attr->name, attr->elem);
1724 ret = 0;
1725 }
1726
1727 /* max ID per element */
1728 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
1729 int nbId = 0;
1730
1731 /* the trick is taht we parse DtD as their own internal subset */
1732 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
1733 attr->elem);
1734 if (elem != NULL) {
1735 nbId = xmlScanIDAttributeDecl(NULL, elem);
1736 }
1737 if (nbId >= 1)
1738 VERROR(ctxt->userData,
1739 "Element %s has ID attribute defined in the external subset : %s\n",
1740 attr->elem, attr->name);
1741 }
1742
1743 return(ret);
1744}
1745
1746/**
1747 * xmlValidateElementDecl:
1748 * @ctxt: the validation context
1749 * @doc: a document instance
1750 * @elem: an element definition
1751 *
1752 * Try to validate a single element definition
1753 * basically it does the following checks as described by the
1754 * XML-1.0 recommendation:
1755 * - [ VC: One ID per Element Type ]
1756 * - [ VC: No Duplicate Types ]
1757 * - [ VC: Unique Element Type Declaration ]
1758 *
1759 * returns 1 if valid or 0 otherwise
1760 */
1761
1762int
1763xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1764 xmlElementPtr elem) {
1765 int ret = 1;
1766 xmlElementPtr tst;
1767
1768 CHECK_DTD;
1769
1770 if (elem == NULL) return(1);
1771
1772 /* No Duplicate Types */
1773 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
1774 xmlElementContentPtr cur, next;
1775 const CHAR *name;
1776
1777 cur = elem->content;
1778 while (cur != NULL) {
1779 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
1780 if (cur->c1 == NULL) break;
1781 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
1782 name = cur->c1->name;
1783 next = cur->c2;
1784 while (next != NULL) {
1785 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
1786 if (!xmlStrcmp(next->name, name)) {
1787 VERROR(ctxt->userData,
1788 "Definition of %s has duplicate references of %s\n",
1789 elem->name, name);
1790 ret = 0;
1791 }
1792 break;
1793 }
1794 if (next->c1 == NULL) break;
1795 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
1796 if (!xmlStrcmp(next->c1->name, name)) {
1797 VERROR(ctxt->userData,
1798 "Definition of %s has duplicate references of %s\n",
1799 elem->name, name);
1800 ret = 0;
1801 }
1802 next = next->c2;
1803 }
1804 }
1805 cur = cur->c2;
1806 }
1807 }
1808
1809 /* VC: Unique Element Type Declaration */
1810 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
1811 if ((tst != NULL ) && (tst != elem)) {
1812 VERROR(ctxt->userData, "Redefinition of element %s\n",
1813 elem->name);
1814 ret = 0;
1815 }
1816 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
1817 if ((tst != NULL ) && (tst != elem)) {
1818 VERROR(ctxt->userData, "Redefinition of element %s\n",
1819 elem->name);
1820 ret = 0;
1821 }
1822
1823 /* One ID per Element Type */
1824 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
1825 ret = 0;
1826 }
1827 return(ret);
1828}
1829
1830/**
1831 * xmlValidateOneAttribute:
1832 * @ctxt: the validation context
1833 * @doc: a document instance
1834 * @elem: an element instance
1835 * @attr: an attribute instance
1836 *
1837 * Try to validate a single attribute for an element
1838 * basically it * does the following checks as described by the
1839 * XML-1.0 recommendation:
1840 * - [ VC: Attribute Value Type ]
1841 * - [ VC: Fixed Attribute Default ]
1842 * - [ VC: Entity Name ]
1843 * - [ VC: Name Token ]
1844 * - [ VC: ID ]
1845 * - [ VC: IDREF ]
1846 * - [ VC: Entity Name ]
1847 * - [ VC: Notation Attributes ]
1848 *
1849 * The ID/IDREF uniqueness and matching are done separately
1850 *
1851 * returns 1 if valid or 0 otherwise
1852 */
1853
1854int
1855xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1856 xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
1857 xmlElementPtr elemDecl;
1858 xmlAttributePtr attrDecl;
1859 int val;
1860 int ret = 1;
1861
1862 CHECK_DTD;
1863 if ((elem == NULL) || (elem->name == NULL)) return(0);
1864 if ((attr == NULL) || (attr->name == NULL)) return(0);
1865
1866 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1867 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1868 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
1869
1870
1871 /* Validity Constraint: Attribute Value Type */
1872 if (attrDecl == NULL) {
1873 VERROR(ctxt->userData,
1874 "No declaration for attribute %s on element %s\n",
1875 attr->name, elem->name);
1876 return(0);
1877 }
1878 val = xmlValidateAttributeValue(attrDecl->type, value);
1879 if (val == 0) {
1880 VERROR(ctxt->userData,
1881 "Syntax of value for attribute %s on %s is not valid\n",
1882 attr->name, elem->name);
1883 ret = 0;
1884 }
1885
1886 /* Validity Constraint: Notation Attributes */
1887 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
1888 xmlEnumerationPtr tree = attrDecl->tree;
1889 xmlNotationPtr nota;
1890
1891 /* First check that the given NOTATION was declared */
1892 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
1893 if (nota == NULL)
1894 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
1895
1896 if (nota == NULL) {
1897 VERROR(ctxt->userData,
1898 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
1899 value, attr->name, elem->name);
1900 ret = 0;
1901 }
1902
1903 /* Second, verify that it's among the list */
1904 while (tree != NULL) {
1905 if (!xmlStrcmp(tree->name, value)) break;
1906 tree = tree->next;
1907 }
1908 if (tree == NULL) {
1909 VERROR(ctxt->userData,
1910 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
1911 value, attr->name, elem->name);
1912 ret = 0;
1913 }
1914 }
1915
1916 /* Validity Constraint: Enumeration */
1917 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
1918 xmlEnumerationPtr tree = attrDecl->tree;
1919 while (tree != NULL) {
1920 if (!xmlStrcmp(tree->name, value)) break;
1921 tree = tree->next;
1922 }
1923 if (tree == NULL) {
1924 VERROR(ctxt->userData,
1925 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
1926 value, attr->name, elem->name);
1927 ret = 0;
1928 }
1929 }
1930
1931 /* Fixed Attribute Default */
1932 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
1933 (xmlStrcmp(attrDecl->defaultValue, value))) {
1934 VERROR(ctxt->userData,
1935 "Value for attribute %s on %s must be \"%s\"\n",
1936 attr->name, elem->name, attrDecl->defaultValue);
1937 ret = 0;
1938 }
1939
1940 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
1941 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1942 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
1943 if (elemDecl == NULL) {
1944 /* the error has or will be reported soon in xmlValidateOneElement */
1945 return(0);
1946 }
1947 return(ret);
1948}
1949
1950int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
1951 xmlElementContentPtr cont);
1952
1953/**
1954 * xmlValidateElementTypeExpr:
1955 * @ctxt: the validation context
1956 * @child: pointer to the child list
1957 * @cont: pointer to the content declaration
1958 *
1959 * Try to validate the content of an element of type element
1960 * but don't handle the occurence factor
1961 *
1962 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
1963 * also update child value in-situ.
1964 */
1965
1966int
1967xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
1968 xmlElementContentPtr cont) {
1969 xmlNodePtr cur;
1970 int ret = 1;
1971
1972 if (cont == NULL) return(-1);
1973 while (*child != NULL) {
1974 if ((*child)->type == XML_PI_NODE) {
1975 *child = (*child)->next;
1976 continue;
1977 }
1978 if ((*child)->type == XML_COMMENT_NODE) {
1979 *child = (*child)->next;
1980 continue;
1981 }
1982 else if ((*child)->type != XML_ELEMENT_NODE) {
1983 return(-1);
1984 }
1985 break;
1986 }
1987 switch (cont->type) {
1988 case XML_ELEMENT_CONTENT_PCDATA:
1989 /* Internal error !!! */
1990 fprintf(stderr, "Internal: MIXED struct bad\n");
1991 return(-1);
1992 case XML_ELEMENT_CONTENT_ELEMENT:
1993 if (*child == NULL) return(0);
1994 ret = (!xmlStrcmp((*child)->name, cont->name));
1995 if (ret == 1)
1996 *child = (*child)->next;
1997 return(ret);
1998 case XML_ELEMENT_CONTENT_OR:
1999 cur = *child;
2000 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2001 if (ret == -1) return(-1);
2002 if (ret == 1) {
2003 return(1);
2004 }
2005 /* rollback and retry the other path */
2006 *child = cur;
2007 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2008 if (ret == -1) return(-1);
2009 if (ret == 0) {
2010 *child = cur;
2011 return(0);
2012 }
2013 return(1);
2014 case XML_ELEMENT_CONTENT_SEQ:
2015 cur = *child;
2016 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2017 if (ret == -1) return(-1);
2018 if (ret == 0) {
2019 *child = cur;
2020 return(0);
2021 }
2022 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2023 if (ret == -1) return(-1);
2024 if (ret == 0) {
2025 *child = cur;
2026 return(0);
2027 }
2028 return(1);
2029 }
2030 return(ret);
2031}
2032
2033/**
2034 * xmlValidateElementTypeElement:
2035 * @ctxt: the validation context
2036 * @child: pointer to the child list
2037 * @cont: pointer to the content declaration
2038 *
2039 * Try to validate the content of an element of type element
2040 * yeah, Yet Another Regexp Implementation, and recursive
2041 *
2042 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2043 * also update child and content values in-situ.
2044 */
2045
2046int
2047xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2048 xmlElementContentPtr cont) {
2049 xmlNodePtr cur;
2050 int ret = 1;
2051
2052 if (cont == NULL) return(-1);
2053 while (*child != NULL) {
2054 if ((*child)->type == XML_PI_NODE) {
2055 *child = (*child)->next;
2056 continue;
2057 }
2058 if ((*child)->type == XML_COMMENT_NODE) {
2059 *child = (*child)->next;
2060 continue;
2061 }
2062 else if ((*child)->type != XML_ELEMENT_NODE) {
2063 return(-1);
2064 }
2065 break;
2066 }
2067 cur = *child;
2068 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2069 if (ret == -1) return(-1);
2070 switch (cont->ocur) {
2071 case XML_ELEMENT_CONTENT_ONCE:
2072 if (ret == 1) {
2073 return(1);
2074 }
2075 *child = cur;
2076 return(0);
2077 case XML_ELEMENT_CONTENT_OPT:
2078 if (ret == 0) {
2079 *child = cur;
2080 return(1);
2081 }
2082 break;
2083 case XML_ELEMENT_CONTENT_MULT:
2084 if (ret == 0) {
2085 *child = cur;
2086 break;
2087 }
2088 /* no break on purpose */
2089 case XML_ELEMENT_CONTENT_PLUS:
2090 if (ret == 0) {
2091 *child = cur;
2092 return(0);
2093 }
2094 do {
2095 cur = *child;
2096 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2097 } while (ret == 1);
2098 if (ret == -1) return(-1);
2099 *child = cur;
2100 break;
2101 }
2102 while (*child != NULL) {
2103 if ((*child)->type == XML_PI_NODE) {
2104 *child = (*child)->next;
2105 continue;
2106 }
2107 if ((*child)->type == XML_COMMENT_NODE) {
2108 *child = (*child)->next;
2109 continue;
2110 }
2111 else if ((*child)->type != XML_ELEMENT_NODE) {
2112 return(-1);
2113 }
2114 break;
2115 }
2116 return(1);
2117}
2118
2119/**
2120 * xmlSprintfElementChilds:
2121 * @buf: an output buffer
2122 * @content: An element
2123 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2124 *
2125 * This will dump the list of childs to the buffer
2126 * Intended just for the debug routine
2127 */
2128void
2129xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2130 xmlNodePtr cur;
2131
2132 if (node == NULL) return;
2133 if (glob) strcat(buf, "(");
2134 cur = node->childs;
2135 while (cur != NULL) {
2136 switch (cur->type) {
2137 case XML_ELEMENT_NODE:
2138 strcat(buf, cur->name);
2139 if (cur->next != NULL)
2140 strcat(buf, " ");
2141 break;
2142 case XML_TEXT_NODE:
2143 case XML_CDATA_SECTION_NODE:
2144 case XML_ENTITY_REF_NODE:
2145 strcat(buf, "CDATA");
2146 if (cur->next != NULL)
2147 strcat(buf, " ");
2148 break;
2149 case XML_ATTRIBUTE_NODE:
2150 case XML_DOCUMENT_NODE:
2151 case XML_DOCUMENT_TYPE_NODE:
2152 case XML_DOCUMENT_FRAG_NODE:
2153 case XML_NOTATION_NODE:
2154 strcat(buf, "???");
2155 if (cur->next != NULL)
2156 strcat(buf, " ");
2157 break;
2158 case XML_ENTITY_NODE:
2159 case XML_PI_NODE:
2160 case XML_COMMENT_NODE:
2161 break;
2162 }
2163 cur = cur->next;
2164 }
2165 if (glob) strcat(buf, ")");
2166}
2167
2168
2169/**
2170 * xmlValidateOneElement:
2171 * @ctxt: the validation context
2172 * @doc: a document instance
2173 * @elem: an element instance
2174 *
2175 * Try to validate a single element and it's attributes,
2176 * basically it does the following checks as described by the
2177 * XML-1.0 recommendation:
2178 * - [ VC: Element Valid ]
2179 * - [ VC: Required Attribute ]
2180 * Then call xmlValidateOneAttribute() for each attribute present.
2181 *
2182 * The ID/IDREF checkings are done separately
2183 *
2184 * returns 1 if valid or 0 otherwise
2185 */
2186
2187int
2188xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2189 xmlNodePtr elem) {
2190 xmlElementPtr elemDecl;
2191 xmlElementContentPtr cont;
2192 xmlNodePtr child;
2193 int ret = 1;
2194 const CHAR *name;
2195
2196 CHECK_DTD;
2197
2198 if ((elem == NULL) || (elem->name == NULL)) return(0);
2199
2200 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2201 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2202 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2203 if (elemDecl == NULL) {
2204 VERROR(ctxt->userData, "No declaration for element %s\n",
2205 elem->name);
2206 return(0);
2207 }
2208
2209 /* Check taht the element content matches the definition */
2210 switch (elemDecl->type) {
2211 case XML_ELEMENT_TYPE_EMPTY:
2212 if (elem->childs != NULL) {
2213 VERROR(ctxt->userData,
2214 "Element %s was declared EMPTY this one has content\n",
2215 elem->name);
2216 ret = 0;
2217 }
2218 break;
2219 case XML_ELEMENT_TYPE_ANY:
2220 /* I don't think anything is required then */
2221 break;
2222 case XML_ELEMENT_TYPE_MIXED:
2223 /* Hum, this start to get messy */
2224 child = elem->childs;
2225 while (child != NULL) {
2226 if (child->type == XML_ELEMENT_NODE) {
2227 name = child->name;
2228 cont = elemDecl->content;
2229 while (cont != NULL) {
2230 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2231 if (!xmlStrcmp(cont->name, name)) break;
2232 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2233 (cont->c1 != NULL) &&
2234 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2235 if (!xmlStrcmp(cont->c1->name, name)) break;
2236 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2237 (cont->c1 == NULL) ||
2238 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2239 /* Internal error !!! */
2240 fprintf(stderr, "Internal: MIXED struct bad\n");
2241 break;
2242 }
2243 cont = cont->c2;
2244 }
2245 if (cont == NULL) {
2246 VERROR(ctxt->userData,
2247 "Element %s is not declared in %s list of possible childs\n",
2248 name, elem->name);
2249 ret = 0;
2250 }
2251 }
2252 child = child->next;
2253 }
2254 break;
2255 case XML_ELEMENT_TYPE_ELEMENT:
2256 child = elem->childs;
2257 cont = elemDecl->content;
2258 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2259 if ((ret == 0) || (child != NULL)) {
2260 char expr[1000];
2261 char list[2000];
2262
2263 expr[0] = 0;
2264 xmlSprintfElementContent(expr, cont, 1);
2265 list[0] = 0;
2266 xmlSprintfElementChilds(list, elem, 1);
2267
2268 VERROR(ctxt->userData,
2269 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2270 elem->name, expr, list);
2271 ret = 0;
2272 }
2273 break;
2274 }
2275
2276 return(ret);
2277}
2278
2279/**
2280 * xmlValidateRoot:
2281 * @ctxt: the validation context
2282 * @doc: a document instance
2283 *
2284 * Try to validate a the root element
2285 * basically it does the following check as described by the
2286 * XML-1.0 recommendation:
2287 * - [ VC: Root Element Type ]
2288 * it doesn't try to recurse or apply other check to the element
2289 *
2290 * returns 1 if valid or 0 otherwise
2291 */
2292
2293int
2294xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2295 if (doc == NULL) return(0);
2296
2297 if ((doc->intSubset == NULL) ||
2298 (doc->intSubset->name == NULL)) {
2299 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2300 return(0);
2301 }
2302 if ((doc->root == NULL) || (doc->root->name == NULL)) {
2303 VERROR(ctxt->userData, "Not valid: no root element\n");
2304 return(0);
2305 }
2306 if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2307 VERROR(ctxt->userData,
2308 "Not valid: root and DtD name do not match %s and %s\n",
2309 doc->root->name, doc->intSubset->name);
2310 return(0);
2311 }
2312 return(1);
2313}
2314
2315
2316/**
2317 * xmlValidateElement:
2318 * @ctxt: the validation context
2319 * @doc: a document instance
2320 * @elem: an element instance
2321 *
2322 * Try to validate the subtree under an element
2323 *
2324 * returns 1 if valid or 0 otherwise
2325 */
2326
2327int
2328xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
2329 CHECK_DTD;
2330
2331 return(1);
2332}
2333
2334/**
2335 * xmlValidateDtd:
2336 * @ctxt: the validation context
2337 * @doc: a document instance
2338 * @dtd: a dtd instance
2339 *
2340 * Try to validate the dtd instance
2341 *
2342 * basically it does check all the definitions in the DtD.
2343 *
2344 * returns 1 if valid or 0 otherwise
2345 */
2346
2347int
2348xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
2349 return(1);
2350}
2351
2352/**
2353 * xmlValidateDocument:
2354 * @ctxt: the validation context
2355 * @doc: a document instance
2356 *
2357 * Try to validate the document instance
2358 *
2359 * basically it does the all the checks described by the
2360 * i.e. validates the internal and external subset (if present)
2361 * and validate the document tree.
2362 *
2363 * returns 1 if valid or 0 otherwise
2364 */
2365
2366int
2367xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2368 if (!xmlValidateRoot(ctxt, doc)) return(0);
2369
2370 return(1);
2371}
2372