blob: a6466ff637be900228b2906dd867a130fa3f2789 [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 Veillardc08a2c61999-09-08 21:35:25 +00001319 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001320 * *
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 Veillardc08a2c61999-09-08 21:35:25 +00001554 * Refs *
1555 * *
1556 ************************************************************************/
1557/**
1558 * xmlCreateRefTable:
1559 *
1560 * create and initialize an empty ref hash table.
1561 *
1562 * Returns the xmlRefTablePtr just created or NULL in case
1563 * of error.
1564 */
1565xmlRefTablePtr
1566xmlCreateRefTable(void) {
1567 xmlRefTablePtr ret;
1568
1569 ret = (xmlRefTablePtr)
1570 xmlMalloc(sizeof(xmlRefTable));
1571 if (ret == NULL) {
1572 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1573 (long)sizeof(xmlRefTable));
1574 return(NULL);
1575 }
1576 ret->max_refs = XML_MIN_NOTATION_TABLE;
1577 ret->nb_refs = 0;
1578 ret->table = (xmlRefPtr *)
1579 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1580 if (ret == NULL) {
1581 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1582 ret->max_refs * (long)sizeof(xmlRef));
1583 xmlFree(ret);
1584 return(NULL);
1585 }
1586 return(ret);
1587}
1588
1589
1590/**
1591 * xmlAddRef:
1592 * @ctxt: the validation context
1593 * @doc: pointer to the document
1594 * @value: the value name
1595 * @attr: the attribute holding the Ref
1596 *
1597 * Register a new ref declaration
1598 *
1599 * Returns NULL if not, othervise the new xmlRefPtr
1600 */
1601xmlRefPtr
1602xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
1603 xmlAttrPtr attr) {
1604 xmlRefPtr ret;
1605 xmlRefTablePtr table;
1606
1607 if (doc == NULL) {
1608 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1609 return(NULL);
1610 }
1611 if (value == NULL) {
1612 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1613 return(NULL);
1614 }
1615 if (attr == NULL) {
1616 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1617 return(NULL);
1618 }
1619
1620 /*
1621 * Create the Ref table if needed.
1622 */
1623 table = doc->refs;
1624 if (table == NULL)
1625 table = doc->refs = xmlCreateRefTable();
1626 if (table == NULL) {
1627 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1628 return(NULL);
1629 }
1630
1631 /*
1632 * Grow the table, if needed.
1633 */
1634 if (table->nb_refs >= table->max_refs) {
1635 /*
1636 * need more refs.
1637 */
1638 table->max_refs *= 2;
1639 table->table = (xmlRefPtr *)
1640 xmlRealloc(table->table, table->max_refs *
1641 sizeof(xmlRefPtr));
1642 if (table->table == NULL) {
1643 fprintf(stderr, "xmlAddRef: out of memory\n");
1644 return(NULL);
1645 }
1646 }
1647 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1648 if (ret == NULL) {
1649 fprintf(stderr, "xmlAddRef: out of memory\n");
1650 return(NULL);
1651 }
1652 table->table[table->nb_refs] = ret;
1653
1654 /*
1655 * fill the structure.
1656 */
1657 ret->value = xmlStrdup(value);
1658 ret->attr = attr;
1659 table->nb_refs++;
1660
1661 return(ret);
1662}
1663
1664/**
1665 * xmlFreeRef:
1666 * @not: A ref
1667 *
1668 * Deallocate the memory used by an ref definition
1669 */
1670void
1671xmlFreeRef(xmlRefPtr ref) {
1672 if (ref == NULL) return;
1673 if (ref->value != NULL)
1674 xmlFree((CHAR *) ref->value);
1675 memset(ref, -1, sizeof(xmlRef));
1676 xmlFree(ref);
1677}
1678
1679/**
1680 * xmlFreeRefTable:
1681 * @table: An ref table
1682 *
1683 * Deallocate the memory used by an Ref hash table.
1684 */
1685void
1686xmlFreeRefTable(xmlRefTablePtr table) {
1687 int i;
1688
1689 if (table == NULL) return;
1690
1691 for (i = 0;i < table->nb_refs;i++) {
1692 xmlFreeRef(table->table[i]);
1693 }
1694 xmlFree(table->table);
1695 xmlFree(table);
1696}
1697
1698/**
1699 * xmlIsRef
1700 * @doc: the document
1701 * @elem: the element carrying the attribute
1702 * @attr: the attribute
1703 *
1704 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1705 * then this is simple, otherwise we use an heuristic: name Ref (upper
1706 * or lowercase).
1707 *
1708 * Returns 0 or 1 depending on the lookup result
1709 */
1710int
1711xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1712 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1713 return(0);
1714 /*******************
1715 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1716 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1717 (attr->name[2] == 0)) return(1);
1718 *******************/
1719 } else {
1720 xmlAttributePtr attrDecl;
1721
1722 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1723 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1724 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1725 attr->name);
1726
1727 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1728 return(1);
1729 }
1730 return(0);
1731}
1732
1733/**
1734 * xmlGetRef:
1735 * @doc: pointer to the document
1736 * @Ref: the Ref value
1737 *
1738 * Search the attribute declaring the given Ref
1739 *
1740 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1741 */
1742xmlAttrPtr
1743xmlGetRef(xmlDocPtr doc, const CHAR *Ref) {
1744 xmlRefPtr cur;
1745 xmlRefTablePtr table;
1746 int i;
1747
1748 if (doc == NULL) {
1749 fprintf(stderr, "xmlGetRef: doc == NULL\n");
1750 return(NULL);
1751 }
1752
1753 if (Ref == NULL) {
1754 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1755 return(NULL);
1756 }
1757
1758 table = doc->refs;
1759 if (table == NULL)
1760 return(NULL);
1761
1762 /*
1763 * Search the Ref list.
1764 */
1765 for (i = 0;i < table->nb_refs;i++) {
1766 cur = table->table[i];
1767 if (!xmlStrcmp(cur->value, Ref)) {
1768 return(cur->attr);
1769 }
1770 }
1771 return(NULL);
1772}
1773
1774/************************************************************************
1775 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001776 * Routines for validity checking *
1777 * *
1778 ************************************************************************/
1779
1780/**
1781 * xmlGetDtdElementDesc:
1782 * @dtd: a pointer to the DtD to search
1783 * @name: the element name
1784 *
1785 * Search the Dtd for the description of this element
1786 *
1787 * returns the xmlElementPtr if found or NULL
1788 */
1789
1790xmlElementPtr
1791xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
1792 xmlElementTablePtr table;
1793 xmlElementPtr cur;
1794 int i;
1795
1796 if (dtd == NULL) return(NULL);
1797 if (dtd->elements == NULL) return(NULL);
1798 table = dtd->elements;
1799
1800 for (i = 0;i < table->nb_elements;i++) {
1801 cur = table->table[i];
1802 if (!xmlStrcmp(cur->name, name))
1803 return(cur);
1804 }
1805 return(NULL);
1806}
1807
1808/**
1809 * xmlGetDtdAttrDesc:
1810 * @dtd: a pointer to the DtD to search
1811 * @elem: the element name
1812 * @name: the attribute name
1813 *
1814 * Search the Dtd for the description of this attribute on
1815 * this element.
1816 *
1817 * returns the xmlAttributePtr if found or NULL
1818 */
1819
1820xmlAttributePtr
1821xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
1822 xmlAttributeTablePtr table;
1823 xmlAttributePtr cur;
1824 int i;
1825
1826 if (dtd == NULL) return(NULL);
1827 if (dtd->attributes == NULL) return(NULL);
1828 table = dtd->attributes;
1829
1830 for (i = 0;i < table->nb_attributes;i++) {
1831 cur = table->table[i];
1832 if ((!xmlStrcmp(cur->name, name)) &&
1833 (!xmlStrcmp(cur->elem, elem)))
1834 return(cur);
1835 }
1836 return(NULL);
1837}
1838
1839/**
1840 * xmlGetDtdNotationDesc:
1841 * @dtd: a pointer to the DtD to search
1842 * @name: the notation name
1843 *
1844 * Search the Dtd for the description of this notation
1845 *
1846 * returns the xmlNotationPtr if found or NULL
1847 */
1848
1849xmlNotationPtr
1850xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
1851 xmlNotationTablePtr table;
1852 xmlNotationPtr cur;
1853 int i;
1854
1855 if (dtd == NULL) return(NULL);
1856 if (dtd->notations == NULL) return(NULL);
1857 table = dtd->notations;
1858
1859 for (i = 0;i < table->nb_notations;i++) {
1860 cur = table->table[i];
1861 if (!xmlStrcmp(cur->name, name))
1862 return(cur);
1863 }
1864 return(NULL);
1865}
1866
1867/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001868 * xmlValidateNotationUse:
1869 * @ctxt: the validation context
1870 * @doc: the document
1871 * @notationName: the notation name to check
1872 *
1873 * Validate that the given mame match a notation declaration.
1874 * - [ VC: Notation Declared ]
1875 *
1876 * returns 1 if valid or 0 otherwise
1877 */
1878
1879int
1880xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1881 const CHAR *notationName) {
1882 xmlNotationPtr notaDecl;
1883 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1884
1885 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1886 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1887 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1888
1889 if (notaDecl == NULL) {
1890 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1891 notationName);
1892 return(0);
1893 }
1894 return(1);
1895}
1896
1897/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001898 * xmlIsMixedElement
1899 * @doc: the document
1900 * @name: the element name
1901 *
1902 * Search in the DtDs whether an element accept Mixed content (or ANY)
1903 * basically if it is supposed to accept text childs
1904 *
1905 * returns 0 if no, 1 if yes, and -1 if no element description is available
1906 */
1907
1908int
1909xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
1910 xmlElementPtr elemDecl;
1911
1912 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1913
1914 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1915 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1916 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1917 if (elemDecl == NULL) return(-1);
1918 switch (elemDecl->type) {
1919 case XML_ELEMENT_TYPE_ELEMENT:
1920 return(0);
1921 case XML_ELEMENT_TYPE_EMPTY:
1922 /*
1923 * return 1 for EMPTY since we want VC error to pop up
1924 * on <empty> </empty> for example
1925 */
1926 case XML_ELEMENT_TYPE_ANY:
1927 case XML_ELEMENT_TYPE_MIXED:
1928 return(1);
1929 }
1930 return(1);
1931}
1932
1933/**
1934 * xmlValidateNameValue:
1935 * @value: an Name value
1936 *
1937 * Validate that the given value match Name production
1938 *
1939 * returns 1 if valid or 0 otherwise
1940 */
1941
1942int
1943xmlValidateNameValue(const CHAR *value) {
1944 const CHAR *cur;
1945
1946 if (value == NULL) return(0);
1947 cur = value;
1948
1949 if (!IS_LETTER(*cur) && (*cur != '_') &&
1950 (*cur != ':')) {
1951 return(0);
1952 }
1953
1954 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1955 (*cur == '.') || (*cur == '-') ||
1956 (*cur == '_') || (*cur == ':') ||
1957 (IS_COMBINING(*cur)) ||
1958 (IS_EXTENDER(*cur)))
1959 cur++;
1960
1961 if (*cur != 0) return(0);
1962
1963 return(1);
1964}
1965
1966/**
1967 * xmlValidateNamesValue:
1968 * @value: an Names value
1969 *
1970 * Validate that the given value match Names production
1971 *
1972 * returns 1 if valid or 0 otherwise
1973 */
1974
1975int
1976xmlValidateNamesValue(const CHAR *value) {
1977 const CHAR *cur;
1978
1979 if (value == NULL) return(0);
1980 cur = value;
1981
1982 if (!IS_LETTER(*cur) && (*cur != '_') &&
1983 (*cur != ':')) {
1984 return(0);
1985 }
1986
1987 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1988 (*cur == '.') || (*cur == '-') ||
1989 (*cur == '_') || (*cur == ':') ||
1990 (IS_COMBINING(*cur)) ||
1991 (IS_EXTENDER(*cur)))
1992 cur++;
1993
1994 while (IS_BLANK(*cur)) {
1995 while (IS_BLANK(*cur)) cur++;
1996
1997 if (!IS_LETTER(*cur) && (*cur != '_') &&
1998 (*cur != ':')) {
1999 return(0);
2000 }
2001
2002 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2003 (*cur == '.') || (*cur == '-') ||
2004 (*cur == '_') || (*cur == ':') ||
2005 (IS_COMBINING(*cur)) ||
2006 (IS_EXTENDER(*cur)))
2007 cur++;
2008 }
2009
2010 if (*cur != 0) return(0);
2011
2012 return(1);
2013}
2014
2015/**
2016 * xmlValidateNmtokenValue:
2017 * @value: an Mntoken value
2018 *
2019 * Validate that the given value match Nmtoken production
2020 *
2021 * [ VC: Name Token ]
2022 *
2023 * returns 1 if valid or 0 otherwise
2024 */
2025
2026int
2027xmlValidateNmtokenValue(const CHAR *value) {
2028 const CHAR *cur;
2029
2030 if (value == NULL) return(0);
2031 cur = value;
2032
2033 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2034 (*cur != '.') && (*cur != '-') &&
2035 (*cur != '_') && (*cur != ':') &&
2036 (!IS_COMBINING(*cur)) &&
2037 (!IS_EXTENDER(*cur)))
2038 return(0);
2039
2040 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2041 (*cur == '.') || (*cur == '-') ||
2042 (*cur == '_') || (*cur == ':') ||
2043 (IS_COMBINING(*cur)) ||
2044 (IS_EXTENDER(*cur)))
2045 cur++;
2046
2047 if (*cur != 0) return(0);
2048
2049 return(1);
2050 return(1);
2051}
2052
2053/**
2054 * xmlValidateNmtokensValue:
2055 * @value: an Mntokens value
2056 *
2057 * Validate that the given value match Nmtokens production
2058 *
2059 * [ VC: Name Token ]
2060 *
2061 * returns 1 if valid or 0 otherwise
2062 */
2063
2064int
2065xmlValidateNmtokensValue(const CHAR *value) {
2066 const CHAR *cur;
2067
2068 if (value == NULL) return(0);
2069 cur = value;
2070
2071 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2072 (*cur != '.') && (*cur != '-') &&
2073 (*cur != '_') && (*cur != ':') &&
2074 (!IS_COMBINING(*cur)) &&
2075 (!IS_EXTENDER(*cur)))
2076 return(0);
2077
2078 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2079 (*cur == '.') || (*cur == '-') ||
2080 (*cur == '_') || (*cur == ':') ||
2081 (IS_COMBINING(*cur)) ||
2082 (IS_EXTENDER(*cur)))
2083 cur++;
2084
2085 while (IS_BLANK(*cur)) {
2086 while (IS_BLANK(*cur)) cur++;
2087
2088 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2089 (*cur != '.') && (*cur != '-') &&
2090 (*cur != '_') && (*cur != ':') &&
2091 (!IS_COMBINING(*cur)) &&
2092 (!IS_EXTENDER(*cur)))
2093 return(0);
2094
2095 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2096 (*cur == '.') || (*cur == '-') ||
2097 (*cur == '_') || (*cur == ':') ||
2098 (IS_COMBINING(*cur)) ||
2099 (IS_EXTENDER(*cur)))
2100 cur++;
2101 }
2102
2103 if (*cur != 0) return(0);
2104
2105 return(1);
2106}
2107
2108/**
2109 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002110 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002111 * @doc: a document instance
2112 * @nota: a notation definition
2113 *
2114 * Try to validate a single notation definition
2115 * basically it does the following checks as described by the
2116 * XML-1.0 recommendation:
2117 * - it seems that no validity constraing exist on notation declarations
2118 * But this function get called anyway ...
2119 *
2120 * returns 1 if valid or 0 otherwise
2121 */
2122
2123int
2124xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2125 xmlNotationPtr nota) {
2126 int ret = 1;
2127
2128 return(ret);
2129}
2130
2131/**
2132 * xmlValidateAttributeValue:
2133 * @type: an attribute type
2134 * @value: an attribute value
2135 *
2136 * Validate that the given attribute value match the proper production
2137 *
2138 * [ VC: ID ]
2139 * Values of type ID must match the Name production....
2140 *
2141 * [ VC: IDREF ]
2142 * Values of type IDREF must match the Name production, and values
2143 * of type IDREFS must match Names ...
2144 *
2145 * [ VC: Entity Name ]
2146 * Values of type ENTITY must match the Name production, values
2147 * of type ENTITIES must match Names ...
2148 *
2149 * [ VC: Name Token ]
2150 * Values of type NMTOKEN must match the Nmtoken production; values
2151 * of type NMTOKENS must match Nmtokens.
2152 *
2153 * returns 1 if valid or 0 otherwise
2154 */
2155
2156int
2157xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
2158 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002159 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002160 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002161 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002162 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002163 case XML_ATTRIBUTE_IDREF:
2164 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002165 case XML_ATTRIBUTE_NOTATION:
2166 return(xmlValidateNameValue(value));
2167 case XML_ATTRIBUTE_NMTOKENS:
2168 case XML_ATTRIBUTE_ENUMERATION:
2169 return(xmlValidateNmtokensValue(value));
2170 case XML_ATTRIBUTE_NMTOKEN:
2171 return(xmlValidateNmtokenValue(value));
2172 case XML_ATTRIBUTE_CDATA:
2173 break;
2174 }
2175 return(1);
2176}
2177
2178/**
2179 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002180 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002181 * @doc: a document instance
2182 * @attr: an attribute definition
2183 *
2184 * Try to validate a single attribute definition
2185 * basically it does the following checks as described by the
2186 * XML-1.0 recommendation:
2187 * - [ VC: Attribute Default Legal ]
2188 * - [ VC: Enumeration ]
2189 * - [ VC: ID Attribute Default ]
2190 *
2191 * The ID/IDREF uniqueness and matching are done separately
2192 *
2193 * returns 1 if valid or 0 otherwise
2194 */
2195
2196int
2197xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2198 xmlAttributePtr attr) {
2199 int ret = 1;
2200 int val;
2201 CHECK_DTD;
2202 if(attr == NULL) return(1);
2203
2204 /* Attribute Default Legal */
2205 /* Enumeration */
2206 if (attr->defaultValue != NULL) {
2207 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2208 if (val == 0) {
2209 VERROR(ctxt->userData,
2210 "Syntax of default value for attribute %s on %s is not valid\n",
2211 attr->name, attr->elem);
2212 }
2213 ret &= val;
2214 }
2215
2216 /* ID Attribute Default */
2217 if ((attr->type == XML_ATTRIBUTE_ID)&&
2218 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2219 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2220 VERROR(ctxt->userData,
2221 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2222 attr->name, attr->elem);
2223 ret = 0;
2224 }
2225
Daniel Veillardb96e6431999-08-29 21:02:19 +00002226 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002227 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2228 int nbId = 0;
2229
2230 /* the trick is taht we parse DtD as their own internal subset */
2231 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2232 attr->elem);
2233 if (elem != NULL) {
2234 nbId = xmlScanIDAttributeDecl(NULL, elem);
2235 }
2236 if (nbId >= 1)
2237 VERROR(ctxt->userData,
2238 "Element %s has ID attribute defined in the external subset : %s\n",
2239 attr->elem, attr->name);
2240 }
2241
2242 return(ret);
2243}
2244
2245/**
2246 * xmlValidateElementDecl:
2247 * @ctxt: the validation context
2248 * @doc: a document instance
2249 * @elem: an element definition
2250 *
2251 * Try to validate a single element definition
2252 * basically it does the following checks as described by the
2253 * XML-1.0 recommendation:
2254 * - [ VC: One ID per Element Type ]
2255 * - [ VC: No Duplicate Types ]
2256 * - [ VC: Unique Element Type Declaration ]
2257 *
2258 * returns 1 if valid or 0 otherwise
2259 */
2260
2261int
2262xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2263 xmlElementPtr elem) {
2264 int ret = 1;
2265 xmlElementPtr tst;
2266
2267 CHECK_DTD;
2268
2269 if (elem == NULL) return(1);
2270
2271 /* No Duplicate Types */
2272 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2273 xmlElementContentPtr cur, next;
2274 const CHAR *name;
2275
2276 cur = elem->content;
2277 while (cur != NULL) {
2278 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2279 if (cur->c1 == NULL) break;
2280 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2281 name = cur->c1->name;
2282 next = cur->c2;
2283 while (next != NULL) {
2284 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2285 if (!xmlStrcmp(next->name, name)) {
2286 VERROR(ctxt->userData,
2287 "Definition of %s has duplicate references of %s\n",
2288 elem->name, name);
2289 ret = 0;
2290 }
2291 break;
2292 }
2293 if (next->c1 == NULL) break;
2294 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2295 if (!xmlStrcmp(next->c1->name, name)) {
2296 VERROR(ctxt->userData,
2297 "Definition of %s has duplicate references of %s\n",
2298 elem->name, name);
2299 ret = 0;
2300 }
2301 next = next->c2;
2302 }
2303 }
2304 cur = cur->c2;
2305 }
2306 }
2307
2308 /* VC: Unique Element Type Declaration */
2309 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2310 if ((tst != NULL ) && (tst != elem)) {
2311 VERROR(ctxt->userData, "Redefinition of element %s\n",
2312 elem->name);
2313 ret = 0;
2314 }
2315 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2316 if ((tst != NULL ) && (tst != elem)) {
2317 VERROR(ctxt->userData, "Redefinition of element %s\n",
2318 elem->name);
2319 ret = 0;
2320 }
2321
2322 /* One ID per Element Type */
2323 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2324 ret = 0;
2325 }
2326 return(ret);
2327}
2328
2329/**
2330 * xmlValidateOneAttribute:
2331 * @ctxt: the validation context
2332 * @doc: a document instance
2333 * @elem: an element instance
2334 * @attr: an attribute instance
2335 *
2336 * Try to validate a single attribute for an element
2337 * basically it * does the following checks as described by the
2338 * XML-1.0 recommendation:
2339 * - [ VC: Attribute Value Type ]
2340 * - [ VC: Fixed Attribute Default ]
2341 * - [ VC: Entity Name ]
2342 * - [ VC: Name Token ]
2343 * - [ VC: ID ]
2344 * - [ VC: IDREF ]
2345 * - [ VC: Entity Name ]
2346 * - [ VC: Notation Attributes ]
2347 *
2348 * The ID/IDREF uniqueness and matching are done separately
2349 *
2350 * returns 1 if valid or 0 otherwise
2351 */
2352
2353int
2354xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2355 xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002356 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002357 xmlAttributePtr attrDecl;
2358 int val;
2359 int ret = 1;
2360
2361 CHECK_DTD;
2362 if ((elem == NULL) || (elem->name == NULL)) return(0);
2363 if ((attr == NULL) || (attr->name == NULL)) return(0);
2364
2365 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2366 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2367 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2368
2369
2370 /* Validity Constraint: Attribute Value Type */
2371 if (attrDecl == NULL) {
2372 VERROR(ctxt->userData,
2373 "No declaration for attribute %s on element %s\n",
2374 attr->name, elem->name);
2375 return(0);
2376 }
2377 val = xmlValidateAttributeValue(attrDecl->type, value);
2378 if (val == 0) {
2379 VERROR(ctxt->userData,
2380 "Syntax of value for attribute %s on %s is not valid\n",
2381 attr->name, elem->name);
2382 ret = 0;
2383 }
2384
Daniel Veillardb96e6431999-08-29 21:02:19 +00002385 /* Validity Constraint: ID uniqueness */
2386 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2387 xmlAddID(ctxt, doc, value, attr);
2388 }
2389
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002390 if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2391 xmlAddRef(ctxt, doc, value, attr);
2392 }
2393
Daniel Veillardb05deb71999-08-10 19:04:08 +00002394 /* Validity Constraint: Notation Attributes */
2395 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2396 xmlEnumerationPtr tree = attrDecl->tree;
2397 xmlNotationPtr nota;
2398
2399 /* First check that the given NOTATION was declared */
2400 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2401 if (nota == NULL)
2402 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2403
2404 if (nota == NULL) {
2405 VERROR(ctxt->userData,
2406 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2407 value, attr->name, elem->name);
2408 ret = 0;
2409 }
2410
2411 /* Second, verify that it's among the list */
2412 while (tree != NULL) {
2413 if (!xmlStrcmp(tree->name, value)) break;
2414 tree = tree->next;
2415 }
2416 if (tree == NULL) {
2417 VERROR(ctxt->userData,
2418 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2419 value, attr->name, elem->name);
2420 ret = 0;
2421 }
2422 }
2423
2424 /* Validity Constraint: Enumeration */
2425 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2426 xmlEnumerationPtr tree = attrDecl->tree;
2427 while (tree != NULL) {
2428 if (!xmlStrcmp(tree->name, value)) break;
2429 tree = tree->next;
2430 }
2431 if (tree == NULL) {
2432 VERROR(ctxt->userData,
2433 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2434 value, attr->name, elem->name);
2435 ret = 0;
2436 }
2437 }
2438
2439 /* Fixed Attribute Default */
2440 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2441 (xmlStrcmp(attrDecl->defaultValue, value))) {
2442 VERROR(ctxt->userData,
2443 "Value for attribute %s on %s must be \"%s\"\n",
2444 attr->name, elem->name, attrDecl->defaultValue);
2445 ret = 0;
2446 }
2447
Daniel Veillardb96e6431999-08-29 21:02:19 +00002448 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002449 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2450 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2451 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2452 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002453 return(0);
2454 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002455 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002456 return(ret);
2457}
2458
2459int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2460 xmlElementContentPtr cont);
2461
2462/**
2463 * xmlValidateElementTypeExpr:
2464 * @ctxt: the validation context
2465 * @child: pointer to the child list
2466 * @cont: pointer to the content declaration
2467 *
2468 * Try to validate the content of an element of type element
2469 * but don't handle the occurence factor
2470 *
2471 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2472 * also update child value in-situ.
2473 */
2474
2475int
2476xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2477 xmlElementContentPtr cont) {
2478 xmlNodePtr cur;
2479 int ret = 1;
2480
2481 if (cont == NULL) return(-1);
2482 while (*child != NULL) {
2483 if ((*child)->type == XML_PI_NODE) {
2484 *child = (*child)->next;
2485 continue;
2486 }
2487 if ((*child)->type == XML_COMMENT_NODE) {
2488 *child = (*child)->next;
2489 continue;
2490 }
2491 else if ((*child)->type != XML_ELEMENT_NODE) {
2492 return(-1);
2493 }
2494 break;
2495 }
2496 switch (cont->type) {
2497 case XML_ELEMENT_CONTENT_PCDATA:
2498 /* Internal error !!! */
2499 fprintf(stderr, "Internal: MIXED struct bad\n");
2500 return(-1);
2501 case XML_ELEMENT_CONTENT_ELEMENT:
2502 if (*child == NULL) return(0);
2503 ret = (!xmlStrcmp((*child)->name, cont->name));
2504 if (ret == 1)
2505 *child = (*child)->next;
2506 return(ret);
2507 case XML_ELEMENT_CONTENT_OR:
2508 cur = *child;
2509 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2510 if (ret == -1) return(-1);
2511 if (ret == 1) {
2512 return(1);
2513 }
2514 /* rollback and retry the other path */
2515 *child = cur;
2516 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2517 if (ret == -1) return(-1);
2518 if (ret == 0) {
2519 *child = cur;
2520 return(0);
2521 }
2522 return(1);
2523 case XML_ELEMENT_CONTENT_SEQ:
2524 cur = *child;
2525 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2526 if (ret == -1) return(-1);
2527 if (ret == 0) {
2528 *child = cur;
2529 return(0);
2530 }
2531 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2532 if (ret == -1) return(-1);
2533 if (ret == 0) {
2534 *child = cur;
2535 return(0);
2536 }
2537 return(1);
2538 }
2539 return(ret);
2540}
2541
2542/**
2543 * xmlValidateElementTypeElement:
2544 * @ctxt: the validation context
2545 * @child: pointer to the child list
2546 * @cont: pointer to the content declaration
2547 *
2548 * Try to validate the content of an element of type element
2549 * yeah, Yet Another Regexp Implementation, and recursive
2550 *
2551 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2552 * also update child and content values in-situ.
2553 */
2554
2555int
2556xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2557 xmlElementContentPtr cont) {
2558 xmlNodePtr cur;
2559 int ret = 1;
2560
2561 if (cont == NULL) return(-1);
2562 while (*child != NULL) {
2563 if ((*child)->type == XML_PI_NODE) {
2564 *child = (*child)->next;
2565 continue;
2566 }
2567 if ((*child)->type == XML_COMMENT_NODE) {
2568 *child = (*child)->next;
2569 continue;
2570 }
2571 else if ((*child)->type != XML_ELEMENT_NODE) {
2572 return(-1);
2573 }
2574 break;
2575 }
2576 cur = *child;
2577 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2578 if (ret == -1) return(-1);
2579 switch (cont->ocur) {
2580 case XML_ELEMENT_CONTENT_ONCE:
2581 if (ret == 1) {
2582 return(1);
2583 }
2584 *child = cur;
2585 return(0);
2586 case XML_ELEMENT_CONTENT_OPT:
2587 if (ret == 0) {
2588 *child = cur;
2589 return(1);
2590 }
2591 break;
2592 case XML_ELEMENT_CONTENT_MULT:
2593 if (ret == 0) {
2594 *child = cur;
2595 break;
2596 }
2597 /* no break on purpose */
2598 case XML_ELEMENT_CONTENT_PLUS:
2599 if (ret == 0) {
2600 *child = cur;
2601 return(0);
2602 }
2603 do {
2604 cur = *child;
2605 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2606 } while (ret == 1);
2607 if (ret == -1) return(-1);
2608 *child = cur;
2609 break;
2610 }
2611 while (*child != NULL) {
2612 if ((*child)->type == XML_PI_NODE) {
2613 *child = (*child)->next;
2614 continue;
2615 }
2616 if ((*child)->type == XML_COMMENT_NODE) {
2617 *child = (*child)->next;
2618 continue;
2619 }
2620 else if ((*child)->type != XML_ELEMENT_NODE) {
2621 return(-1);
2622 }
2623 break;
2624 }
2625 return(1);
2626}
2627
2628/**
2629 * xmlSprintfElementChilds:
2630 * @buf: an output buffer
2631 * @content: An element
2632 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2633 *
2634 * This will dump the list of childs to the buffer
2635 * Intended just for the debug routine
2636 */
2637void
2638xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2639 xmlNodePtr cur;
2640
2641 if (node == NULL) return;
2642 if (glob) strcat(buf, "(");
2643 cur = node->childs;
2644 while (cur != NULL) {
2645 switch (cur->type) {
2646 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002647 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002648 if (cur->next != NULL)
2649 strcat(buf, " ");
2650 break;
2651 case XML_TEXT_NODE:
2652 case XML_CDATA_SECTION_NODE:
2653 case XML_ENTITY_REF_NODE:
2654 strcat(buf, "CDATA");
2655 if (cur->next != NULL)
2656 strcat(buf, " ");
2657 break;
2658 case XML_ATTRIBUTE_NODE:
2659 case XML_DOCUMENT_NODE:
2660 case XML_DOCUMENT_TYPE_NODE:
2661 case XML_DOCUMENT_FRAG_NODE:
2662 case XML_NOTATION_NODE:
2663 strcat(buf, "???");
2664 if (cur->next != NULL)
2665 strcat(buf, " ");
2666 break;
2667 case XML_ENTITY_NODE:
2668 case XML_PI_NODE:
2669 case XML_COMMENT_NODE:
2670 break;
2671 }
2672 cur = cur->next;
2673 }
2674 if (glob) strcat(buf, ")");
2675}
2676
2677
2678/**
2679 * xmlValidateOneElement:
2680 * @ctxt: the validation context
2681 * @doc: a document instance
2682 * @elem: an element instance
2683 *
2684 * Try to validate a single element and it's attributes,
2685 * basically it does the following checks as described by the
2686 * XML-1.0 recommendation:
2687 * - [ VC: Element Valid ]
2688 * - [ VC: Required Attribute ]
2689 * Then call xmlValidateOneAttribute() for each attribute present.
2690 *
2691 * The ID/IDREF checkings are done separately
2692 *
2693 * returns 1 if valid or 0 otherwise
2694 */
2695
2696int
2697xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2698 xmlNodePtr elem) {
2699 xmlElementPtr elemDecl;
2700 xmlElementContentPtr cont;
2701 xmlNodePtr child;
2702 int ret = 1;
2703 const CHAR *name;
2704
2705 CHECK_DTD;
2706
2707 if ((elem == NULL) || (elem->name == NULL)) return(0);
2708
2709 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2710 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2711 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2712 if (elemDecl == NULL) {
2713 VERROR(ctxt->userData, "No declaration for element %s\n",
2714 elem->name);
2715 return(0);
2716 }
2717
2718 /* Check taht the element content matches the definition */
2719 switch (elemDecl->type) {
2720 case XML_ELEMENT_TYPE_EMPTY:
2721 if (elem->childs != NULL) {
2722 VERROR(ctxt->userData,
2723 "Element %s was declared EMPTY this one has content\n",
2724 elem->name);
2725 ret = 0;
2726 }
2727 break;
2728 case XML_ELEMENT_TYPE_ANY:
2729 /* I don't think anything is required then */
2730 break;
2731 case XML_ELEMENT_TYPE_MIXED:
2732 /* Hum, this start to get messy */
2733 child = elem->childs;
2734 while (child != NULL) {
2735 if (child->type == XML_ELEMENT_NODE) {
2736 name = child->name;
2737 cont = elemDecl->content;
2738 while (cont != NULL) {
2739 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2740 if (!xmlStrcmp(cont->name, name)) break;
2741 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2742 (cont->c1 != NULL) &&
2743 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2744 if (!xmlStrcmp(cont->c1->name, name)) break;
2745 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2746 (cont->c1 == NULL) ||
2747 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2748 /* Internal error !!! */
2749 fprintf(stderr, "Internal: MIXED struct bad\n");
2750 break;
2751 }
2752 cont = cont->c2;
2753 }
2754 if (cont == NULL) {
2755 VERROR(ctxt->userData,
2756 "Element %s is not declared in %s list of possible childs\n",
2757 name, elem->name);
2758 ret = 0;
2759 }
2760 }
2761 child = child->next;
2762 }
2763 break;
2764 case XML_ELEMENT_TYPE_ELEMENT:
2765 child = elem->childs;
2766 cont = elemDecl->content;
2767 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2768 if ((ret == 0) || (child != NULL)) {
2769 char expr[1000];
2770 char list[2000];
2771
2772 expr[0] = 0;
2773 xmlSprintfElementContent(expr, cont, 1);
2774 list[0] = 0;
2775 xmlSprintfElementChilds(list, elem, 1);
2776
2777 VERROR(ctxt->userData,
2778 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2779 elem->name, expr, list);
2780 ret = 0;
2781 }
2782 break;
2783 }
2784
Daniel Veillardb96e6431999-08-29 21:02:19 +00002785 /* TODO - [ VC: Required Attribute ] */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002786 return(ret);
2787}
2788
2789/**
2790 * xmlValidateRoot:
2791 * @ctxt: the validation context
2792 * @doc: a document instance
2793 *
2794 * Try to validate a the root element
2795 * basically it does the following check as described by the
2796 * XML-1.0 recommendation:
2797 * - [ VC: Root Element Type ]
2798 * it doesn't try to recurse or apply other check to the element
2799 *
2800 * returns 1 if valid or 0 otherwise
2801 */
2802
2803int
2804xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2805 if (doc == NULL) return(0);
2806
2807 if ((doc->intSubset == NULL) ||
2808 (doc->intSubset->name == NULL)) {
2809 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2810 return(0);
2811 }
2812 if ((doc->root == NULL) || (doc->root->name == NULL)) {
2813 VERROR(ctxt->userData, "Not valid: no root element\n");
2814 return(0);
2815 }
2816 if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2817 VERROR(ctxt->userData,
2818 "Not valid: root and DtD name do not match %s and %s\n",
2819 doc->root->name, doc->intSubset->name);
2820 return(0);
2821 }
2822 return(1);
2823}
2824
2825
2826/**
2827 * xmlValidateElement:
2828 * @ctxt: the validation context
2829 * @doc: a document instance
2830 * @elem: an element instance
2831 *
2832 * Try to validate the subtree under an element
2833 *
2834 * returns 1 if valid or 0 otherwise
2835 */
2836
2837int
2838xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002839 xmlNodePtr child;
2840 xmlAttrPtr attr;
2841 CHAR *value;
2842 int ret = 1;
2843
2844 /* TODO xmlValidateElement */
2845
2846 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002847 CHECK_DTD;
2848
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002849 ret &= xmlValidateOneElement(ctxt, doc, elem);
2850 attr = elem->properties;
2851 while(attr != NULL) {
2852 value = xmlNodeListGetString(doc, attr->val, 0);
2853 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
2854 if (value != NULL)
2855 free(value);
2856 attr= attr->next;
2857 }
2858 child = elem->childs;
2859 while (child != NULL) {
2860 ret &= xmlValidateElement(ctxt, doc, child);
2861 child = child->next;
2862 }
2863
2864 return(ret);
2865}
2866
2867/**
2868 * xmlValidateDocumentFinal:
2869 * @ctxt: the validation context
2870 * @doc: a document instance
2871 *
2872 * Does the final step for the document validation once all the
2873 * incremental validation steps have been completed
2874 *
2875 * basically it does the following checks described by the XML Rec
2876 *
2877 *
2878 * returns 1 if valid or 0 otherwise
2879 */
2880
2881int
2882xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2883 int ret = 1, i;
2884 xmlRefTablePtr table;
2885 xmlAttrPtr id;
2886
2887 if (doc == NULL) {
2888 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
2889 return(0);
2890 }
2891
2892 /*
2893 * Get the refs table
2894 */
2895 table = doc->refs;
2896 if (table != NULL) {
2897 for (i = 0; i < table->nb_refs; i++) {
2898 id = xmlGetID(doc, table->table[i]->value);
2899 if (id == NULL) {
2900 VERROR(ctxt->userData,
2901 "IDREF attribute %s reference an unknown ID '%s'\n",
2902 table->table[i]->attr->name, table->table[i]->value);
2903 ret = 0;
2904 }
2905 }
2906 }
2907 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002908}
2909
2910/**
2911 * xmlValidateDtd:
2912 * @ctxt: the validation context
2913 * @doc: a document instance
2914 * @dtd: a dtd instance
2915 *
2916 * Try to validate the dtd instance
2917 *
2918 * basically it does check all the definitions in the DtD.
2919 *
2920 * returns 1 if valid or 0 otherwise
2921 */
2922
2923int
2924xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002925 /* TODO xmlValidateDtd */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002926 return(1);
2927}
2928
2929/**
2930 * xmlValidateDocument:
2931 * @ctxt: the validation context
2932 * @doc: a document instance
2933 *
2934 * Try to validate the document instance
2935 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002936 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00002937 * i.e. validates the internal and external subset (if present)
2938 * and validate the document tree.
2939 *
2940 * returns 1 if valid or 0 otherwise
2941 */
2942
2943int
2944xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002945 int ret;
2946
Daniel Veillardb05deb71999-08-10 19:04:08 +00002947 if (!xmlValidateRoot(ctxt, doc)) return(0);
2948
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002949 ret = xmlValidateElement(ctxt, doc, doc->root);
2950 ret &= xmlValidateDocumentFinal(ctxt, doc);
2951 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002952}
2953