blob: 3a107dbe12b057eb1392e5d9e3664295c6a97159 [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>
Daniel Veillard6454aec1999-09-02 22:04:43 +000013#include "xmlmemory.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000014#include "valid.h"
15#include "parser.h"
Daniel Veillardb05deb71999-08-10 19:04:08 +000016#include "parserInternals.h"
17
18#define VERROR \
19 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
20
21#define VWARNING \
22 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
23
24#define CHECK_DTD \
25 if (doc == NULL) return(0); \
26 else if (doc->intSubset == NULL) return(0)
27
28xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name);
29xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000030
31/****************************************************************
32 * *
33 * Util functions for data allocation/deallocation *
34 * *
35 ****************************************************************/
36
37/**
38 * xmlNewElementContent:
39 * @name: the subelement name or NULL
40 * @type: the type of element content decl
41 *
42 * Allocate an element content structure.
43 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000044 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000045 */
46xmlElementContentPtr
Daniel Veillardc26087b1999-08-30 11:23:51 +000047xmlNewElementContent(CHAR *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000048 xmlElementContentPtr ret;
49
50 switch(type) {
51 case XML_ELEMENT_CONTENT_ELEMENT:
52 if (name == NULL) {
53 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
54 }
55 break;
56 case XML_ELEMENT_CONTENT_PCDATA:
57 case XML_ELEMENT_CONTENT_SEQ:
58 case XML_ELEMENT_CONTENT_OR:
59 if (name != NULL) {
60 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
61 }
62 break;
63 default:
64 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
65 exit(1);
66 }
Daniel Veillard6454aec1999-09-02 22:04:43 +000067 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000068 if (ret == NULL) {
69 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
70 return(NULL);
71 }
72 ret->type = type;
73 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +000074 if (name != NULL)
75 ret->name = xmlStrdup(name);
76 else
77 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +000078 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000079 return(ret);
80}
81
82/**
Daniel Veillard3b9def11999-01-31 22:15:06 +000083 * xmlCopyElementContent:
84 * @content: An element content pointer.
85 *
86 * Build a copy of an element content description.
87 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000088 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +000089 */
90xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +000091xmlCopyElementContent(xmlElementContentPtr cur) {
92 xmlElementContentPtr ret;
93
94 if (cur == NULL) return(NULL);
95 ret = xmlNewElementContent((CHAR *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +000096 if (ret == NULL) {
97 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
98 return(NULL);
99 }
100 ret->ocur = cur->ocur;
101 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
102 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000103 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000104}
105
106/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000107 * xmlFreeElementContent:
108 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000109 *
110 * Free an element content structure. This is a recursive call !
111 */
112void
113xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000114 if (cur == NULL) return;
115 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
116 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000117 if (cur->name != NULL) xmlFree((CHAR *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000118 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000119 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000120}
121
Daniel Veillard1899e851999-02-01 12:18:54 +0000122/**
123 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000124 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000125 * @content: An element table
126 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
127 *
128 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000129 */
130void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000131xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000132 if (content == NULL) return;
133
Daniel Veillard5099ae81999-04-21 20:12:07 +0000134 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000135 switch (content->type) {
136 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000137 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000138 break;
139 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000140 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000141 break;
142 case XML_ELEMENT_CONTENT_SEQ:
143 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
144 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000145 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000146 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000147 xmlDumpElementContent(buf, content->c1, 0);
148 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000149 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000150 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000151 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000152 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000153 break;
154 case XML_ELEMENT_CONTENT_OR:
155 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
156 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000157 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000158 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000159 xmlDumpElementContent(buf, content->c1, 0);
160 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000161 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000162 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000163 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000164 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000165 break;
166 default:
167 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
168 content->type);
169 }
170 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000171 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000172 switch (content->ocur) {
173 case XML_ELEMENT_CONTENT_ONCE:
174 break;
175 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000176 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000177 break;
178 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000179 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000180 break;
181 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000182 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000183 break;
184 }
185}
186
Daniel Veillardb05deb71999-08-10 19:04:08 +0000187/**
188 * xmlSprintfElementContent:
189 * @buf: an output buffer
190 * @content: An element table
191 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
192 *
193 * This will dump the content of the element content definition
194 * Intended just for the debug routine
195 */
196void
197xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
198 if (content == NULL) return;
199 if (glob) strcat(buf, "(");
200 switch (content->type) {
201 case XML_ELEMENT_CONTENT_PCDATA:
202 strcat(buf, "#PCDATA");
203 break;
204 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000205 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000206 break;
207 case XML_ELEMENT_CONTENT_SEQ:
208 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
209 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
210 xmlSprintfElementContent(buf, content->c1, 1);
211 else
212 xmlSprintfElementContent(buf, content->c1, 0);
213 strcat(buf, " , ");
214 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
215 xmlSprintfElementContent(buf, content->c2, 1);
216 else
217 xmlSprintfElementContent(buf, content->c2, 0);
218 break;
219 case XML_ELEMENT_CONTENT_OR:
220 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
221 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
222 xmlSprintfElementContent(buf, content->c1, 1);
223 else
224 xmlSprintfElementContent(buf, content->c1, 0);
225 strcat(buf, " | ");
226 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
227 xmlSprintfElementContent(buf, content->c2, 1);
228 else
229 xmlSprintfElementContent(buf, content->c2, 0);
230 break;
231 }
232 if (glob)
233 strcat(buf, ")");
234 switch (content->ocur) {
235 case XML_ELEMENT_CONTENT_ONCE:
236 break;
237 case XML_ELEMENT_CONTENT_OPT:
238 strcat(buf, "?");
239 break;
240 case XML_ELEMENT_CONTENT_MULT:
241 strcat(buf, "*");
242 break;
243 case XML_ELEMENT_CONTENT_PLUS:
244 strcat(buf, "+");
245 break;
246 }
247}
248
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000249/****************************************************************
250 * *
251 * Registration of DTD declarations *
252 * *
253 ****************************************************************/
254
Daniel Veillard3b9def11999-01-31 22:15:06 +0000255/**
256 * xmlCreateElementTable:
257 *
258 * create and initialize an empty element hash table.
259 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000260 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000261 */
262xmlElementTablePtr
263xmlCreateElementTable(void) {
264 xmlElementTablePtr ret;
265
266 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000267 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000268 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000269 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000270 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000271 return(NULL);
272 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000273 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000274 ret->nb_elements = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000275 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000276 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000277 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000278 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000279 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000280 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000281 return(NULL);
282 }
283 return(ret);
284}
285
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000286
287/**
288 * xmlAddElementDecl:
Daniel Veillard1e346af1999-02-22 10:33:01 +0000289 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000290 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000291 * @type: the element type
292 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000293 *
294 * Register a new element declaration
295 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000296 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000297 */
298xmlElementPtr
Daniel Veillardb05deb71999-08-10 19:04:08 +0000299xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
Daniel Veillardc26087b1999-08-30 11:23:51 +0000300 xmlElementContentType type, xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000301 xmlElementPtr ret, cur;
302 xmlElementTablePtr table;
303 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000304
305 if (dtd == NULL) {
306 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
307 return(NULL);
308 }
309 if (name == NULL) {
310 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
311 return(NULL);
312 }
313 switch (type) {
314 case XML_ELEMENT_TYPE_EMPTY:
315 if (content != NULL) {
316 fprintf(stderr,
317 "xmlAddElementDecl: content != NULL for EMPTY\n");
318 return(NULL);
319 }
320 break;
321 case XML_ELEMENT_TYPE_ANY:
322 if (content != NULL) {
323 fprintf(stderr,
324 "xmlAddElementDecl: content != NULL for ANY\n");
325 return(NULL);
326 }
327 break;
328 case XML_ELEMENT_TYPE_MIXED:
329 if (content == NULL) {
330 fprintf(stderr,
331 "xmlAddElementDecl: content == NULL for MIXED\n");
332 return(NULL);
333 }
334 break;
335 case XML_ELEMENT_TYPE_ELEMENT:
336 if (content == NULL) {
337 fprintf(stderr,
338 "xmlAddElementDecl: content == NULL for ELEMENT\n");
339 return(NULL);
340 }
341 break;
342 default:
343 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
344 return(NULL);
345 }
346
347 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000348 * Create the Element table if needed.
349 */
350 table = dtd->elements;
351 if (table == NULL)
352 table = dtd->elements = xmlCreateElementTable();
353 if (table == NULL) {
354 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
355 return(NULL);
356 }
357
358 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000359 * Validity Check:
360 * Search the DTD for previous declarations of the ELEMENT
361 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000362 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000363 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000364 if (!xmlStrcmp(cur->name, name)) {
365 /*
366 * The element is already defined in this Dtd.
367 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000368 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000369 return(NULL);
370 }
371 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000372
373 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000374 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000375 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000376 if (table->nb_elements >= table->max_elements) {
377 /*
378 * need more elements.
379 */
380 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000381 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000382 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000383 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000384 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
385 return(NULL);
386 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000387 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000388 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000389 if (ret == NULL) {
390 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
391 return(NULL);
392 }
393 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000394
395 /*
396 * fill the structure.
397 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000398 ret->type = type;
399 ret->name = xmlStrdup(name);
Daniel Veillard14fff061999-06-22 21:49:07 +0000400 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000401 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000402 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000403
404 return(ret);
405}
406
Daniel Veillard3b9def11999-01-31 22:15:06 +0000407/**
408 * xmlFreeElement:
409 * @elem: An element
410 *
411 * Deallocate the memory used by an element definition
412 */
413void
414xmlFreeElement(xmlElementPtr elem) {
415 if (elem == NULL) return;
416 xmlFreeElementContent(elem->content);
417 if (elem->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000418 xmlFree((CHAR *) elem->name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000419 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000420 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000421}
422
423/**
424 * xmlFreeElementTable:
425 * @table: An element table
426 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000427 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000428 */
429void
430xmlFreeElementTable(xmlElementTablePtr table) {
431 int i;
432
433 if (table == NULL) return;
434
435 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000436 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000437 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000438 xmlFree(table->table);
439 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000440}
441
442/**
443 * xmlCopyElementTable:
444 * @table: An element table
445 *
446 * Build a copy of an element table.
447 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000448 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000449 */
450xmlElementTablePtr
451xmlCopyElementTable(xmlElementTablePtr table) {
452 xmlElementTablePtr ret;
453 xmlElementPtr cur, ent;
454 int i;
455
Daniel Veillard6454aec1999-09-02 22:04:43 +0000456 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000457 if (ret == NULL) {
458 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
459 return(NULL);
460 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000461 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000462 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000463 if (ret->table == NULL) {
464 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000465 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000466 return(NULL);
467 }
468 ret->max_elements = table->max_elements;
469 ret->nb_elements = table->nb_elements;
470 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000471 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000472 if (cur == NULL) {
473 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000474 xmlFree(ret);
475 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000476 return(NULL);
477 }
478 ret->table[i] = cur;
479 ent = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000480 cur->type = ent->type;
481 if (ent->name != NULL)
482 cur->name = xmlStrdup(ent->name);
483 else
484 cur->name = NULL;
485 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000486 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000487 }
488 return(ret);
489}
490
491/**
492 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000493 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000494 * @table: An element table
495 *
496 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000497 */
498void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000499xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000500 int i;
501 xmlElementPtr cur;
502
503 if (table == NULL) return;
504
505 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000506 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000507 switch (cur->type) {
508 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000509 xmlBufferWriteChar(buf, "<!ELEMENT ");
510 xmlBufferWriteCHAR(buf, cur->name);
511 xmlBufferWriteChar(buf, " EMPTY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000512 break;
513 case XML_ELEMENT_TYPE_ANY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000514 xmlBufferWriteChar(buf, "<!ELEMENT ");
515 xmlBufferWriteCHAR(buf, cur->name);
516 xmlBufferWriteChar(buf, " ANY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000517 break;
518 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000519 xmlBufferWriteChar(buf, "<!ELEMENT ");
520 xmlBufferWriteCHAR(buf, cur->name);
521 xmlBufferWriteChar(buf, " ");
522 xmlDumpElementContent(buf, cur->content, 1);
523 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000524 break;
525 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000526 xmlBufferWriteChar(buf, "<!ELEMENT ");
527 xmlBufferWriteCHAR(buf, cur->name);
528 xmlBufferWriteChar(buf, " ");
529 xmlDumpElementContent(buf, cur->content, 1);
530 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000531 break;
532 default:
533 fprintf(stderr,
534 "xmlDumpElementTable: internal: unknown type %d\n",
535 cur->type);
536 }
537 }
538}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000539
540/**
541 * xmlCreateEnumeration:
542 * @name: the enumeration name or NULL
543 *
544 * create and initialize an enumeration attribute node.
545 *
546 * Returns the xmlEnumerationPtr just created or NULL in case
547 * of error.
548 */
549xmlEnumerationPtr
550xmlCreateEnumeration(CHAR *name) {
551 xmlEnumerationPtr ret;
552
Daniel Veillard6454aec1999-09-02 22:04:43 +0000553 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000554 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000555 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000556 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000557 return(NULL);
558 }
559
560 if (name != NULL)
561 ret->name = xmlStrdup(name);
562 else
563 ret->name = NULL;
564 ret->next = NULL;
565 return(ret);
566}
567
568/**
569 * xmlFreeEnumeration:
570 * @cur: the tree to free.
571 *
572 * free an enumeration attribute node (recursive).
573 */
574void
575xmlFreeEnumeration(xmlEnumerationPtr cur) {
576 if (cur == NULL) return;
577
578 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
579
Daniel Veillard6454aec1999-09-02 22:04:43 +0000580 if (cur->name != NULL) xmlFree((CHAR *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000581 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000582 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000583}
584
585/**
586 * xmlCopyEnumeration:
587 * @cur: the tree to copy.
588 *
589 * Copy an enumeration attribute node (recursive).
590 *
591 * Returns the xmlEnumerationPtr just created or NULL in case
592 * of error.
593 */
594xmlEnumerationPtr
595xmlCopyEnumeration(xmlEnumerationPtr cur) {
596 xmlEnumerationPtr ret;
597
598 if (cur == NULL) return(NULL);
599 ret = xmlCreateEnumeration((CHAR *) cur->name);
600
601 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
602 else ret->next = NULL;
603
604 return(ret);
605}
606
607/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000608 * xmlDumpEnumeration:
609 * @buf: the XML buffer output
610 * @enum: An enumeration
611 *
612 * This will dump the content of the enumeration
613 */
614void
615xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
616 if (cur == NULL) return;
617
618 xmlBufferWriteCHAR(buf, cur->name);
619 if (cur->next == NULL)
620 xmlBufferWriteChar(buf, ")");
621 else {
622 xmlBufferWriteChar(buf, " | ");
623 xmlDumpEnumeration(buf, cur->next);
624 }
625}
626
627/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000628 * xmlCreateAttributeTable:
629 *
630 * create and initialize an empty attribute hash table.
631 *
632 * Returns the xmlAttributeTablePtr just created or NULL in case
633 * of error.
634 */
635xmlAttributeTablePtr
636xmlCreateAttributeTable(void) {
637 xmlAttributeTablePtr ret;
638
639 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000640 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000641 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000642 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000643 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000644 return(NULL);
645 }
646 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
647 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000648 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000649 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000650 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000651 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000652 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000653 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000654 return(NULL);
655 }
656 return(ret);
657}
658
Daniel Veillardb05deb71999-08-10 19:04:08 +0000659/**
660 * xmlScanAttributeDecl:
661 * @dtd: pointer to the DTD
662 * @elem: the element name
663 *
664 * When inserting a new element scan the DtD for existing attributes
665 * for taht element and initialize the Attribute chain
666 *
667 * Returns the pointer to the first attribute decl in the chain,
668 * possibly NULL.
669 */
670xmlAttributePtr
671xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem) {
672 xmlAttributePtr ret = NULL;
673 xmlAttributeTablePtr table;
674 int i;
675
676 if (dtd == NULL) {
677 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
678 return(NULL);
679 }
680 if (elem == NULL) {
681 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
682 return(NULL);
683 }
684 table = dtd->attributes;
685 if (table == NULL)
686 return(NULL);
687
688 for (i = 0;i < table->nb_attributes;i++) {
689 if (!xmlStrcmp(table->table[i]->elem, elem)) {
690 table->table[i]->next = ret;
691 ret = table->table[i];
692 }
693 }
694 return(ret);
695}
696
697/**
698 * xmlScanIDAttributeDecl:
699 * @ctxt: the validation context
700 * @elem: the element name
701 *
702 * Veryfy that the element don't have too many ID attributes
703 * declared.
704 *
705 * Returns the number of ID attributes found.
706 */
707int
708xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
709 xmlAttributePtr cur;
710 int ret = 0;
711
712 if (elem == NULL) return(0);
713 cur = elem->attributes;
714 while (cur != NULL) {
715 if (cur->type == XML_ATTRIBUTE_ID) {
716 ret ++;
717 if (ret > 1)
718 VERROR(ctxt->userData,
719 "Element %s has too may ID attributes defined : %s\n",
720 elem->name, cur->name);
721 }
722 cur = cur->next;
723 }
724 return(ret);
725}
726
Daniel Veillard1e346af1999-02-22 10:33:01 +0000727
728/**
729 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000730 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000731 * @dtd: pointer to the DTD
732 * @elem: the element name
733 * @name: the attribute name
734 * @type: the attribute type
735 * @def: the attribute default type
736 * @defaultValue: the attribute default value
737 * @tree: if it's an enumeration, the associated list
738 *
739 * Register a new attribute declaration
740 *
741 * Returns NULL if not, othervise the entity
742 */
743xmlAttributePtr
Daniel Veillardb05deb71999-08-10 19:04:08 +0000744xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *elem,
Daniel Veillardc26087b1999-08-30 11:23:51 +0000745 const CHAR *name, xmlAttributeType type,
746 xmlAttributeDefault def, const CHAR *defaultValue,
747 xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000748 xmlAttributePtr ret, cur;
749 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000750 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000751 int i;
752
753 if (dtd == NULL) {
754 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
755 return(NULL);
756 }
757 if (name == NULL) {
758 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
759 return(NULL);
760 }
761 if (elem == NULL) {
762 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
763 return(NULL);
764 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000765 /*
766 * Check the type and possibly the default value.
767 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000768 switch (type) {
769 case XML_ATTRIBUTE_CDATA:
770 break;
771 case XML_ATTRIBUTE_ID:
772 break;
773 case XML_ATTRIBUTE_IDREF:
774 break;
775 case XML_ATTRIBUTE_IDREFS:
776 break;
777 case XML_ATTRIBUTE_ENTITY:
778 break;
779 case XML_ATTRIBUTE_ENTITIES:
780 break;
781 case XML_ATTRIBUTE_NMTOKEN:
782 break;
783 case XML_ATTRIBUTE_NMTOKENS:
784 break;
785 case XML_ATTRIBUTE_ENUMERATION:
786 break;
787 case XML_ATTRIBUTE_NOTATION:
788 break;
789 default:
790 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
791 return(NULL);
792 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000793 if ((defaultValue != NULL) &&
794 (!xmlValidateAttributeValue(type, defaultValue))) {
795 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
796 elem, name, defaultValue);
797 defaultValue = NULL;
798 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000799
800 /*
801 * Create the Attribute table if needed.
802 */
803 table = dtd->attributes;
804 if (table == NULL)
805 table = dtd->attributes = xmlCreateAttributeTable();
806 if (table == NULL) {
807 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
808 return(NULL);
809 }
810
811 /*
812 * Validity Check:
813 * Search the DTD for previous declarations of the ATTLIST
814 */
815 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000816 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +0000817 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
818 /*
819 * The attribute is already defined in this Dtd.
820 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000821 VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
822 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000823 }
824 }
825
826 /*
827 * Grow the table, if needed.
828 */
829 if (table->nb_attributes >= table->max_attributes) {
830 /*
831 * need more attributes.
832 */
833 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000834 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000835 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000836 sizeof(xmlAttributePtr));
837 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000838 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
839 return(NULL);
840 }
841 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000842 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000843 if (ret == NULL) {
844 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
845 return(NULL);
846 }
847 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000848
849 /*
850 * fill the structure.
851 */
852 ret->type = type;
853 ret->name = xmlStrdup(name);
854 ret->elem = xmlStrdup(elem);
855 ret->def = def;
856 ret->tree = tree;
857 if (defaultValue != NULL)
858 ret->defaultValue = xmlStrdup(defaultValue);
859 else
860 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000861 elemDef = xmlGetDtdElementDesc(dtd, elem);
862 if (elemDef != NULL) {
863 if ((type == XML_ATTRIBUTE_ID) &&
864 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
865 VERROR(ctxt->userData,
866 "Element %s has too may ID attributes defined : %s\n",
867 elem, name);
868 ret->next = elemDef->attributes;
869 elemDef->attributes = ret;
870 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000871 table->nb_attributes++;
872
873 return(ret);
874}
875
876/**
877 * xmlFreeAttribute:
878 * @elem: An attribute
879 *
880 * Deallocate the memory used by an attribute definition
881 */
882void
883xmlFreeAttribute(xmlAttributePtr attr) {
884 if (attr == NULL) return;
885 if (attr->tree != NULL)
886 xmlFreeEnumeration(attr->tree);
887 if (attr->elem != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000888 xmlFree((CHAR *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000889 if (attr->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000890 xmlFree((CHAR *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000891 if (attr->defaultValue != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000892 xmlFree((CHAR *) attr->defaultValue);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000893 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000894 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000895}
896
897/**
898 * xmlFreeAttributeTable:
899 * @table: An attribute table
900 *
901 * Deallocate the memory used by an entities hash table.
902 */
903void
904xmlFreeAttributeTable(xmlAttributeTablePtr table) {
905 int i;
906
907 if (table == NULL) return;
908
909 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000910 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000911 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000912 xmlFree(table->table);
913 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000914}
915
916/**
917 * xmlCopyAttributeTable:
918 * @table: An attribute table
919 *
920 * Build a copy of an attribute table.
921 *
922 * Returns the new xmlAttributeTablePtr or NULL in case of error.
923 */
924xmlAttributeTablePtr
925xmlCopyAttributeTable(xmlAttributeTablePtr table) {
926 xmlAttributeTablePtr ret;
927 xmlAttributePtr cur, attr;
928 int i;
929
Daniel Veillard6454aec1999-09-02 22:04:43 +0000930 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000931 if (ret == NULL) {
932 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
933 return(NULL);
934 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000935 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000936 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000937 if (ret->table == NULL) {
938 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000939 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000940 return(NULL);
941 }
942 ret->max_attributes = table->max_attributes;
943 ret->nb_attributes = table->nb_attributes;
944 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000945 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +0000946 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000947 if (cur == NULL) {
948 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000949 xmlFree(ret);
950 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000951 return(NULL);
952 }
953 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000954 cur->type = attr->type;
955 cur->def = attr->def;
956 cur->tree = xmlCopyEnumeration(attr->tree);
957 if (attr->elem != NULL)
958 cur->elem = xmlStrdup(attr->elem);
959 else
960 cur->elem = NULL;
961 if (attr->name != NULL)
962 cur->name = xmlStrdup(attr->name);
963 else
964 cur->name = NULL;
965 if (attr->defaultValue != NULL)
966 cur->defaultValue = xmlStrdup(attr->defaultValue);
967 else
968 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000969 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000970 }
971 return(ret);
972}
973
974/**
975 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000976 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +0000977 * @table: An attribute table
978 *
979 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +0000980 */
981void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000982xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000983 int i;
984 xmlAttributePtr cur;
985
986 if (table == NULL) return;
987
988 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000989 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +0000990 xmlBufferWriteChar(buf, "<!ATTLIST ");
991 xmlBufferWriteCHAR(buf, cur->elem);
992 xmlBufferWriteChar(buf, " ");
993 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000994 switch (cur->type) {
995 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000996 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +0000997 break;
998 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000999 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001000 break;
1001 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001002 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001003 break;
1004 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001005 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001006 break;
1007 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001008 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001009 break;
1010 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001011 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001012 break;
1013 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001014 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001015 break;
1016 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001017 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001018 break;
1019 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001020 xmlBufferWriteChar(buf, " (");
1021 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001022 break;
1023 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001024 xmlBufferWriteChar(buf, " NOTATION (");
1025 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001026 break;
1027 default:
1028 fprintf(stderr,
1029 "xmlDumpAttributeTable: internal: unknown type %d\n",
1030 cur->type);
1031 }
1032 switch (cur->def) {
1033 case XML_ATTRIBUTE_NONE:
1034 break;
1035 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001036 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001037 break;
1038 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001039 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001040 break;
1041 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001042 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001043 break;
1044 default:
1045 fprintf(stderr,
1046 "xmlDumpAttributeTable: internal: unknown default %d\n",
1047 cur->def);
1048 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001049 if (cur->defaultValue != NULL) {
1050 xmlBufferWriteChar(buf, " ");
1051 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1052 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001053 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001054 }
1055}
1056
1057/************************************************************************
1058 * *
1059 * NOTATIONs *
1060 * *
1061 ************************************************************************/
1062/**
1063 * xmlCreateNotationTable:
1064 *
1065 * create and initialize an empty notation hash table.
1066 *
1067 * Returns the xmlNotationTablePtr just created or NULL in case
1068 * of error.
1069 */
1070xmlNotationTablePtr
1071xmlCreateNotationTable(void) {
1072 xmlNotationTablePtr ret;
1073
1074 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001075 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001076 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001077 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001078 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001079 return(NULL);
1080 }
1081 ret->max_notations = XML_MIN_NOTATION_TABLE;
1082 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001083 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001084 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001085 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001086 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001087 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001088 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001089 return(NULL);
1090 }
1091 return(ret);
1092}
1093
1094
1095/**
1096 * xmlAddNotationDecl:
1097 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001098 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001099 * @name: the entity name
1100 * @PublicID: the public identifier or NULL
1101 * @SystemID: the system identifier or NULL
1102 *
1103 * Register a new notation declaration
1104 *
1105 * Returns NULL if not, othervise the entity
1106 */
1107xmlNotationPtr
Daniel Veillardb05deb71999-08-10 19:04:08 +00001108xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
1109 const CHAR *PublicID, const CHAR *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001110 xmlNotationPtr ret, cur;
1111 xmlNotationTablePtr table;
1112 int i;
1113
1114 if (dtd == NULL) {
1115 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1116 return(NULL);
1117 }
1118 if (name == NULL) {
1119 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1120 return(NULL);
1121 }
1122 if ((PublicID == NULL) && (SystemID == NULL)) {
1123 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1124 }
1125
1126 /*
1127 * Create the Notation table if needed.
1128 */
1129 table = dtd->notations;
1130 if (table == NULL)
1131 table = dtd->notations = xmlCreateNotationTable();
1132 if (table == NULL) {
1133 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1134 return(NULL);
1135 }
1136
1137 /*
1138 * Validity Check:
1139 * Search the DTD for previous declarations of the ATTLIST
1140 */
1141 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001142 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001143 if (!xmlStrcmp(cur->name, name)) {
1144 /*
1145 * The notation is already defined in this Dtd.
1146 */
1147 fprintf(stderr,
1148 "xmlAddNotationDecl: %s already defined\n", name);
1149 }
1150 }
1151
1152 /*
1153 * Grow the table, if needed.
1154 */
1155 if (table->nb_notations >= table->max_notations) {
1156 /*
1157 * need more notations.
1158 */
1159 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001160 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001161 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001162 sizeof(xmlNotationPtr));
1163 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001164 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1165 return(NULL);
1166 }
1167 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001168 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001169 if (ret == NULL) {
1170 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1171 return(NULL);
1172 }
1173 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001174
1175 /*
1176 * fill the structure.
1177 */
1178 ret->name = xmlStrdup(name);
1179 if (SystemID != NULL)
1180 ret->SystemID = xmlStrdup(SystemID);
1181 else
1182 ret->SystemID = NULL;
1183 if (PublicID != NULL)
1184 ret->PublicID = xmlStrdup(PublicID);
1185 else
1186 ret->PublicID = NULL;
1187 table->nb_notations++;
1188
1189 return(ret);
1190}
1191
1192/**
1193 * xmlFreeNotation:
1194 * @not: A notation
1195 *
1196 * Deallocate the memory used by an notation definition
1197 */
1198void
1199xmlFreeNotation(xmlNotationPtr nota) {
1200 if (nota == NULL) return;
1201 if (nota->name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001202 xmlFree((CHAR *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001203 if (nota->PublicID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001204 xmlFree((CHAR *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001205 if (nota->SystemID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001206 xmlFree((CHAR *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001207 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001208 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001209}
1210
1211/**
1212 * xmlFreeNotationTable:
1213 * @table: An notation table
1214 *
1215 * Deallocate the memory used by an entities hash table.
1216 */
1217void
1218xmlFreeNotationTable(xmlNotationTablePtr table) {
1219 int i;
1220
1221 if (table == NULL) return;
1222
1223 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001224 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001225 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001226 xmlFree(table->table);
1227 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001228}
1229
1230/**
1231 * xmlCopyNotationTable:
1232 * @table: A notation table
1233 *
1234 * Build a copy of a notation table.
1235 *
1236 * Returns the new xmlNotationTablePtr or NULL in case of error.
1237 */
1238xmlNotationTablePtr
1239xmlCopyNotationTable(xmlNotationTablePtr table) {
1240 xmlNotationTablePtr ret;
1241 xmlNotationPtr cur, nota;
1242 int i;
1243
Daniel Veillard6454aec1999-09-02 22:04:43 +00001244 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001245 if (ret == NULL) {
1246 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1247 return(NULL);
1248 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001249 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001250 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001251 if (ret->table == NULL) {
1252 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001253 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001254 return(NULL);
1255 }
1256 ret->max_notations = table->max_notations;
1257 ret->nb_notations = table->nb_notations;
1258 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001259 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001260 if (cur == NULL) {
1261 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001262 xmlFree(ret);
1263 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001264 return(NULL);
1265 }
1266 ret->table[i] = cur;
1267 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001268 if (nota->name != NULL)
1269 cur->name = xmlStrdup(nota->name);
1270 else
1271 cur->name = NULL;
1272 if (nota->PublicID != NULL)
1273 cur->PublicID = xmlStrdup(nota->PublicID);
1274 else
1275 cur->PublicID = NULL;
1276 if (nota->SystemID != NULL)
1277 cur->SystemID = xmlStrdup(nota->SystemID);
1278 else
1279 cur->SystemID = NULL;
1280 }
1281 return(ret);
1282}
1283
1284/**
1285 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001286 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001287 * @table: A notation table
1288 *
1289 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001290 */
1291void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001292xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001293 int i;
1294 xmlNotationPtr cur;
1295
1296 if (table == NULL) return;
1297
1298 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001299 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001300 xmlBufferWriteChar(buf, "<!NOTATION ");
1301 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001302 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001303 xmlBufferWriteChar(buf, " PUBLIC ");
1304 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001305 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001306 xmlBufferWriteChar(buf, " ");
1307 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001308 }
1309 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001310 xmlBufferWriteChar(buf, " SYSTEM ");
1311 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001312 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001313 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001314 }
1315}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001316
1317/************************************************************************
1318 * *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001319 * NOTATIONs *
1320 * *
1321 ************************************************************************/
1322/**
1323 * xmlCreateIDTable:
1324 *
1325 * create and initialize an empty id hash table.
1326 *
1327 * Returns the xmlIDTablePtr just created or NULL in case
1328 * of error.
1329 */
1330xmlIDTablePtr
1331xmlCreateIDTable(void) {
1332 xmlIDTablePtr ret;
1333
1334 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001335 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001336 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001337 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001338 (long)sizeof(xmlIDTable));
1339 return(NULL);
1340 }
1341 ret->max_ids = XML_MIN_NOTATION_TABLE;
1342 ret->nb_ids = 0;
1343 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001344 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001345 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001346 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001347 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001348 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001349 return(NULL);
1350 }
1351 return(ret);
1352}
1353
1354
1355/**
1356 * xmlAddID:
1357 * @ctxt: the validation context
1358 * @doc: pointer to the document
1359 * @value: the value name
1360 * @attr: the attribute holding the ID
1361 *
1362 * Register a new id declaration
1363 *
1364 * Returns NULL if not, othervise the new xmlIDPtr
1365 */
1366xmlIDPtr
1367xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
1368 xmlAttrPtr attr) {
1369 xmlIDPtr ret, cur;
1370 xmlIDTablePtr table;
1371 int i;
1372
1373 if (doc == NULL) {
1374 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1375 return(NULL);
1376 }
1377 if (value == NULL) {
1378 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1379 return(NULL);
1380 }
1381 if (attr == NULL) {
1382 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1383 return(NULL);
1384 }
1385
1386 /*
1387 * Create the ID table if needed.
1388 */
1389 table = doc->ids;
1390 if (table == NULL)
1391 table = doc->ids = xmlCreateIDTable();
1392 if (table == NULL) {
1393 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1394 return(NULL);
1395 }
1396
1397 /*
1398 * Validity Check:
1399 * Search the DTD for previous declarations of the ATTLIST
1400 */
1401 for (i = 0;i < table->nb_ids;i++) {
1402 cur = table->table[i];
1403 if (!xmlStrcmp(cur->value, value)) {
1404 /*
1405 * The id is already defined in this Dtd.
1406 */
1407 VERROR(ctxt->userData, "ID %s already defined\n", value);
1408 return(NULL);
1409 }
1410 }
1411
1412 /*
1413 * Grow the table, if needed.
1414 */
1415 if (table->nb_ids >= table->max_ids) {
1416 /*
1417 * need more ids.
1418 */
1419 table->max_ids *= 2;
1420 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001421 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001422 sizeof(xmlIDPtr));
1423 if (table->table == NULL) {
1424 fprintf(stderr, "xmlAddID: out of memory\n");
1425 return(NULL);
1426 }
1427 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001428 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001429 if (ret == NULL) {
1430 fprintf(stderr, "xmlAddID: out of memory\n");
1431 return(NULL);
1432 }
1433 table->table[table->nb_ids] = ret;
1434
1435 /*
1436 * fill the structure.
1437 */
1438 ret->value = xmlStrdup(value);
1439 ret->attr = attr;
1440 table->nb_ids++;
1441
1442 return(ret);
1443}
1444
1445/**
1446 * xmlFreeID:
1447 * @not: A id
1448 *
1449 * Deallocate the memory used by an id definition
1450 */
1451void
1452xmlFreeID(xmlIDPtr id) {
1453 if (id == NULL) return;
1454 if (id->value != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001455 xmlFree((CHAR *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001456 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001457 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001458}
1459
1460/**
1461 * xmlFreeIDTable:
1462 * @table: An id table
1463 *
1464 * Deallocate the memory used by an ID hash table.
1465 */
1466void
1467xmlFreeIDTable(xmlIDTablePtr table) {
1468 int i;
1469
1470 if (table == NULL) return;
1471
1472 for (i = 0;i < table->nb_ids;i++) {
1473 xmlFreeID(table->table[i]);
1474 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001475 xmlFree(table->table);
1476 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001477}
1478
1479/**
1480 * xmlIsID
1481 * @doc: the document
1482 * @elem: the element carrying the attribute
1483 * @attr: the attribute
1484 *
1485 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1486 * then this is simple, otherwise we use an heuristic: name ID (upper
1487 * or lowercase).
1488 *
1489 * Returns 0 or 1 depending on the lookup result
1490 */
1491int
1492xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1493 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1494 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1495 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1496 (attr->name[2] == 0)) return(1);
1497 } else {
1498 xmlAttributePtr attrDecl;
1499
1500 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1501 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1502 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1503 attr->name);
1504
Daniel Veillardb96e6431999-08-29 21:02:19 +00001505 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001506 return(1);
1507 }
1508 return(0);
1509}
1510
Daniel Veillardb96e6431999-08-29 21:02:19 +00001511/**
1512 * xmlGetID:
1513 * @doc: pointer to the document
1514 * @ID: the ID value
1515 *
1516 * Search the attribute declaring the given ID
1517 *
1518 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1519 */
1520xmlAttrPtr
1521xmlGetID(xmlDocPtr doc, const CHAR *ID) {
1522 xmlIDPtr cur;
1523 xmlIDTablePtr table;
1524 int i;
1525
1526 if (doc == NULL) {
1527 fprintf(stderr, "xmlGetID: doc == NULL\n");
1528 return(NULL);
1529 }
1530
1531 if (ID == NULL) {
1532 fprintf(stderr, "xmlGetID: ID == NULL\n");
1533 return(NULL);
1534 }
1535
1536 table = doc->ids;
1537 if (table == NULL)
1538 return(NULL);
1539
1540 /*
1541 * Search the ID list.
1542 */
1543 for (i = 0;i < table->nb_ids;i++) {
1544 cur = table->table[i];
1545 if (!xmlStrcmp(cur->value, ID)) {
1546 return(cur->attr);
1547 }
1548 }
1549 return(NULL);
1550}
1551
Daniel Veillard991e63d1999-08-15 23:32:28 +00001552/************************************************************************
1553 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001554 * Routines for validity checking *
1555 * *
1556 ************************************************************************/
1557
1558/**
1559 * xmlGetDtdElementDesc:
1560 * @dtd: a pointer to the DtD to search
1561 * @name: the element name
1562 *
1563 * Search the Dtd for the description of this element
1564 *
1565 * returns the xmlElementPtr if found or NULL
1566 */
1567
1568xmlElementPtr
1569xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
1570 xmlElementTablePtr table;
1571 xmlElementPtr cur;
1572 int i;
1573
1574 if (dtd == NULL) return(NULL);
1575 if (dtd->elements == NULL) return(NULL);
1576 table = dtd->elements;
1577
1578 for (i = 0;i < table->nb_elements;i++) {
1579 cur = table->table[i];
1580 if (!xmlStrcmp(cur->name, name))
1581 return(cur);
1582 }
1583 return(NULL);
1584}
1585
1586/**
1587 * xmlGetDtdAttrDesc:
1588 * @dtd: a pointer to the DtD to search
1589 * @elem: the element name
1590 * @name: the attribute name
1591 *
1592 * Search the Dtd for the description of this attribute on
1593 * this element.
1594 *
1595 * returns the xmlAttributePtr if found or NULL
1596 */
1597
1598xmlAttributePtr
1599xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
1600 xmlAttributeTablePtr table;
1601 xmlAttributePtr cur;
1602 int i;
1603
1604 if (dtd == NULL) return(NULL);
1605 if (dtd->attributes == NULL) return(NULL);
1606 table = dtd->attributes;
1607
1608 for (i = 0;i < table->nb_attributes;i++) {
1609 cur = table->table[i];
1610 if ((!xmlStrcmp(cur->name, name)) &&
1611 (!xmlStrcmp(cur->elem, elem)))
1612 return(cur);
1613 }
1614 return(NULL);
1615}
1616
1617/**
1618 * xmlGetDtdNotationDesc:
1619 * @dtd: a pointer to the DtD to search
1620 * @name: the notation name
1621 *
1622 * Search the Dtd for the description of this notation
1623 *
1624 * returns the xmlNotationPtr if found or NULL
1625 */
1626
1627xmlNotationPtr
1628xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
1629 xmlNotationTablePtr table;
1630 xmlNotationPtr cur;
1631 int i;
1632
1633 if (dtd == NULL) return(NULL);
1634 if (dtd->notations == NULL) return(NULL);
1635 table = dtd->notations;
1636
1637 for (i = 0;i < table->nb_notations;i++) {
1638 cur = table->table[i];
1639 if (!xmlStrcmp(cur->name, name))
1640 return(cur);
1641 }
1642 return(NULL);
1643}
1644
1645/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001646 * xmlValidateNotationUse:
1647 * @ctxt: the validation context
1648 * @doc: the document
1649 * @notationName: the notation name to check
1650 *
1651 * Validate that the given mame match a notation declaration.
1652 * - [ VC: Notation Declared ]
1653 *
1654 * returns 1 if valid or 0 otherwise
1655 */
1656
1657int
1658xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1659 const CHAR *notationName) {
1660 xmlNotationPtr notaDecl;
1661 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1662
1663 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1664 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1665 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1666
1667 if (notaDecl == NULL) {
1668 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1669 notationName);
1670 return(0);
1671 }
1672 return(1);
1673}
1674
1675/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001676 * xmlIsMixedElement
1677 * @doc: the document
1678 * @name: the element name
1679 *
1680 * Search in the DtDs whether an element accept Mixed content (or ANY)
1681 * basically if it is supposed to accept text childs
1682 *
1683 * returns 0 if no, 1 if yes, and -1 if no element description is available
1684 */
1685
1686int
1687xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
1688 xmlElementPtr elemDecl;
1689
1690 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1691
1692 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1693 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1694 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1695 if (elemDecl == NULL) return(-1);
1696 switch (elemDecl->type) {
1697 case XML_ELEMENT_TYPE_ELEMENT:
1698 return(0);
1699 case XML_ELEMENT_TYPE_EMPTY:
1700 /*
1701 * return 1 for EMPTY since we want VC error to pop up
1702 * on <empty> </empty> for example
1703 */
1704 case XML_ELEMENT_TYPE_ANY:
1705 case XML_ELEMENT_TYPE_MIXED:
1706 return(1);
1707 }
1708 return(1);
1709}
1710
1711/**
1712 * xmlValidateNameValue:
1713 * @value: an Name value
1714 *
1715 * Validate that the given value match Name production
1716 *
1717 * returns 1 if valid or 0 otherwise
1718 */
1719
1720int
1721xmlValidateNameValue(const CHAR *value) {
1722 const CHAR *cur;
1723
1724 if (value == NULL) return(0);
1725 cur = value;
1726
1727 if (!IS_LETTER(*cur) && (*cur != '_') &&
1728 (*cur != ':')) {
1729 return(0);
1730 }
1731
1732 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1733 (*cur == '.') || (*cur == '-') ||
1734 (*cur == '_') || (*cur == ':') ||
1735 (IS_COMBINING(*cur)) ||
1736 (IS_EXTENDER(*cur)))
1737 cur++;
1738
1739 if (*cur != 0) return(0);
1740
1741 return(1);
1742}
1743
1744/**
1745 * xmlValidateNamesValue:
1746 * @value: an Names value
1747 *
1748 * Validate that the given value match Names production
1749 *
1750 * returns 1 if valid or 0 otherwise
1751 */
1752
1753int
1754xmlValidateNamesValue(const CHAR *value) {
1755 const CHAR *cur;
1756
1757 if (value == NULL) return(0);
1758 cur = value;
1759
1760 if (!IS_LETTER(*cur) && (*cur != '_') &&
1761 (*cur != ':')) {
1762 return(0);
1763 }
1764
1765 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1766 (*cur == '.') || (*cur == '-') ||
1767 (*cur == '_') || (*cur == ':') ||
1768 (IS_COMBINING(*cur)) ||
1769 (IS_EXTENDER(*cur)))
1770 cur++;
1771
1772 while (IS_BLANK(*cur)) {
1773 while (IS_BLANK(*cur)) cur++;
1774
1775 if (!IS_LETTER(*cur) && (*cur != '_') &&
1776 (*cur != ':')) {
1777 return(0);
1778 }
1779
1780 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1781 (*cur == '.') || (*cur == '-') ||
1782 (*cur == '_') || (*cur == ':') ||
1783 (IS_COMBINING(*cur)) ||
1784 (IS_EXTENDER(*cur)))
1785 cur++;
1786 }
1787
1788 if (*cur != 0) return(0);
1789
1790 return(1);
1791}
1792
1793/**
1794 * xmlValidateNmtokenValue:
1795 * @value: an Mntoken value
1796 *
1797 * Validate that the given value match Nmtoken production
1798 *
1799 * [ VC: Name Token ]
1800 *
1801 * returns 1 if valid or 0 otherwise
1802 */
1803
1804int
1805xmlValidateNmtokenValue(const CHAR *value) {
1806 const CHAR *cur;
1807
1808 if (value == NULL) return(0);
1809 cur = value;
1810
1811 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1812 (*cur != '.') && (*cur != '-') &&
1813 (*cur != '_') && (*cur != ':') &&
1814 (!IS_COMBINING(*cur)) &&
1815 (!IS_EXTENDER(*cur)))
1816 return(0);
1817
1818 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1819 (*cur == '.') || (*cur == '-') ||
1820 (*cur == '_') || (*cur == ':') ||
1821 (IS_COMBINING(*cur)) ||
1822 (IS_EXTENDER(*cur)))
1823 cur++;
1824
1825 if (*cur != 0) return(0);
1826
1827 return(1);
1828 return(1);
1829}
1830
1831/**
1832 * xmlValidateNmtokensValue:
1833 * @value: an Mntokens value
1834 *
1835 * Validate that the given value match Nmtokens production
1836 *
1837 * [ VC: Name Token ]
1838 *
1839 * returns 1 if valid or 0 otherwise
1840 */
1841
1842int
1843xmlValidateNmtokensValue(const CHAR *value) {
1844 const CHAR *cur;
1845
1846 if (value == NULL) return(0);
1847 cur = value;
1848
1849 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1850 (*cur != '.') && (*cur != '-') &&
1851 (*cur != '_') && (*cur != ':') &&
1852 (!IS_COMBINING(*cur)) &&
1853 (!IS_EXTENDER(*cur)))
1854 return(0);
1855
1856 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1857 (*cur == '.') || (*cur == '-') ||
1858 (*cur == '_') || (*cur == ':') ||
1859 (IS_COMBINING(*cur)) ||
1860 (IS_EXTENDER(*cur)))
1861 cur++;
1862
1863 while (IS_BLANK(*cur)) {
1864 while (IS_BLANK(*cur)) cur++;
1865
1866 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1867 (*cur != '.') && (*cur != '-') &&
1868 (*cur != '_') && (*cur != ':') &&
1869 (!IS_COMBINING(*cur)) &&
1870 (!IS_EXTENDER(*cur)))
1871 return(0);
1872
1873 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1874 (*cur == '.') || (*cur == '-') ||
1875 (*cur == '_') || (*cur == ':') ||
1876 (IS_COMBINING(*cur)) ||
1877 (IS_EXTENDER(*cur)))
1878 cur++;
1879 }
1880
1881 if (*cur != 0) return(0);
1882
1883 return(1);
1884}
1885
1886/**
1887 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001888 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00001889 * @doc: a document instance
1890 * @nota: a notation definition
1891 *
1892 * Try to validate a single notation definition
1893 * basically it does the following checks as described by the
1894 * XML-1.0 recommendation:
1895 * - it seems that no validity constraing exist on notation declarations
1896 * But this function get called anyway ...
1897 *
1898 * returns 1 if valid or 0 otherwise
1899 */
1900
1901int
1902xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1903 xmlNotationPtr nota) {
1904 int ret = 1;
1905
1906 return(ret);
1907}
1908
1909/**
1910 * xmlValidateAttributeValue:
1911 * @type: an attribute type
1912 * @value: an attribute value
1913 *
1914 * Validate that the given attribute value match the proper production
1915 *
1916 * [ VC: ID ]
1917 * Values of type ID must match the Name production....
1918 *
1919 * [ VC: IDREF ]
1920 * Values of type IDREF must match the Name production, and values
1921 * of type IDREFS must match Names ...
1922 *
1923 * [ VC: Entity Name ]
1924 * Values of type ENTITY must match the Name production, values
1925 * of type ENTITIES must match Names ...
1926 *
1927 * [ VC: Name Token ]
1928 * Values of type NMTOKEN must match the Nmtoken production; values
1929 * of type NMTOKENS must match Nmtokens.
1930 *
1931 * returns 1 if valid or 0 otherwise
1932 */
1933
1934int
1935xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
1936 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001937 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001938 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001939 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001940 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001941 case XML_ATTRIBUTE_IDREF:
1942 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001943 case XML_ATTRIBUTE_NOTATION:
1944 return(xmlValidateNameValue(value));
1945 case XML_ATTRIBUTE_NMTOKENS:
1946 case XML_ATTRIBUTE_ENUMERATION:
1947 return(xmlValidateNmtokensValue(value));
1948 case XML_ATTRIBUTE_NMTOKEN:
1949 return(xmlValidateNmtokenValue(value));
1950 case XML_ATTRIBUTE_CDATA:
1951 break;
1952 }
1953 return(1);
1954}
1955
1956/**
1957 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00001958 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00001959 * @doc: a document instance
1960 * @attr: an attribute definition
1961 *
1962 * Try to validate a single attribute definition
1963 * basically it does the following checks as described by the
1964 * XML-1.0 recommendation:
1965 * - [ VC: Attribute Default Legal ]
1966 * - [ VC: Enumeration ]
1967 * - [ VC: ID Attribute Default ]
1968 *
1969 * The ID/IDREF uniqueness and matching are done separately
1970 *
1971 * returns 1 if valid or 0 otherwise
1972 */
1973
1974int
1975xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1976 xmlAttributePtr attr) {
1977 int ret = 1;
1978 int val;
1979 CHECK_DTD;
1980 if(attr == NULL) return(1);
1981
1982 /* Attribute Default Legal */
1983 /* Enumeration */
1984 if (attr->defaultValue != NULL) {
1985 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
1986 if (val == 0) {
1987 VERROR(ctxt->userData,
1988 "Syntax of default value for attribute %s on %s is not valid\n",
1989 attr->name, attr->elem);
1990 }
1991 ret &= val;
1992 }
1993
1994 /* ID Attribute Default */
1995 if ((attr->type == XML_ATTRIBUTE_ID)&&
1996 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
1997 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
1998 VERROR(ctxt->userData,
1999 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2000 attr->name, attr->elem);
2001 ret = 0;
2002 }
2003
Daniel Veillardb96e6431999-08-29 21:02:19 +00002004 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002005 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2006 int nbId = 0;
2007
2008 /* the trick is taht we parse DtD as their own internal subset */
2009 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2010 attr->elem);
2011 if (elem != NULL) {
2012 nbId = xmlScanIDAttributeDecl(NULL, elem);
2013 }
2014 if (nbId >= 1)
2015 VERROR(ctxt->userData,
2016 "Element %s has ID attribute defined in the external subset : %s\n",
2017 attr->elem, attr->name);
2018 }
2019
2020 return(ret);
2021}
2022
2023/**
2024 * xmlValidateElementDecl:
2025 * @ctxt: the validation context
2026 * @doc: a document instance
2027 * @elem: an element definition
2028 *
2029 * Try to validate a single element definition
2030 * basically it does the following checks as described by the
2031 * XML-1.0 recommendation:
2032 * - [ VC: One ID per Element Type ]
2033 * - [ VC: No Duplicate Types ]
2034 * - [ VC: Unique Element Type Declaration ]
2035 *
2036 * returns 1 if valid or 0 otherwise
2037 */
2038
2039int
2040xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2041 xmlElementPtr elem) {
2042 int ret = 1;
2043 xmlElementPtr tst;
2044
2045 CHECK_DTD;
2046
2047 if (elem == NULL) return(1);
2048
2049 /* No Duplicate Types */
2050 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2051 xmlElementContentPtr cur, next;
2052 const CHAR *name;
2053
2054 cur = elem->content;
2055 while (cur != NULL) {
2056 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2057 if (cur->c1 == NULL) break;
2058 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2059 name = cur->c1->name;
2060 next = cur->c2;
2061 while (next != NULL) {
2062 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2063 if (!xmlStrcmp(next->name, name)) {
2064 VERROR(ctxt->userData,
2065 "Definition of %s has duplicate references of %s\n",
2066 elem->name, name);
2067 ret = 0;
2068 }
2069 break;
2070 }
2071 if (next->c1 == NULL) break;
2072 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2073 if (!xmlStrcmp(next->c1->name, name)) {
2074 VERROR(ctxt->userData,
2075 "Definition of %s has duplicate references of %s\n",
2076 elem->name, name);
2077 ret = 0;
2078 }
2079 next = next->c2;
2080 }
2081 }
2082 cur = cur->c2;
2083 }
2084 }
2085
2086 /* VC: Unique Element Type Declaration */
2087 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2088 if ((tst != NULL ) && (tst != elem)) {
2089 VERROR(ctxt->userData, "Redefinition of element %s\n",
2090 elem->name);
2091 ret = 0;
2092 }
2093 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2094 if ((tst != NULL ) && (tst != elem)) {
2095 VERROR(ctxt->userData, "Redefinition of element %s\n",
2096 elem->name);
2097 ret = 0;
2098 }
2099
2100 /* One ID per Element Type */
2101 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2102 ret = 0;
2103 }
2104 return(ret);
2105}
2106
2107/**
2108 * xmlValidateOneAttribute:
2109 * @ctxt: the validation context
2110 * @doc: a document instance
2111 * @elem: an element instance
2112 * @attr: an attribute instance
2113 *
2114 * Try to validate a single attribute for an element
2115 * basically it * does the following checks as described by the
2116 * XML-1.0 recommendation:
2117 * - [ VC: Attribute Value Type ]
2118 * - [ VC: Fixed Attribute Default ]
2119 * - [ VC: Entity Name ]
2120 * - [ VC: Name Token ]
2121 * - [ VC: ID ]
2122 * - [ VC: IDREF ]
2123 * - [ VC: Entity Name ]
2124 * - [ VC: Notation Attributes ]
2125 *
2126 * The ID/IDREF uniqueness and matching are done separately
2127 *
2128 * returns 1 if valid or 0 otherwise
2129 */
2130
2131int
2132xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2133 xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002134 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002135 xmlAttributePtr attrDecl;
2136 int val;
2137 int ret = 1;
2138
2139 CHECK_DTD;
2140 if ((elem == NULL) || (elem->name == NULL)) return(0);
2141 if ((attr == NULL) || (attr->name == NULL)) return(0);
2142
2143 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2144 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2145 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2146
2147
2148 /* Validity Constraint: Attribute Value Type */
2149 if (attrDecl == NULL) {
2150 VERROR(ctxt->userData,
2151 "No declaration for attribute %s on element %s\n",
2152 attr->name, elem->name);
2153 return(0);
2154 }
2155 val = xmlValidateAttributeValue(attrDecl->type, value);
2156 if (val == 0) {
2157 VERROR(ctxt->userData,
2158 "Syntax of value for attribute %s on %s is not valid\n",
2159 attr->name, elem->name);
2160 ret = 0;
2161 }
2162
Daniel Veillardb96e6431999-08-29 21:02:19 +00002163 /* Validity Constraint: ID uniqueness */
2164 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2165 xmlAddID(ctxt, doc, value, attr);
2166 }
2167
Daniel Veillardb05deb71999-08-10 19:04:08 +00002168 /* Validity Constraint: Notation Attributes */
2169 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2170 xmlEnumerationPtr tree = attrDecl->tree;
2171 xmlNotationPtr nota;
2172
2173 /* First check that the given NOTATION was declared */
2174 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2175 if (nota == NULL)
2176 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2177
2178 if (nota == NULL) {
2179 VERROR(ctxt->userData,
2180 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2181 value, attr->name, elem->name);
2182 ret = 0;
2183 }
2184
2185 /* Second, verify that it's among the list */
2186 while (tree != NULL) {
2187 if (!xmlStrcmp(tree->name, value)) break;
2188 tree = tree->next;
2189 }
2190 if (tree == NULL) {
2191 VERROR(ctxt->userData,
2192 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2193 value, attr->name, elem->name);
2194 ret = 0;
2195 }
2196 }
2197
2198 /* Validity Constraint: Enumeration */
2199 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2200 xmlEnumerationPtr tree = attrDecl->tree;
2201 while (tree != NULL) {
2202 if (!xmlStrcmp(tree->name, value)) break;
2203 tree = tree->next;
2204 }
2205 if (tree == NULL) {
2206 VERROR(ctxt->userData,
2207 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2208 value, attr->name, elem->name);
2209 ret = 0;
2210 }
2211 }
2212
2213 /* Fixed Attribute Default */
2214 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2215 (xmlStrcmp(attrDecl->defaultValue, value))) {
2216 VERROR(ctxt->userData,
2217 "Value for attribute %s on %s must be \"%s\"\n",
2218 attr->name, elem->name, attrDecl->defaultValue);
2219 ret = 0;
2220 }
2221
Daniel Veillardb96e6431999-08-29 21:02:19 +00002222 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002223 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2224 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2225 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2226 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002227 return(0);
2228 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002229 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002230 return(ret);
2231}
2232
2233int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2234 xmlElementContentPtr cont);
2235
2236/**
2237 * xmlValidateElementTypeExpr:
2238 * @ctxt: the validation context
2239 * @child: pointer to the child list
2240 * @cont: pointer to the content declaration
2241 *
2242 * Try to validate the content of an element of type element
2243 * but don't handle the occurence factor
2244 *
2245 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2246 * also update child value in-situ.
2247 */
2248
2249int
2250xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2251 xmlElementContentPtr cont) {
2252 xmlNodePtr cur;
2253 int ret = 1;
2254
2255 if (cont == NULL) return(-1);
2256 while (*child != NULL) {
2257 if ((*child)->type == XML_PI_NODE) {
2258 *child = (*child)->next;
2259 continue;
2260 }
2261 if ((*child)->type == XML_COMMENT_NODE) {
2262 *child = (*child)->next;
2263 continue;
2264 }
2265 else if ((*child)->type != XML_ELEMENT_NODE) {
2266 return(-1);
2267 }
2268 break;
2269 }
2270 switch (cont->type) {
2271 case XML_ELEMENT_CONTENT_PCDATA:
2272 /* Internal error !!! */
2273 fprintf(stderr, "Internal: MIXED struct bad\n");
2274 return(-1);
2275 case XML_ELEMENT_CONTENT_ELEMENT:
2276 if (*child == NULL) return(0);
2277 ret = (!xmlStrcmp((*child)->name, cont->name));
2278 if (ret == 1)
2279 *child = (*child)->next;
2280 return(ret);
2281 case XML_ELEMENT_CONTENT_OR:
2282 cur = *child;
2283 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2284 if (ret == -1) return(-1);
2285 if (ret == 1) {
2286 return(1);
2287 }
2288 /* rollback and retry the other path */
2289 *child = cur;
2290 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2291 if (ret == -1) return(-1);
2292 if (ret == 0) {
2293 *child = cur;
2294 return(0);
2295 }
2296 return(1);
2297 case XML_ELEMENT_CONTENT_SEQ:
2298 cur = *child;
2299 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2300 if (ret == -1) return(-1);
2301 if (ret == 0) {
2302 *child = cur;
2303 return(0);
2304 }
2305 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2306 if (ret == -1) return(-1);
2307 if (ret == 0) {
2308 *child = cur;
2309 return(0);
2310 }
2311 return(1);
2312 }
2313 return(ret);
2314}
2315
2316/**
2317 * xmlValidateElementTypeElement:
2318 * @ctxt: the validation context
2319 * @child: pointer to the child list
2320 * @cont: pointer to the content declaration
2321 *
2322 * Try to validate the content of an element of type element
2323 * yeah, Yet Another Regexp Implementation, and recursive
2324 *
2325 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2326 * also update child and content values in-situ.
2327 */
2328
2329int
2330xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2331 xmlElementContentPtr cont) {
2332 xmlNodePtr cur;
2333 int ret = 1;
2334
2335 if (cont == NULL) return(-1);
2336 while (*child != NULL) {
2337 if ((*child)->type == XML_PI_NODE) {
2338 *child = (*child)->next;
2339 continue;
2340 }
2341 if ((*child)->type == XML_COMMENT_NODE) {
2342 *child = (*child)->next;
2343 continue;
2344 }
2345 else if ((*child)->type != XML_ELEMENT_NODE) {
2346 return(-1);
2347 }
2348 break;
2349 }
2350 cur = *child;
2351 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2352 if (ret == -1) return(-1);
2353 switch (cont->ocur) {
2354 case XML_ELEMENT_CONTENT_ONCE:
2355 if (ret == 1) {
2356 return(1);
2357 }
2358 *child = cur;
2359 return(0);
2360 case XML_ELEMENT_CONTENT_OPT:
2361 if (ret == 0) {
2362 *child = cur;
2363 return(1);
2364 }
2365 break;
2366 case XML_ELEMENT_CONTENT_MULT:
2367 if (ret == 0) {
2368 *child = cur;
2369 break;
2370 }
2371 /* no break on purpose */
2372 case XML_ELEMENT_CONTENT_PLUS:
2373 if (ret == 0) {
2374 *child = cur;
2375 return(0);
2376 }
2377 do {
2378 cur = *child;
2379 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2380 } while (ret == 1);
2381 if (ret == -1) return(-1);
2382 *child = cur;
2383 break;
2384 }
2385 while (*child != NULL) {
2386 if ((*child)->type == XML_PI_NODE) {
2387 *child = (*child)->next;
2388 continue;
2389 }
2390 if ((*child)->type == XML_COMMENT_NODE) {
2391 *child = (*child)->next;
2392 continue;
2393 }
2394 else if ((*child)->type != XML_ELEMENT_NODE) {
2395 return(-1);
2396 }
2397 break;
2398 }
2399 return(1);
2400}
2401
2402/**
2403 * xmlSprintfElementChilds:
2404 * @buf: an output buffer
2405 * @content: An element
2406 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2407 *
2408 * This will dump the list of childs to the buffer
2409 * Intended just for the debug routine
2410 */
2411void
2412xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2413 xmlNodePtr cur;
2414
2415 if (node == NULL) return;
2416 if (glob) strcat(buf, "(");
2417 cur = node->childs;
2418 while (cur != NULL) {
2419 switch (cur->type) {
2420 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002421 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002422 if (cur->next != NULL)
2423 strcat(buf, " ");
2424 break;
2425 case XML_TEXT_NODE:
2426 case XML_CDATA_SECTION_NODE:
2427 case XML_ENTITY_REF_NODE:
2428 strcat(buf, "CDATA");
2429 if (cur->next != NULL)
2430 strcat(buf, " ");
2431 break;
2432 case XML_ATTRIBUTE_NODE:
2433 case XML_DOCUMENT_NODE:
2434 case XML_DOCUMENT_TYPE_NODE:
2435 case XML_DOCUMENT_FRAG_NODE:
2436 case XML_NOTATION_NODE:
2437 strcat(buf, "???");
2438 if (cur->next != NULL)
2439 strcat(buf, " ");
2440 break;
2441 case XML_ENTITY_NODE:
2442 case XML_PI_NODE:
2443 case XML_COMMENT_NODE:
2444 break;
2445 }
2446 cur = cur->next;
2447 }
2448 if (glob) strcat(buf, ")");
2449}
2450
2451
2452/**
2453 * xmlValidateOneElement:
2454 * @ctxt: the validation context
2455 * @doc: a document instance
2456 * @elem: an element instance
2457 *
2458 * Try to validate a single element and it's attributes,
2459 * basically it does the following checks as described by the
2460 * XML-1.0 recommendation:
2461 * - [ VC: Element Valid ]
2462 * - [ VC: Required Attribute ]
2463 * Then call xmlValidateOneAttribute() for each attribute present.
2464 *
2465 * The ID/IDREF checkings are done separately
2466 *
2467 * returns 1 if valid or 0 otherwise
2468 */
2469
2470int
2471xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2472 xmlNodePtr elem) {
2473 xmlElementPtr elemDecl;
2474 xmlElementContentPtr cont;
2475 xmlNodePtr child;
2476 int ret = 1;
2477 const CHAR *name;
2478
2479 CHECK_DTD;
2480
2481 if ((elem == NULL) || (elem->name == NULL)) return(0);
2482
2483 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2484 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2485 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2486 if (elemDecl == NULL) {
2487 VERROR(ctxt->userData, "No declaration for element %s\n",
2488 elem->name);
2489 return(0);
2490 }
2491
2492 /* Check taht the element content matches the definition */
2493 switch (elemDecl->type) {
2494 case XML_ELEMENT_TYPE_EMPTY:
2495 if (elem->childs != NULL) {
2496 VERROR(ctxt->userData,
2497 "Element %s was declared EMPTY this one has content\n",
2498 elem->name);
2499 ret = 0;
2500 }
2501 break;
2502 case XML_ELEMENT_TYPE_ANY:
2503 /* I don't think anything is required then */
2504 break;
2505 case XML_ELEMENT_TYPE_MIXED:
2506 /* Hum, this start to get messy */
2507 child = elem->childs;
2508 while (child != NULL) {
2509 if (child->type == XML_ELEMENT_NODE) {
2510 name = child->name;
2511 cont = elemDecl->content;
2512 while (cont != NULL) {
2513 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2514 if (!xmlStrcmp(cont->name, name)) break;
2515 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2516 (cont->c1 != NULL) &&
2517 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2518 if (!xmlStrcmp(cont->c1->name, name)) break;
2519 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2520 (cont->c1 == NULL) ||
2521 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2522 /* Internal error !!! */
2523 fprintf(stderr, "Internal: MIXED struct bad\n");
2524 break;
2525 }
2526 cont = cont->c2;
2527 }
2528 if (cont == NULL) {
2529 VERROR(ctxt->userData,
2530 "Element %s is not declared in %s list of possible childs\n",
2531 name, elem->name);
2532 ret = 0;
2533 }
2534 }
2535 child = child->next;
2536 }
2537 break;
2538 case XML_ELEMENT_TYPE_ELEMENT:
2539 child = elem->childs;
2540 cont = elemDecl->content;
2541 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2542 if ((ret == 0) || (child != NULL)) {
2543 char expr[1000];
2544 char list[2000];
2545
2546 expr[0] = 0;
2547 xmlSprintfElementContent(expr, cont, 1);
2548 list[0] = 0;
2549 xmlSprintfElementChilds(list, elem, 1);
2550
2551 VERROR(ctxt->userData,
2552 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2553 elem->name, expr, list);
2554 ret = 0;
2555 }
2556 break;
2557 }
2558
Daniel Veillardb96e6431999-08-29 21:02:19 +00002559 /* TODO - [ VC: Required Attribute ] */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002560 return(ret);
2561}
2562
2563/**
2564 * xmlValidateRoot:
2565 * @ctxt: the validation context
2566 * @doc: a document instance
2567 *
2568 * Try to validate a the root element
2569 * basically it does the following check as described by the
2570 * XML-1.0 recommendation:
2571 * - [ VC: Root Element Type ]
2572 * it doesn't try to recurse or apply other check to the element
2573 *
2574 * returns 1 if valid or 0 otherwise
2575 */
2576
2577int
2578xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2579 if (doc == NULL) return(0);
2580
2581 if ((doc->intSubset == NULL) ||
2582 (doc->intSubset->name == NULL)) {
2583 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2584 return(0);
2585 }
2586 if ((doc->root == NULL) || (doc->root->name == NULL)) {
2587 VERROR(ctxt->userData, "Not valid: no root element\n");
2588 return(0);
2589 }
2590 if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2591 VERROR(ctxt->userData,
2592 "Not valid: root and DtD name do not match %s and %s\n",
2593 doc->root->name, doc->intSubset->name);
2594 return(0);
2595 }
2596 return(1);
2597}
2598
2599
2600/**
2601 * xmlValidateElement:
2602 * @ctxt: the validation context
2603 * @doc: a document instance
2604 * @elem: an element instance
2605 *
2606 * Try to validate the subtree under an element
2607 *
2608 * returns 1 if valid or 0 otherwise
2609 */
2610
2611int
2612xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
2613 CHECK_DTD;
2614
2615 return(1);
2616}
2617
2618/**
2619 * xmlValidateDtd:
2620 * @ctxt: the validation context
2621 * @doc: a document instance
2622 * @dtd: a dtd instance
2623 *
2624 * Try to validate the dtd instance
2625 *
2626 * basically it does check all the definitions in the DtD.
2627 *
2628 * returns 1 if valid or 0 otherwise
2629 */
2630
2631int
2632xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
2633 return(1);
2634}
2635
2636/**
2637 * xmlValidateDocument:
2638 * @ctxt: the validation context
2639 * @doc: a document instance
2640 *
2641 * Try to validate the document instance
2642 *
2643 * basically it does the all the checks described by the
2644 * i.e. validates the internal and external subset (if present)
2645 * and validate the document tree.
2646 *
2647 * returns 1 if valid or 0 otherwise
2648 */
2649
2650int
2651xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2652 if (!xmlValidateRoot(ctxt, doc)) return(0);
2653
2654 return(1);
2655}
2656