blob: 3af1dcd7400625ae0da091c525f3b50ead2503a1 [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
Daniel Veillard7f7d1111999-09-22 09:46:25 +000010#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000011#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000012#else
13#include "config.h"
14#endif
15
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000016#include <stdio.h>
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000017#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018
19#ifdef HAVE_STDLIB_H
20#include <stdlib.h>
21#endif
22
Daniel Veillard6454aec1999-09-02 22:04:43 +000023#include "xmlmemory.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000024#include "valid.h"
25#include "parser.h"
Daniel Veillardb05deb71999-08-10 19:04:08 +000026#include "parserInternals.h"
27
28#define VERROR \
29 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
30
31#define VWARNING \
32 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
33
34#define CHECK_DTD \
35 if (doc == NULL) return(0); \
36 else if (doc->intSubset == NULL) return(0)
37
Daniel Veillarddd6b3671999-09-23 22:19:22 +000038xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
39xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000040
41/****************************************************************
42 * *
43 * Util functions for data allocation/deallocation *
44 * *
45 ****************************************************************/
46
47/**
48 * xmlNewElementContent:
49 * @name: the subelement name or NULL
50 * @type: the type of element content decl
51 *
52 * Allocate an element content structure.
53 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000054 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000055 */
56xmlElementContentPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +000057xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000058 xmlElementContentPtr ret;
59
60 switch(type) {
61 case XML_ELEMENT_CONTENT_ELEMENT:
62 if (name == NULL) {
63 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
64 }
65 break;
66 case XML_ELEMENT_CONTENT_PCDATA:
67 case XML_ELEMENT_CONTENT_SEQ:
68 case XML_ELEMENT_CONTENT_OR:
69 if (name != NULL) {
70 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
71 }
72 break;
73 default:
74 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
75 exit(1);
76 }
Daniel Veillard6454aec1999-09-02 22:04:43 +000077 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000078 if (ret == NULL) {
79 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
80 return(NULL);
81 }
82 ret->type = type;
83 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +000084 if (name != NULL)
85 ret->name = xmlStrdup(name);
86 else
87 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +000088 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000089 return(ret);
90}
91
92/**
Daniel Veillard3b9def11999-01-31 22:15:06 +000093 * xmlCopyElementContent:
94 * @content: An element content pointer.
95 *
96 * Build a copy of an element content description.
97 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000098 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +000099 */
100xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000101xmlCopyElementContent(xmlElementContentPtr cur) {
102 xmlElementContentPtr ret;
103
104 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000105 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +0000106 if (ret == NULL) {
107 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
108 return(NULL);
109 }
110 ret->ocur = cur->ocur;
111 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
112 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000113 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000114}
115
116/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000117 * xmlFreeElementContent:
118 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000119 *
120 * Free an element content structure. This is a recursive call !
121 */
122void
123xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000124 if (cur == NULL) return;
125 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
126 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000127 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000128 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000129 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000130}
131
Daniel Veillard1899e851999-02-01 12:18:54 +0000132/**
133 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000134 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000135 * @content: An element table
136 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
137 *
138 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000139 */
140void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000141xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000142 if (content == NULL) return;
143
Daniel Veillard5099ae81999-04-21 20:12:07 +0000144 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000145 switch (content->type) {
146 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000147 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000148 break;
149 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000150 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000151 break;
152 case XML_ELEMENT_CONTENT_SEQ:
153 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
154 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000155 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000156 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000157 xmlDumpElementContent(buf, content->c1, 0);
158 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000159 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000160 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000161 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000162 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000163 break;
164 case XML_ELEMENT_CONTENT_OR:
165 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
166 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000167 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000168 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000169 xmlDumpElementContent(buf, content->c1, 0);
170 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000171 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000172 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000173 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000174 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000175 break;
176 default:
177 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
178 content->type);
179 }
180 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000181 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000182 switch (content->ocur) {
183 case XML_ELEMENT_CONTENT_ONCE:
184 break;
185 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000186 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000187 break;
188 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000189 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000190 break;
191 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000192 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000193 break;
194 }
195}
196
Daniel Veillardb05deb71999-08-10 19:04:08 +0000197/**
198 * xmlSprintfElementContent:
199 * @buf: an output buffer
200 * @content: An element table
201 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
202 *
203 * This will dump the content of the element content definition
204 * Intended just for the debug routine
205 */
206void
207xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
208 if (content == NULL) return;
209 if (glob) strcat(buf, "(");
210 switch (content->type) {
211 case XML_ELEMENT_CONTENT_PCDATA:
212 strcat(buf, "#PCDATA");
213 break;
214 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000215 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000216 break;
217 case XML_ELEMENT_CONTENT_SEQ:
218 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
219 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
220 xmlSprintfElementContent(buf, content->c1, 1);
221 else
222 xmlSprintfElementContent(buf, content->c1, 0);
223 strcat(buf, " , ");
224 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
225 xmlSprintfElementContent(buf, content->c2, 1);
226 else
227 xmlSprintfElementContent(buf, content->c2, 0);
228 break;
229 case XML_ELEMENT_CONTENT_OR:
230 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
231 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
232 xmlSprintfElementContent(buf, content->c1, 1);
233 else
234 xmlSprintfElementContent(buf, content->c1, 0);
235 strcat(buf, " | ");
236 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
237 xmlSprintfElementContent(buf, content->c2, 1);
238 else
239 xmlSprintfElementContent(buf, content->c2, 0);
240 break;
241 }
242 if (glob)
243 strcat(buf, ")");
244 switch (content->ocur) {
245 case XML_ELEMENT_CONTENT_ONCE:
246 break;
247 case XML_ELEMENT_CONTENT_OPT:
248 strcat(buf, "?");
249 break;
250 case XML_ELEMENT_CONTENT_MULT:
251 strcat(buf, "*");
252 break;
253 case XML_ELEMENT_CONTENT_PLUS:
254 strcat(buf, "+");
255 break;
256 }
257}
258
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000259/****************************************************************
260 * *
261 * Registration of DTD declarations *
262 * *
263 ****************************************************************/
264
Daniel Veillard3b9def11999-01-31 22:15:06 +0000265/**
266 * xmlCreateElementTable:
267 *
268 * create and initialize an empty element hash table.
269 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000270 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000271 */
272xmlElementTablePtr
273xmlCreateElementTable(void) {
274 xmlElementTablePtr ret;
275
276 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000277 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000278 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000279 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000280 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000281 return(NULL);
282 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000283 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000284 ret->nb_elements = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000285 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000286 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000287 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000288 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000289 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000290 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000291 return(NULL);
292 }
293 return(ret);
294}
295
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000296
297/**
298 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000299 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000300 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000301 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000302 * @type: the element type
303 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000304 *
305 * Register a new element declaration
306 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000307 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000308 */
309xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000310xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillard51e3b151999-11-12 17:02:31 +0000311 xmlElementTypeVal type, xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000312 xmlElementPtr ret, cur;
313 xmlElementTablePtr table;
314 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000315
316 if (dtd == NULL) {
317 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
318 return(NULL);
319 }
320 if (name == NULL) {
321 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
322 return(NULL);
323 }
324 switch (type) {
325 case XML_ELEMENT_TYPE_EMPTY:
326 if (content != NULL) {
327 fprintf(stderr,
328 "xmlAddElementDecl: content != NULL for EMPTY\n");
329 return(NULL);
330 }
331 break;
332 case XML_ELEMENT_TYPE_ANY:
333 if (content != NULL) {
334 fprintf(stderr,
335 "xmlAddElementDecl: content != NULL for ANY\n");
336 return(NULL);
337 }
338 break;
339 case XML_ELEMENT_TYPE_MIXED:
340 if (content == NULL) {
341 fprintf(stderr,
342 "xmlAddElementDecl: content == NULL for MIXED\n");
343 return(NULL);
344 }
345 break;
346 case XML_ELEMENT_TYPE_ELEMENT:
347 if (content == NULL) {
348 fprintf(stderr,
349 "xmlAddElementDecl: content == NULL for ELEMENT\n");
350 return(NULL);
351 }
352 break;
353 default:
354 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
355 return(NULL);
356 }
357
358 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000359 * Create the Element table if needed.
360 */
361 table = dtd->elements;
362 if (table == NULL)
363 table = dtd->elements = xmlCreateElementTable();
364 if (table == NULL) {
365 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
366 return(NULL);
367 }
368
369 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000370 * Validity Check:
371 * Search the DTD for previous declarations of the ELEMENT
372 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000373 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000374 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000375 if (!xmlStrcmp(cur->name, name)) {
376 /*
377 * The element is already defined in this Dtd.
378 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000379 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000380 return(NULL);
381 }
382 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000383
384 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000385 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000386 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000387 if (table->nb_elements >= table->max_elements) {
388 /*
389 * need more elements.
390 */
391 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000392 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000393 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000394 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000395 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
396 return(NULL);
397 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000398 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000399 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000400 if (ret == NULL) {
401 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
402 return(NULL);
403 }
404 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000405
406 /*
407 * fill the structure.
408 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000409 ret->type = type;
410 ret->name = xmlStrdup(name);
Daniel Veillard14fff061999-06-22 21:49:07 +0000411 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000412 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000413 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000414
415 return(ret);
416}
417
Daniel Veillard3b9def11999-01-31 22:15:06 +0000418/**
419 * xmlFreeElement:
420 * @elem: An element
421 *
422 * Deallocate the memory used by an element definition
423 */
424void
425xmlFreeElement(xmlElementPtr elem) {
426 if (elem == NULL) return;
427 xmlFreeElementContent(elem->content);
428 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000429 xmlFree((xmlChar *) elem->name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000430 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000431 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000432}
433
434/**
435 * xmlFreeElementTable:
436 * @table: An element table
437 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000438 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000439 */
440void
441xmlFreeElementTable(xmlElementTablePtr table) {
442 int i;
443
444 if (table == NULL) return;
445
446 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000447 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000448 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000449 xmlFree(table->table);
450 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000451}
452
453/**
454 * xmlCopyElementTable:
455 * @table: An element table
456 *
457 * Build a copy of an element table.
458 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000459 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000460 */
461xmlElementTablePtr
462xmlCopyElementTable(xmlElementTablePtr table) {
463 xmlElementTablePtr ret;
464 xmlElementPtr cur, ent;
465 int i;
466
Daniel Veillard6454aec1999-09-02 22:04:43 +0000467 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000468 if (ret == NULL) {
469 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
470 return(NULL);
471 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000472 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000473 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000474 if (ret->table == NULL) {
475 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000476 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000477 return(NULL);
478 }
479 ret->max_elements = table->max_elements;
480 ret->nb_elements = table->nb_elements;
481 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000482 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000483 if (cur == NULL) {
484 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000485 xmlFree(ret);
486 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000487 return(NULL);
488 }
489 ret->table[i] = cur;
490 ent = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000491 cur->type = ent->type;
492 if (ent->name != NULL)
493 cur->name = xmlStrdup(ent->name);
494 else
495 cur->name = NULL;
496 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000497 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000498 }
499 return(ret);
500}
501
502/**
503 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000504 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000505 * @table: An element table
506 *
507 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000508 */
509void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000510xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000511 int i;
512 xmlElementPtr cur;
513
514 if (table == NULL) return;
515
516 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000517 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000518 switch (cur->type) {
519 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000520 xmlBufferWriteChar(buf, "<!ELEMENT ");
521 xmlBufferWriteCHAR(buf, cur->name);
522 xmlBufferWriteChar(buf, " EMPTY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000523 break;
524 case XML_ELEMENT_TYPE_ANY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000525 xmlBufferWriteChar(buf, "<!ELEMENT ");
526 xmlBufferWriteCHAR(buf, cur->name);
527 xmlBufferWriteChar(buf, " ANY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000528 break;
529 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000530 xmlBufferWriteChar(buf, "<!ELEMENT ");
531 xmlBufferWriteCHAR(buf, cur->name);
532 xmlBufferWriteChar(buf, " ");
533 xmlDumpElementContent(buf, cur->content, 1);
534 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000535 break;
536 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000537 xmlBufferWriteChar(buf, "<!ELEMENT ");
538 xmlBufferWriteCHAR(buf, cur->name);
539 xmlBufferWriteChar(buf, " ");
540 xmlDumpElementContent(buf, cur->content, 1);
541 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000542 break;
543 default:
544 fprintf(stderr,
545 "xmlDumpElementTable: internal: unknown type %d\n",
546 cur->type);
547 }
548 }
549}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000550
551/**
552 * xmlCreateEnumeration:
553 * @name: the enumeration name or NULL
554 *
555 * create and initialize an enumeration attribute node.
556 *
557 * Returns the xmlEnumerationPtr just created or NULL in case
558 * of error.
559 */
560xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000561xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000562 xmlEnumerationPtr ret;
563
Daniel Veillard6454aec1999-09-02 22:04:43 +0000564 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000565 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000566 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000567 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000568 return(NULL);
569 }
570
571 if (name != NULL)
572 ret->name = xmlStrdup(name);
573 else
574 ret->name = NULL;
575 ret->next = NULL;
576 return(ret);
577}
578
579/**
580 * xmlFreeEnumeration:
581 * @cur: the tree to free.
582 *
583 * free an enumeration attribute node (recursive).
584 */
585void
586xmlFreeEnumeration(xmlEnumerationPtr cur) {
587 if (cur == NULL) return;
588
589 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
590
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000591 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000592 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000593 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000594}
595
596/**
597 * xmlCopyEnumeration:
598 * @cur: the tree to copy.
599 *
600 * Copy an enumeration attribute node (recursive).
601 *
602 * Returns the xmlEnumerationPtr just created or NULL in case
603 * of error.
604 */
605xmlEnumerationPtr
606xmlCopyEnumeration(xmlEnumerationPtr cur) {
607 xmlEnumerationPtr ret;
608
609 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000610 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000611
612 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
613 else ret->next = NULL;
614
615 return(ret);
616}
617
618/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000619 * xmlDumpEnumeration:
620 * @buf: the XML buffer output
621 * @enum: An enumeration
622 *
623 * This will dump the content of the enumeration
624 */
625void
626xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
627 if (cur == NULL) return;
628
629 xmlBufferWriteCHAR(buf, cur->name);
630 if (cur->next == NULL)
631 xmlBufferWriteChar(buf, ")");
632 else {
633 xmlBufferWriteChar(buf, " | ");
634 xmlDumpEnumeration(buf, cur->next);
635 }
636}
637
638/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000639 * xmlCreateAttributeTable:
640 *
641 * create and initialize an empty attribute hash table.
642 *
643 * Returns the xmlAttributeTablePtr just created or NULL in case
644 * of error.
645 */
646xmlAttributeTablePtr
647xmlCreateAttributeTable(void) {
648 xmlAttributeTablePtr ret;
649
650 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000651 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000652 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000653 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000654 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000655 return(NULL);
656 }
657 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
658 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000659 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000660 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000661 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000662 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000663 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000664 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000665 return(NULL);
666 }
667 return(ret);
668}
669
Daniel Veillardb05deb71999-08-10 19:04:08 +0000670/**
671 * xmlScanAttributeDecl:
672 * @dtd: pointer to the DTD
673 * @elem: the element name
674 *
675 * When inserting a new element scan the DtD for existing attributes
676 * for taht element and initialize the Attribute chain
677 *
678 * Returns the pointer to the first attribute decl in the chain,
679 * possibly NULL.
680 */
681xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000682xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000683 xmlAttributePtr ret = NULL;
684 xmlAttributeTablePtr table;
685 int i;
686
687 if (dtd == NULL) {
688 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
689 return(NULL);
690 }
691 if (elem == NULL) {
692 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
693 return(NULL);
694 }
695 table = dtd->attributes;
696 if (table == NULL)
697 return(NULL);
698
699 for (i = 0;i < table->nb_attributes;i++) {
700 if (!xmlStrcmp(table->table[i]->elem, elem)) {
701 table->table[i]->next = ret;
702 ret = table->table[i];
703 }
704 }
705 return(ret);
706}
707
708/**
709 * xmlScanIDAttributeDecl:
710 * @ctxt: the validation context
711 * @elem: the element name
712 *
713 * Veryfy that the element don't have too many ID attributes
714 * declared.
715 *
716 * Returns the number of ID attributes found.
717 */
718int
719xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
720 xmlAttributePtr cur;
721 int ret = 0;
722
723 if (elem == NULL) return(0);
724 cur = elem->attributes;
725 while (cur != NULL) {
726 if (cur->type == XML_ATTRIBUTE_ID) {
727 ret ++;
728 if (ret > 1)
729 VERROR(ctxt->userData,
730 "Element %s has too may ID attributes defined : %s\n",
731 elem->name, cur->name);
732 }
733 cur = cur->next;
734 }
735 return(ret);
736}
737
Daniel Veillard1e346af1999-02-22 10:33:01 +0000738
739/**
740 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000741 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000742 * @dtd: pointer to the DTD
743 * @elem: the element name
744 * @name: the attribute name
745 * @type: the attribute type
746 * @def: the attribute default type
747 * @defaultValue: the attribute default value
748 * @tree: if it's an enumeration, the associated list
749 *
750 * Register a new attribute declaration
751 *
752 * Returns NULL if not, othervise the entity
753 */
754xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000755xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
756 const xmlChar *name, xmlAttributeType type,
757 xmlAttributeDefault def, const xmlChar *defaultValue,
Daniel Veillardc26087b1999-08-30 11:23:51 +0000758 xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000759 xmlAttributePtr ret, cur;
760 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000761 xmlElementPtr elemDef;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000762 xmlChar *rname;
763 xmlChar *ns;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000764 int i;
765
766 if (dtd == NULL) {
767 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
768 return(NULL);
769 }
770 if (name == NULL) {
771 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
772 return(NULL);
773 }
774 if (elem == NULL) {
775 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
776 return(NULL);
777 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000778 /*
779 * Check the type and possibly the default value.
780 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000781 switch (type) {
782 case XML_ATTRIBUTE_CDATA:
783 break;
784 case XML_ATTRIBUTE_ID:
785 break;
786 case XML_ATTRIBUTE_IDREF:
787 break;
788 case XML_ATTRIBUTE_IDREFS:
789 break;
790 case XML_ATTRIBUTE_ENTITY:
791 break;
792 case XML_ATTRIBUTE_ENTITIES:
793 break;
794 case XML_ATTRIBUTE_NMTOKEN:
795 break;
796 case XML_ATTRIBUTE_NMTOKENS:
797 break;
798 case XML_ATTRIBUTE_ENUMERATION:
799 break;
800 case XML_ATTRIBUTE_NOTATION:
801 break;
802 default:
803 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
804 return(NULL);
805 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000806 if ((defaultValue != NULL) &&
807 (!xmlValidateAttributeValue(type, defaultValue))) {
808 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
809 elem, name, defaultValue);
810 defaultValue = NULL;
811 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000812
813 /*
814 * Create the Attribute table if needed.
815 */
816 table = dtd->attributes;
817 if (table == NULL)
818 table = dtd->attributes = xmlCreateAttributeTable();
819 if (table == NULL) {
820 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
821 return(NULL);
822 }
823
824 /*
Daniel Veillard10a2c651999-12-12 13:03:50 +0000825 * Split the full name into a namespace prefix and the tag name
826 */
827 rname = xmlSplitQName(name, &ns);
828
829 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +0000830 * Validity Check:
831 * Search the DTD for previous declarations of the ATTLIST
832 */
833 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000834 cur = table->table[i];
Daniel Veillard10a2c651999-12-12 13:03:50 +0000835 if ((ns != NULL) && (cur->prefix == NULL)) continue;
836 if ((ns == NULL) && (cur->prefix != NULL)) continue;
837 if ((!xmlStrcmp(cur->name, rname)) && (!xmlStrcmp(cur->elem, elem)) &&
838 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000839 /*
840 * The attribute is already defined in this Dtd.
841 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000842 VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
843 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000844 }
845 }
846
847 /*
848 * Grow the table, if needed.
849 */
850 if (table->nb_attributes >= table->max_attributes) {
851 /*
852 * need more attributes.
853 */
854 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000855 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000856 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000857 sizeof(xmlAttributePtr));
858 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000859 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
860 return(NULL);
861 }
862 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000863 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000864 if (ret == NULL) {
865 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
866 return(NULL);
867 }
868 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000869
870 /*
871 * fill the structure.
872 */
873 ret->type = type;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000874 ret->name = rname;
875 ret->prefix = ns;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000876 ret->elem = xmlStrdup(elem);
877 ret->def = def;
878 ret->tree = tree;
879 if (defaultValue != NULL)
880 ret->defaultValue = xmlStrdup(defaultValue);
881 else
882 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000883 elemDef = xmlGetDtdElementDesc(dtd, elem);
884 if (elemDef != NULL) {
885 if ((type == XML_ATTRIBUTE_ID) &&
886 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
887 VERROR(ctxt->userData,
888 "Element %s has too may ID attributes defined : %s\n",
889 elem, name);
890 ret->next = elemDef->attributes;
891 elemDef->attributes = ret;
892 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000893 table->nb_attributes++;
894
895 return(ret);
896}
897
898/**
899 * xmlFreeAttribute:
900 * @elem: An attribute
901 *
902 * Deallocate the memory used by an attribute definition
903 */
904void
905xmlFreeAttribute(xmlAttributePtr attr) {
906 if (attr == NULL) return;
907 if (attr->tree != NULL)
908 xmlFreeEnumeration(attr->tree);
909 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000910 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000911 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000912 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000913 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000914 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +0000915 if (attr->prefix != NULL)
916 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000917 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000918 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000919}
920
921/**
922 * xmlFreeAttributeTable:
923 * @table: An attribute table
924 *
925 * Deallocate the memory used by an entities hash table.
926 */
927void
928xmlFreeAttributeTable(xmlAttributeTablePtr table) {
929 int i;
930
931 if (table == NULL) return;
932
933 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000934 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000935 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000936 xmlFree(table->table);
937 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000938}
939
940/**
941 * xmlCopyAttributeTable:
942 * @table: An attribute table
943 *
944 * Build a copy of an attribute table.
945 *
946 * Returns the new xmlAttributeTablePtr or NULL in case of error.
947 */
948xmlAttributeTablePtr
949xmlCopyAttributeTable(xmlAttributeTablePtr table) {
950 xmlAttributeTablePtr ret;
951 xmlAttributePtr cur, attr;
952 int i;
953
Daniel Veillard6454aec1999-09-02 22:04:43 +0000954 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000955 if (ret == NULL) {
956 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
957 return(NULL);
958 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000959 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000960 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000961 if (ret->table == NULL) {
962 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000963 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000964 return(NULL);
965 }
966 ret->max_attributes = table->max_attributes;
967 ret->nb_attributes = table->nb_attributes;
968 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000969 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +0000970 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000971 if (cur == NULL) {
972 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000973 xmlFree(ret);
974 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000975 return(NULL);
976 }
977 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000978 cur->type = attr->type;
979 cur->def = attr->def;
980 cur->tree = xmlCopyEnumeration(attr->tree);
981 if (attr->elem != NULL)
982 cur->elem = xmlStrdup(attr->elem);
983 else
984 cur->elem = NULL;
985 if (attr->name != NULL)
986 cur->name = xmlStrdup(attr->name);
987 else
988 cur->name = NULL;
989 if (attr->defaultValue != NULL)
990 cur->defaultValue = xmlStrdup(attr->defaultValue);
991 else
992 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000993 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000994 }
995 return(ret);
996}
997
998/**
999 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001000 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001001 * @table: An attribute table
1002 *
1003 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001004 */
1005void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001006xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001007 int i;
1008 xmlAttributePtr cur;
1009
1010 if (table == NULL) return;
1011
1012 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001013 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001014 xmlBufferWriteChar(buf, "<!ATTLIST ");
1015 xmlBufferWriteCHAR(buf, cur->elem);
1016 xmlBufferWriteChar(buf, " ");
1017 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001018 switch (cur->type) {
1019 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001020 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001021 break;
1022 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001023 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001024 break;
1025 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001026 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001027 break;
1028 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001029 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001030 break;
1031 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001032 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001033 break;
1034 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001035 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001036 break;
1037 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001038 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001039 break;
1040 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001041 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001042 break;
1043 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001044 xmlBufferWriteChar(buf, " (");
1045 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001046 break;
1047 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001048 xmlBufferWriteChar(buf, " NOTATION (");
1049 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001050 break;
1051 default:
1052 fprintf(stderr,
1053 "xmlDumpAttributeTable: internal: unknown type %d\n",
1054 cur->type);
1055 }
1056 switch (cur->def) {
1057 case XML_ATTRIBUTE_NONE:
1058 break;
1059 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001060 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001061 break;
1062 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001063 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001064 break;
1065 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001066 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001067 break;
1068 default:
1069 fprintf(stderr,
1070 "xmlDumpAttributeTable: internal: unknown default %d\n",
1071 cur->def);
1072 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001073 if (cur->defaultValue != NULL) {
1074 xmlBufferWriteChar(buf, " ");
1075 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1076 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001077 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001078 }
1079}
1080
1081/************************************************************************
1082 * *
1083 * NOTATIONs *
1084 * *
1085 ************************************************************************/
1086/**
1087 * xmlCreateNotationTable:
1088 *
1089 * create and initialize an empty notation hash table.
1090 *
1091 * Returns the xmlNotationTablePtr just created or NULL in case
1092 * of error.
1093 */
1094xmlNotationTablePtr
1095xmlCreateNotationTable(void) {
1096 xmlNotationTablePtr ret;
1097
1098 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001099 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001100 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001101 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001102 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001103 return(NULL);
1104 }
1105 ret->max_notations = XML_MIN_NOTATION_TABLE;
1106 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001107 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001108 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001109 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001110 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001111 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001112 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001113 return(NULL);
1114 }
1115 return(ret);
1116}
1117
1118
1119/**
1120 * xmlAddNotationDecl:
1121 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001122 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001123 * @name: the entity name
1124 * @PublicID: the public identifier or NULL
1125 * @SystemID: the system identifier or NULL
1126 *
1127 * Register a new notation declaration
1128 *
1129 * Returns NULL if not, othervise the entity
1130 */
1131xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001132xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1133 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001134 xmlNotationPtr ret, cur;
1135 xmlNotationTablePtr table;
1136 int i;
1137
1138 if (dtd == NULL) {
1139 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1140 return(NULL);
1141 }
1142 if (name == NULL) {
1143 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1144 return(NULL);
1145 }
1146 if ((PublicID == NULL) && (SystemID == NULL)) {
1147 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1148 }
1149
1150 /*
1151 * Create the Notation table if needed.
1152 */
1153 table = dtd->notations;
1154 if (table == NULL)
1155 table = dtd->notations = xmlCreateNotationTable();
1156 if (table == NULL) {
1157 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1158 return(NULL);
1159 }
1160
1161 /*
1162 * Validity Check:
1163 * Search the DTD for previous declarations of the ATTLIST
1164 */
1165 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001166 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001167 if (!xmlStrcmp(cur->name, name)) {
1168 /*
1169 * The notation is already defined in this Dtd.
1170 */
1171 fprintf(stderr,
1172 "xmlAddNotationDecl: %s already defined\n", name);
1173 }
1174 }
1175
1176 /*
1177 * Grow the table, if needed.
1178 */
1179 if (table->nb_notations >= table->max_notations) {
1180 /*
1181 * need more notations.
1182 */
1183 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001184 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001185 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001186 sizeof(xmlNotationPtr));
1187 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001188 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1189 return(NULL);
1190 }
1191 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001192 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001193 if (ret == NULL) {
1194 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1195 return(NULL);
1196 }
1197 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001198
1199 /*
1200 * fill the structure.
1201 */
1202 ret->name = xmlStrdup(name);
1203 if (SystemID != NULL)
1204 ret->SystemID = xmlStrdup(SystemID);
1205 else
1206 ret->SystemID = NULL;
1207 if (PublicID != NULL)
1208 ret->PublicID = xmlStrdup(PublicID);
1209 else
1210 ret->PublicID = NULL;
1211 table->nb_notations++;
1212
1213 return(ret);
1214}
1215
1216/**
1217 * xmlFreeNotation:
1218 * @not: A notation
1219 *
1220 * Deallocate the memory used by an notation definition
1221 */
1222void
1223xmlFreeNotation(xmlNotationPtr nota) {
1224 if (nota == NULL) return;
1225 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001226 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001227 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001228 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001229 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001230 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001231 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001232 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001233}
1234
1235/**
1236 * xmlFreeNotationTable:
1237 * @table: An notation table
1238 *
1239 * Deallocate the memory used by an entities hash table.
1240 */
1241void
1242xmlFreeNotationTable(xmlNotationTablePtr table) {
1243 int i;
1244
1245 if (table == NULL) return;
1246
1247 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001248 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001249 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001250 xmlFree(table->table);
1251 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001252}
1253
1254/**
1255 * xmlCopyNotationTable:
1256 * @table: A notation table
1257 *
1258 * Build a copy of a notation table.
1259 *
1260 * Returns the new xmlNotationTablePtr or NULL in case of error.
1261 */
1262xmlNotationTablePtr
1263xmlCopyNotationTable(xmlNotationTablePtr table) {
1264 xmlNotationTablePtr ret;
1265 xmlNotationPtr cur, nota;
1266 int i;
1267
Daniel Veillard6454aec1999-09-02 22:04:43 +00001268 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001269 if (ret == NULL) {
1270 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1271 return(NULL);
1272 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001273 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001274 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001275 if (ret->table == NULL) {
1276 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001277 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001278 return(NULL);
1279 }
1280 ret->max_notations = table->max_notations;
1281 ret->nb_notations = table->nb_notations;
1282 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001283 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001284 if (cur == NULL) {
1285 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001286 xmlFree(ret);
1287 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001288 return(NULL);
1289 }
1290 ret->table[i] = cur;
1291 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001292 if (nota->name != NULL)
1293 cur->name = xmlStrdup(nota->name);
1294 else
1295 cur->name = NULL;
1296 if (nota->PublicID != NULL)
1297 cur->PublicID = xmlStrdup(nota->PublicID);
1298 else
1299 cur->PublicID = NULL;
1300 if (nota->SystemID != NULL)
1301 cur->SystemID = xmlStrdup(nota->SystemID);
1302 else
1303 cur->SystemID = NULL;
1304 }
1305 return(ret);
1306}
1307
1308/**
1309 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001310 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001311 * @table: A notation table
1312 *
1313 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001314 */
1315void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001316xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001317 int i;
1318 xmlNotationPtr cur;
1319
1320 if (table == NULL) return;
1321
1322 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001323 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001324 xmlBufferWriteChar(buf, "<!NOTATION ");
1325 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001326 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001327 xmlBufferWriteChar(buf, " PUBLIC ");
1328 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001329 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001330 xmlBufferWriteChar(buf, " ");
1331 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001332 }
1333 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001334 xmlBufferWriteChar(buf, " SYSTEM ");
1335 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001336 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001337 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001338 }
1339}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001340
1341/************************************************************************
1342 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001343 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001344 * *
1345 ************************************************************************/
1346/**
1347 * xmlCreateIDTable:
1348 *
1349 * create and initialize an empty id hash table.
1350 *
1351 * Returns the xmlIDTablePtr just created or NULL in case
1352 * of error.
1353 */
1354xmlIDTablePtr
1355xmlCreateIDTable(void) {
1356 xmlIDTablePtr ret;
1357
1358 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001359 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001360 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001361 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001362 (long)sizeof(xmlIDTable));
1363 return(NULL);
1364 }
1365 ret->max_ids = XML_MIN_NOTATION_TABLE;
1366 ret->nb_ids = 0;
1367 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001368 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001369 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001370 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001371 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001372 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001373 return(NULL);
1374 }
1375 return(ret);
1376}
1377
1378
1379/**
1380 * xmlAddID:
1381 * @ctxt: the validation context
1382 * @doc: pointer to the document
1383 * @value: the value name
1384 * @attr: the attribute holding the ID
1385 *
1386 * Register a new id declaration
1387 *
1388 * Returns NULL if not, othervise the new xmlIDPtr
1389 */
1390xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001391xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001392 xmlAttrPtr attr) {
1393 xmlIDPtr ret, cur;
1394 xmlIDTablePtr table;
1395 int i;
1396
1397 if (doc == NULL) {
1398 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1399 return(NULL);
1400 }
1401 if (value == NULL) {
1402 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1403 return(NULL);
1404 }
1405 if (attr == NULL) {
1406 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1407 return(NULL);
1408 }
1409
1410 /*
1411 * Create the ID table if needed.
1412 */
1413 table = doc->ids;
1414 if (table == NULL)
1415 table = doc->ids = xmlCreateIDTable();
1416 if (table == NULL) {
1417 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1418 return(NULL);
1419 }
1420
1421 /*
1422 * Validity Check:
1423 * Search the DTD for previous declarations of the ATTLIST
1424 */
1425 for (i = 0;i < table->nb_ids;i++) {
1426 cur = table->table[i];
1427 if (!xmlStrcmp(cur->value, value)) {
1428 /*
1429 * The id is already defined in this Dtd.
1430 */
1431 VERROR(ctxt->userData, "ID %s already defined\n", value);
1432 return(NULL);
1433 }
1434 }
1435
1436 /*
1437 * Grow the table, if needed.
1438 */
1439 if (table->nb_ids >= table->max_ids) {
1440 /*
1441 * need more ids.
1442 */
1443 table->max_ids *= 2;
1444 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001445 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001446 sizeof(xmlIDPtr));
1447 if (table->table == NULL) {
1448 fprintf(stderr, "xmlAddID: out of memory\n");
1449 return(NULL);
1450 }
1451 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001452 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001453 if (ret == NULL) {
1454 fprintf(stderr, "xmlAddID: out of memory\n");
1455 return(NULL);
1456 }
1457 table->table[table->nb_ids] = ret;
1458
1459 /*
1460 * fill the structure.
1461 */
1462 ret->value = xmlStrdup(value);
1463 ret->attr = attr;
1464 table->nb_ids++;
1465
1466 return(ret);
1467}
1468
1469/**
1470 * xmlFreeID:
1471 * @not: A id
1472 *
1473 * Deallocate the memory used by an id definition
1474 */
1475void
1476xmlFreeID(xmlIDPtr id) {
1477 if (id == NULL) return;
1478 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001479 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001480 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001481 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001482}
1483
1484/**
1485 * xmlFreeIDTable:
1486 * @table: An id table
1487 *
1488 * Deallocate the memory used by an ID hash table.
1489 */
1490void
1491xmlFreeIDTable(xmlIDTablePtr table) {
1492 int i;
1493
1494 if (table == NULL) return;
1495
1496 for (i = 0;i < table->nb_ids;i++) {
1497 xmlFreeID(table->table[i]);
1498 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001499 xmlFree(table->table);
1500 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001501}
1502
1503/**
1504 * xmlIsID
1505 * @doc: the document
1506 * @elem: the element carrying the attribute
1507 * @attr: the attribute
1508 *
1509 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1510 * then this is simple, otherwise we use an heuristic: name ID (upper
1511 * or lowercase).
1512 *
1513 * Returns 0 or 1 depending on the lookup result
1514 */
1515int
1516xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1517 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1518 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1519 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1520 (attr->name[2] == 0)) return(1);
1521 } else {
1522 xmlAttributePtr attrDecl;
1523
1524 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1525 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1526 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1527 attr->name);
1528
Daniel Veillardb96e6431999-08-29 21:02:19 +00001529 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001530 return(1);
1531 }
1532 return(0);
1533}
1534
Daniel Veillardb96e6431999-08-29 21:02:19 +00001535/**
1536 * xmlGetID:
1537 * @doc: pointer to the document
1538 * @ID: the ID value
1539 *
1540 * Search the attribute declaring the given ID
1541 *
1542 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1543 */
1544xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001545xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001546 xmlIDPtr cur;
1547 xmlIDTablePtr table;
1548 int i;
1549
1550 if (doc == NULL) {
1551 fprintf(stderr, "xmlGetID: doc == NULL\n");
1552 return(NULL);
1553 }
1554
1555 if (ID == NULL) {
1556 fprintf(stderr, "xmlGetID: ID == NULL\n");
1557 return(NULL);
1558 }
1559
1560 table = doc->ids;
1561 if (table == NULL)
1562 return(NULL);
1563
1564 /*
1565 * Search the ID list.
1566 */
1567 for (i = 0;i < table->nb_ids;i++) {
1568 cur = table->table[i];
1569 if (!xmlStrcmp(cur->value, ID)) {
1570 return(cur->attr);
1571 }
1572 }
1573 return(NULL);
1574}
1575
Daniel Veillard991e63d1999-08-15 23:32:28 +00001576/************************************************************************
1577 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001578 * Refs *
1579 * *
1580 ************************************************************************/
1581/**
1582 * xmlCreateRefTable:
1583 *
1584 * create and initialize an empty ref hash table.
1585 *
1586 * Returns the xmlRefTablePtr just created or NULL in case
1587 * of error.
1588 */
1589xmlRefTablePtr
1590xmlCreateRefTable(void) {
1591 xmlRefTablePtr ret;
1592
1593 ret = (xmlRefTablePtr)
1594 xmlMalloc(sizeof(xmlRefTable));
1595 if (ret == NULL) {
1596 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1597 (long)sizeof(xmlRefTable));
1598 return(NULL);
1599 }
1600 ret->max_refs = XML_MIN_NOTATION_TABLE;
1601 ret->nb_refs = 0;
1602 ret->table = (xmlRefPtr *)
1603 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1604 if (ret == NULL) {
1605 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1606 ret->max_refs * (long)sizeof(xmlRef));
1607 xmlFree(ret);
1608 return(NULL);
1609 }
1610 return(ret);
1611}
1612
1613
1614/**
1615 * xmlAddRef:
1616 * @ctxt: the validation context
1617 * @doc: pointer to the document
1618 * @value: the value name
1619 * @attr: the attribute holding the Ref
1620 *
1621 * Register a new ref declaration
1622 *
1623 * Returns NULL if not, othervise the new xmlRefPtr
1624 */
1625xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001626xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001627 xmlAttrPtr attr) {
1628 xmlRefPtr ret;
1629 xmlRefTablePtr table;
1630
1631 if (doc == NULL) {
1632 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1633 return(NULL);
1634 }
1635 if (value == NULL) {
1636 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1637 return(NULL);
1638 }
1639 if (attr == NULL) {
1640 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1641 return(NULL);
1642 }
1643
1644 /*
1645 * Create the Ref table if needed.
1646 */
1647 table = doc->refs;
1648 if (table == NULL)
1649 table = doc->refs = xmlCreateRefTable();
1650 if (table == NULL) {
1651 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1652 return(NULL);
1653 }
1654
1655 /*
1656 * Grow the table, if needed.
1657 */
1658 if (table->nb_refs >= table->max_refs) {
1659 /*
1660 * need more refs.
1661 */
1662 table->max_refs *= 2;
1663 table->table = (xmlRefPtr *)
1664 xmlRealloc(table->table, table->max_refs *
1665 sizeof(xmlRefPtr));
1666 if (table->table == NULL) {
1667 fprintf(stderr, "xmlAddRef: out of memory\n");
1668 return(NULL);
1669 }
1670 }
1671 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1672 if (ret == NULL) {
1673 fprintf(stderr, "xmlAddRef: out of memory\n");
1674 return(NULL);
1675 }
1676 table->table[table->nb_refs] = ret;
1677
1678 /*
1679 * fill the structure.
1680 */
1681 ret->value = xmlStrdup(value);
1682 ret->attr = attr;
1683 table->nb_refs++;
1684
1685 return(ret);
1686}
1687
1688/**
1689 * xmlFreeRef:
1690 * @not: A ref
1691 *
1692 * Deallocate the memory used by an ref definition
1693 */
1694void
1695xmlFreeRef(xmlRefPtr ref) {
1696 if (ref == NULL) return;
1697 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001698 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001699 memset(ref, -1, sizeof(xmlRef));
1700 xmlFree(ref);
1701}
1702
1703/**
1704 * xmlFreeRefTable:
1705 * @table: An ref table
1706 *
1707 * Deallocate the memory used by an Ref hash table.
1708 */
1709void
1710xmlFreeRefTable(xmlRefTablePtr table) {
1711 int i;
1712
1713 if (table == NULL) return;
1714
1715 for (i = 0;i < table->nb_refs;i++) {
1716 xmlFreeRef(table->table[i]);
1717 }
1718 xmlFree(table->table);
1719 xmlFree(table);
1720}
1721
1722/**
1723 * xmlIsRef
1724 * @doc: the document
1725 * @elem: the element carrying the attribute
1726 * @attr: the attribute
1727 *
1728 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1729 * then this is simple, otherwise we use an heuristic: name Ref (upper
1730 * or lowercase).
1731 *
1732 * Returns 0 or 1 depending on the lookup result
1733 */
1734int
1735xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1736 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1737 return(0);
1738 /*******************
1739 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1740 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1741 (attr->name[2] == 0)) return(1);
1742 *******************/
1743 } else {
1744 xmlAttributePtr attrDecl;
1745
1746 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1747 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1748 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1749 attr->name);
1750
1751 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1752 return(1);
1753 }
1754 return(0);
1755}
1756
1757/**
1758 * xmlGetRef:
1759 * @doc: pointer to the document
1760 * @Ref: the Ref value
1761 *
1762 * Search the attribute declaring the given Ref
1763 *
1764 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1765 */
1766xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001767xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001768 xmlRefPtr cur;
1769 xmlRefTablePtr table;
1770 int i;
1771
1772 if (doc == NULL) {
1773 fprintf(stderr, "xmlGetRef: doc == NULL\n");
1774 return(NULL);
1775 }
1776
1777 if (Ref == NULL) {
1778 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1779 return(NULL);
1780 }
1781
1782 table = doc->refs;
1783 if (table == NULL)
1784 return(NULL);
1785
1786 /*
1787 * Search the Ref list.
1788 */
1789 for (i = 0;i < table->nb_refs;i++) {
1790 cur = table->table[i];
1791 if (!xmlStrcmp(cur->value, Ref)) {
1792 return(cur->attr);
1793 }
1794 }
1795 return(NULL);
1796}
1797
1798/************************************************************************
1799 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001800 * Routines for validity checking *
1801 * *
1802 ************************************************************************/
1803
1804/**
1805 * xmlGetDtdElementDesc:
1806 * @dtd: a pointer to the DtD to search
1807 * @name: the element name
1808 *
1809 * Search the Dtd for the description of this element
1810 *
1811 * returns the xmlElementPtr if found or NULL
1812 */
1813
1814xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001815xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001816 xmlElementTablePtr table;
1817 xmlElementPtr cur;
1818 int i;
1819
1820 if (dtd == NULL) return(NULL);
1821 if (dtd->elements == NULL) return(NULL);
1822 table = dtd->elements;
1823
1824 for (i = 0;i < table->nb_elements;i++) {
1825 cur = table->table[i];
1826 if (!xmlStrcmp(cur->name, name))
1827 return(cur);
1828 }
1829 return(NULL);
1830}
1831
1832/**
1833 * xmlGetDtdAttrDesc:
1834 * @dtd: a pointer to the DtD to search
1835 * @elem: the element name
1836 * @name: the attribute name
1837 *
1838 * Search the Dtd for the description of this attribute on
1839 * this element.
1840 *
1841 * returns the xmlAttributePtr if found or NULL
1842 */
1843
1844xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001845xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001846 xmlAttributeTablePtr table;
1847 xmlAttributePtr cur;
1848 int i;
1849
1850 if (dtd == NULL) return(NULL);
1851 if (dtd->attributes == NULL) return(NULL);
1852 table = dtd->attributes;
1853
1854 for (i = 0;i < table->nb_attributes;i++) {
1855 cur = table->table[i];
1856 if ((!xmlStrcmp(cur->name, name)) &&
1857 (!xmlStrcmp(cur->elem, elem)))
1858 return(cur);
1859 }
1860 return(NULL);
1861}
1862
1863/**
1864 * xmlGetDtdNotationDesc:
1865 * @dtd: a pointer to the DtD to search
1866 * @name: the notation name
1867 *
1868 * Search the Dtd for the description of this notation
1869 *
1870 * returns the xmlNotationPtr if found or NULL
1871 */
1872
1873xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001874xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001875 xmlNotationTablePtr table;
1876 xmlNotationPtr cur;
1877 int i;
1878
1879 if (dtd == NULL) return(NULL);
1880 if (dtd->notations == NULL) return(NULL);
1881 table = dtd->notations;
1882
1883 for (i = 0;i < table->nb_notations;i++) {
1884 cur = table->table[i];
1885 if (!xmlStrcmp(cur->name, name))
1886 return(cur);
1887 }
1888 return(NULL);
1889}
1890
1891/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001892 * xmlValidateNotationUse:
1893 * @ctxt: the validation context
1894 * @doc: the document
1895 * @notationName: the notation name to check
1896 *
1897 * Validate that the given mame match a notation declaration.
1898 * - [ VC: Notation Declared ]
1899 *
1900 * returns 1 if valid or 0 otherwise
1901 */
1902
1903int
1904xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001905 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001906 xmlNotationPtr notaDecl;
1907 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1908
1909 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1910 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1911 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1912
1913 if (notaDecl == NULL) {
1914 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1915 notationName);
1916 return(0);
1917 }
1918 return(1);
1919}
1920
1921/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001922 * xmlIsMixedElement
1923 * @doc: the document
1924 * @name: the element name
1925 *
1926 * Search in the DtDs whether an element accept Mixed content (or ANY)
1927 * basically if it is supposed to accept text childs
1928 *
1929 * returns 0 if no, 1 if yes, and -1 if no element description is available
1930 */
1931
1932int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001933xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001934 xmlElementPtr elemDecl;
1935
1936 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1937
1938 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1939 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1940 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1941 if (elemDecl == NULL) return(-1);
1942 switch (elemDecl->type) {
1943 case XML_ELEMENT_TYPE_ELEMENT:
1944 return(0);
1945 case XML_ELEMENT_TYPE_EMPTY:
1946 /*
1947 * return 1 for EMPTY since we want VC error to pop up
1948 * on <empty> </empty> for example
1949 */
1950 case XML_ELEMENT_TYPE_ANY:
1951 case XML_ELEMENT_TYPE_MIXED:
1952 return(1);
1953 }
1954 return(1);
1955}
1956
1957/**
1958 * xmlValidateNameValue:
1959 * @value: an Name value
1960 *
1961 * Validate that the given value match Name production
1962 *
1963 * returns 1 if valid or 0 otherwise
1964 */
1965
1966int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001967xmlValidateNameValue(const xmlChar *value) {
1968 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001969
1970 if (value == NULL) return(0);
1971 cur = value;
1972
1973 if (!IS_LETTER(*cur) && (*cur != '_') &&
1974 (*cur != ':')) {
1975 return(0);
1976 }
1977
1978 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1979 (*cur == '.') || (*cur == '-') ||
1980 (*cur == '_') || (*cur == ':') ||
1981 (IS_COMBINING(*cur)) ||
1982 (IS_EXTENDER(*cur)))
1983 cur++;
1984
1985 if (*cur != 0) return(0);
1986
1987 return(1);
1988}
1989
1990/**
1991 * xmlValidateNamesValue:
1992 * @value: an Names value
1993 *
1994 * Validate that the given value match Names production
1995 *
1996 * returns 1 if valid or 0 otherwise
1997 */
1998
1999int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002000xmlValidateNamesValue(const xmlChar *value) {
2001 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002002
2003 if (value == NULL) return(0);
2004 cur = value;
2005
2006 if (!IS_LETTER(*cur) && (*cur != '_') &&
2007 (*cur != ':')) {
2008 return(0);
2009 }
2010
2011 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2012 (*cur == '.') || (*cur == '-') ||
2013 (*cur == '_') || (*cur == ':') ||
2014 (IS_COMBINING(*cur)) ||
2015 (IS_EXTENDER(*cur)))
2016 cur++;
2017
2018 while (IS_BLANK(*cur)) {
2019 while (IS_BLANK(*cur)) cur++;
2020
2021 if (!IS_LETTER(*cur) && (*cur != '_') &&
2022 (*cur != ':')) {
2023 return(0);
2024 }
2025
2026 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2027 (*cur == '.') || (*cur == '-') ||
2028 (*cur == '_') || (*cur == ':') ||
2029 (IS_COMBINING(*cur)) ||
2030 (IS_EXTENDER(*cur)))
2031 cur++;
2032 }
2033
2034 if (*cur != 0) return(0);
2035
2036 return(1);
2037}
2038
2039/**
2040 * xmlValidateNmtokenValue:
2041 * @value: an Mntoken value
2042 *
2043 * Validate that the given value match Nmtoken production
2044 *
2045 * [ VC: Name Token ]
2046 *
2047 * returns 1 if valid or 0 otherwise
2048 */
2049
2050int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002051xmlValidateNmtokenValue(const xmlChar *value) {
2052 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002053
2054 if (value == NULL) return(0);
2055 cur = value;
2056
2057 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2058 (*cur != '.') && (*cur != '-') &&
2059 (*cur != '_') && (*cur != ':') &&
2060 (!IS_COMBINING(*cur)) &&
2061 (!IS_EXTENDER(*cur)))
2062 return(0);
2063
2064 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2065 (*cur == '.') || (*cur == '-') ||
2066 (*cur == '_') || (*cur == ':') ||
2067 (IS_COMBINING(*cur)) ||
2068 (IS_EXTENDER(*cur)))
2069 cur++;
2070
2071 if (*cur != 0) return(0);
2072
2073 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002074}
2075
2076/**
2077 * xmlValidateNmtokensValue:
2078 * @value: an Mntokens value
2079 *
2080 * Validate that the given value match Nmtokens production
2081 *
2082 * [ VC: Name Token ]
2083 *
2084 * returns 1 if valid or 0 otherwise
2085 */
2086
2087int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002088xmlValidateNmtokensValue(const xmlChar *value) {
2089 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002090
2091 if (value == NULL) return(0);
2092 cur = value;
2093
2094 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2095 (*cur != '.') && (*cur != '-') &&
2096 (*cur != '_') && (*cur != ':') &&
2097 (!IS_COMBINING(*cur)) &&
2098 (!IS_EXTENDER(*cur)))
2099 return(0);
2100
2101 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2102 (*cur == '.') || (*cur == '-') ||
2103 (*cur == '_') || (*cur == ':') ||
2104 (IS_COMBINING(*cur)) ||
2105 (IS_EXTENDER(*cur)))
2106 cur++;
2107
2108 while (IS_BLANK(*cur)) {
2109 while (IS_BLANK(*cur)) cur++;
2110
2111 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2112 (*cur != '.') && (*cur != '-') &&
2113 (*cur != '_') && (*cur != ':') &&
2114 (!IS_COMBINING(*cur)) &&
2115 (!IS_EXTENDER(*cur)))
2116 return(0);
2117
2118 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2119 (*cur == '.') || (*cur == '-') ||
2120 (*cur == '_') || (*cur == ':') ||
2121 (IS_COMBINING(*cur)) ||
2122 (IS_EXTENDER(*cur)))
2123 cur++;
2124 }
2125
2126 if (*cur != 0) return(0);
2127
2128 return(1);
2129}
2130
2131/**
2132 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002133 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002134 * @doc: a document instance
2135 * @nota: a notation definition
2136 *
2137 * Try to validate a single notation definition
2138 * basically it does the following checks as described by the
2139 * XML-1.0 recommendation:
2140 * - it seems that no validity constraing exist on notation declarations
2141 * But this function get called anyway ...
2142 *
2143 * returns 1 if valid or 0 otherwise
2144 */
2145
2146int
2147xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2148 xmlNotationPtr nota) {
2149 int ret = 1;
2150
2151 return(ret);
2152}
2153
2154/**
2155 * xmlValidateAttributeValue:
2156 * @type: an attribute type
2157 * @value: an attribute value
2158 *
2159 * Validate that the given attribute value match the proper production
2160 *
2161 * [ VC: ID ]
2162 * Values of type ID must match the Name production....
2163 *
2164 * [ VC: IDREF ]
2165 * Values of type IDREF must match the Name production, and values
2166 * of type IDREFS must match Names ...
2167 *
2168 * [ VC: Entity Name ]
2169 * Values of type ENTITY must match the Name production, values
2170 * of type ENTITIES must match Names ...
2171 *
2172 * [ VC: Name Token ]
2173 * Values of type NMTOKEN must match the Nmtoken production; values
2174 * of type NMTOKENS must match Nmtokens.
2175 *
2176 * returns 1 if valid or 0 otherwise
2177 */
2178
2179int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002180xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002181 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002182 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002183 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002184 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002185 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002186 case XML_ATTRIBUTE_IDREF:
2187 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002188 case XML_ATTRIBUTE_NOTATION:
2189 return(xmlValidateNameValue(value));
2190 case XML_ATTRIBUTE_NMTOKENS:
2191 case XML_ATTRIBUTE_ENUMERATION:
2192 return(xmlValidateNmtokensValue(value));
2193 case XML_ATTRIBUTE_NMTOKEN:
2194 return(xmlValidateNmtokenValue(value));
2195 case XML_ATTRIBUTE_CDATA:
2196 break;
2197 }
2198 return(1);
2199}
2200
2201/**
2202 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002203 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002204 * @doc: a document instance
2205 * @attr: an attribute definition
2206 *
2207 * Try to validate a single attribute definition
2208 * basically it does the following checks as described by the
2209 * XML-1.0 recommendation:
2210 * - [ VC: Attribute Default Legal ]
2211 * - [ VC: Enumeration ]
2212 * - [ VC: ID Attribute Default ]
2213 *
2214 * The ID/IDREF uniqueness and matching are done separately
2215 *
2216 * returns 1 if valid or 0 otherwise
2217 */
2218
2219int
2220xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2221 xmlAttributePtr attr) {
2222 int ret = 1;
2223 int val;
2224 CHECK_DTD;
2225 if(attr == NULL) return(1);
2226
2227 /* Attribute Default Legal */
2228 /* Enumeration */
2229 if (attr->defaultValue != NULL) {
2230 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2231 if (val == 0) {
2232 VERROR(ctxt->userData,
2233 "Syntax of default value for attribute %s on %s is not valid\n",
2234 attr->name, attr->elem);
2235 }
2236 ret &= val;
2237 }
2238
2239 /* ID Attribute Default */
2240 if ((attr->type == XML_ATTRIBUTE_ID)&&
2241 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2242 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2243 VERROR(ctxt->userData,
2244 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2245 attr->name, attr->elem);
2246 ret = 0;
2247 }
2248
Daniel Veillardb96e6431999-08-29 21:02:19 +00002249 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002250 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2251 int nbId = 0;
2252
2253 /* the trick is taht we parse DtD as their own internal subset */
2254 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2255 attr->elem);
2256 if (elem != NULL) {
2257 nbId = xmlScanIDAttributeDecl(NULL, elem);
2258 }
2259 if (nbId >= 1)
2260 VERROR(ctxt->userData,
2261 "Element %s has ID attribute defined in the external subset : %s\n",
2262 attr->elem, attr->name);
2263 }
2264
2265 return(ret);
2266}
2267
2268/**
2269 * xmlValidateElementDecl:
2270 * @ctxt: the validation context
2271 * @doc: a document instance
2272 * @elem: an element definition
2273 *
2274 * Try to validate a single element definition
2275 * basically it does the following checks as described by the
2276 * XML-1.0 recommendation:
2277 * - [ VC: One ID per Element Type ]
2278 * - [ VC: No Duplicate Types ]
2279 * - [ VC: Unique Element Type Declaration ]
2280 *
2281 * returns 1 if valid or 0 otherwise
2282 */
2283
2284int
2285xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2286 xmlElementPtr elem) {
2287 int ret = 1;
2288 xmlElementPtr tst;
2289
2290 CHECK_DTD;
2291
2292 if (elem == NULL) return(1);
2293
2294 /* No Duplicate Types */
2295 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2296 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002297 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002298
2299 cur = elem->content;
2300 while (cur != NULL) {
2301 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2302 if (cur->c1 == NULL) break;
2303 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2304 name = cur->c1->name;
2305 next = cur->c2;
2306 while (next != NULL) {
2307 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2308 if (!xmlStrcmp(next->name, name)) {
2309 VERROR(ctxt->userData,
2310 "Definition of %s has duplicate references of %s\n",
2311 elem->name, name);
2312 ret = 0;
2313 }
2314 break;
2315 }
2316 if (next->c1 == NULL) break;
2317 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2318 if (!xmlStrcmp(next->c1->name, name)) {
2319 VERROR(ctxt->userData,
2320 "Definition of %s has duplicate references of %s\n",
2321 elem->name, name);
2322 ret = 0;
2323 }
2324 next = next->c2;
2325 }
2326 }
2327 cur = cur->c2;
2328 }
2329 }
2330
2331 /* VC: Unique Element Type Declaration */
2332 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2333 if ((tst != NULL ) && (tst != elem)) {
2334 VERROR(ctxt->userData, "Redefinition of element %s\n",
2335 elem->name);
2336 ret = 0;
2337 }
2338 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2339 if ((tst != NULL ) && (tst != elem)) {
2340 VERROR(ctxt->userData, "Redefinition of element %s\n",
2341 elem->name);
2342 ret = 0;
2343 }
2344
2345 /* One ID per Element Type */
2346 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2347 ret = 0;
2348 }
2349 return(ret);
2350}
2351
2352/**
2353 * xmlValidateOneAttribute:
2354 * @ctxt: the validation context
2355 * @doc: a document instance
2356 * @elem: an element instance
2357 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00002358 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002359 *
2360 * Try to validate a single attribute for an element
2361 * basically it * does the following checks as described by the
2362 * XML-1.0 recommendation:
2363 * - [ VC: Attribute Value Type ]
2364 * - [ VC: Fixed Attribute Default ]
2365 * - [ VC: Entity Name ]
2366 * - [ VC: Name Token ]
2367 * - [ VC: ID ]
2368 * - [ VC: IDREF ]
2369 * - [ VC: Entity Name ]
2370 * - [ VC: Notation Attributes ]
2371 *
2372 * The ID/IDREF uniqueness and matching are done separately
2373 *
2374 * returns 1 if valid or 0 otherwise
2375 */
2376
2377int
2378xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002379 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002380 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002381 xmlAttributePtr attrDecl;
2382 int val;
2383 int ret = 1;
2384
2385 CHECK_DTD;
2386 if ((elem == NULL) || (elem->name == NULL)) return(0);
2387 if ((attr == NULL) || (attr->name == NULL)) return(0);
2388
2389 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2390 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2391 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2392
2393
2394 /* Validity Constraint: Attribute Value Type */
2395 if (attrDecl == NULL) {
2396 VERROR(ctxt->userData,
2397 "No declaration for attribute %s on element %s\n",
2398 attr->name, elem->name);
2399 return(0);
2400 }
2401 val = xmlValidateAttributeValue(attrDecl->type, value);
2402 if (val == 0) {
2403 VERROR(ctxt->userData,
2404 "Syntax of value for attribute %s on %s is not valid\n",
2405 attr->name, elem->name);
2406 ret = 0;
2407 }
2408
Daniel Veillardb96e6431999-08-29 21:02:19 +00002409 /* Validity Constraint: ID uniqueness */
2410 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2411 xmlAddID(ctxt, doc, value, attr);
2412 }
2413
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002414 if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2415 xmlAddRef(ctxt, doc, value, attr);
2416 }
2417
Daniel Veillardb05deb71999-08-10 19:04:08 +00002418 /* Validity Constraint: Notation Attributes */
2419 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2420 xmlEnumerationPtr tree = attrDecl->tree;
2421 xmlNotationPtr nota;
2422
2423 /* First check that the given NOTATION was declared */
2424 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2425 if (nota == NULL)
2426 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2427
2428 if (nota == NULL) {
2429 VERROR(ctxt->userData,
2430 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2431 value, attr->name, elem->name);
2432 ret = 0;
2433 }
2434
2435 /* Second, verify that it's among the list */
2436 while (tree != NULL) {
2437 if (!xmlStrcmp(tree->name, value)) break;
2438 tree = tree->next;
2439 }
2440 if (tree == NULL) {
2441 VERROR(ctxt->userData,
2442 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2443 value, attr->name, elem->name);
2444 ret = 0;
2445 }
2446 }
2447
2448 /* Validity Constraint: Enumeration */
2449 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2450 xmlEnumerationPtr tree = attrDecl->tree;
2451 while (tree != NULL) {
2452 if (!xmlStrcmp(tree->name, value)) break;
2453 tree = tree->next;
2454 }
2455 if (tree == NULL) {
2456 VERROR(ctxt->userData,
2457 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2458 value, attr->name, elem->name);
2459 ret = 0;
2460 }
2461 }
2462
2463 /* Fixed Attribute Default */
2464 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2465 (xmlStrcmp(attrDecl->defaultValue, value))) {
2466 VERROR(ctxt->userData,
2467 "Value for attribute %s on %s must be \"%s\"\n",
2468 attr->name, elem->name, attrDecl->defaultValue);
2469 ret = 0;
2470 }
2471
Daniel Veillardb96e6431999-08-29 21:02:19 +00002472 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002473 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2474 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2475 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2476 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002477 return(0);
2478 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002479 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002480 return(ret);
2481}
2482
2483int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2484 xmlElementContentPtr cont);
2485
2486/**
2487 * xmlValidateElementTypeExpr:
2488 * @ctxt: the validation context
2489 * @child: pointer to the child list
2490 * @cont: pointer to the content declaration
2491 *
2492 * Try to validate the content of an element of type element
2493 * but don't handle the occurence factor
2494 *
2495 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2496 * also update child value in-situ.
2497 */
2498
2499int
2500xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2501 xmlElementContentPtr cont) {
2502 xmlNodePtr cur;
2503 int ret = 1;
2504
2505 if (cont == NULL) return(-1);
2506 while (*child != NULL) {
2507 if ((*child)->type == XML_PI_NODE) {
2508 *child = (*child)->next;
2509 continue;
2510 }
2511 if ((*child)->type == XML_COMMENT_NODE) {
2512 *child = (*child)->next;
2513 continue;
2514 }
2515 else if ((*child)->type != XML_ELEMENT_NODE) {
2516 return(-1);
2517 }
2518 break;
2519 }
2520 switch (cont->type) {
2521 case XML_ELEMENT_CONTENT_PCDATA:
2522 /* Internal error !!! */
2523 fprintf(stderr, "Internal: MIXED struct bad\n");
2524 return(-1);
2525 case XML_ELEMENT_CONTENT_ELEMENT:
2526 if (*child == NULL) return(0);
2527 ret = (!xmlStrcmp((*child)->name, cont->name));
2528 if (ret == 1)
2529 *child = (*child)->next;
2530 return(ret);
2531 case XML_ELEMENT_CONTENT_OR:
2532 cur = *child;
2533 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2534 if (ret == -1) return(-1);
2535 if (ret == 1) {
2536 return(1);
2537 }
2538 /* rollback and retry the other path */
2539 *child = cur;
2540 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2541 if (ret == -1) return(-1);
2542 if (ret == 0) {
2543 *child = cur;
2544 return(0);
2545 }
2546 return(1);
2547 case XML_ELEMENT_CONTENT_SEQ:
2548 cur = *child;
2549 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2550 if (ret == -1) return(-1);
2551 if (ret == 0) {
2552 *child = cur;
2553 return(0);
2554 }
2555 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2556 if (ret == -1) return(-1);
2557 if (ret == 0) {
2558 *child = cur;
2559 return(0);
2560 }
2561 return(1);
2562 }
2563 return(ret);
2564}
2565
2566/**
2567 * xmlValidateElementTypeElement:
2568 * @ctxt: the validation context
2569 * @child: pointer to the child list
2570 * @cont: pointer to the content declaration
2571 *
2572 * Try to validate the content of an element of type element
2573 * yeah, Yet Another Regexp Implementation, and recursive
2574 *
2575 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2576 * also update child and content values in-situ.
2577 */
2578
2579int
2580xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2581 xmlElementContentPtr cont) {
2582 xmlNodePtr cur;
2583 int ret = 1;
2584
2585 if (cont == NULL) return(-1);
2586 while (*child != NULL) {
2587 if ((*child)->type == XML_PI_NODE) {
2588 *child = (*child)->next;
2589 continue;
2590 }
2591 if ((*child)->type == XML_COMMENT_NODE) {
2592 *child = (*child)->next;
2593 continue;
2594 }
2595 else if ((*child)->type != XML_ELEMENT_NODE) {
2596 return(-1);
2597 }
2598 break;
2599 }
2600 cur = *child;
2601 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2602 if (ret == -1) return(-1);
2603 switch (cont->ocur) {
2604 case XML_ELEMENT_CONTENT_ONCE:
2605 if (ret == 1) {
2606 return(1);
2607 }
2608 *child = cur;
2609 return(0);
2610 case XML_ELEMENT_CONTENT_OPT:
2611 if (ret == 0) {
2612 *child = cur;
2613 return(1);
2614 }
2615 break;
2616 case XML_ELEMENT_CONTENT_MULT:
2617 if (ret == 0) {
2618 *child = cur;
2619 break;
2620 }
2621 /* no break on purpose */
2622 case XML_ELEMENT_CONTENT_PLUS:
2623 if (ret == 0) {
2624 *child = cur;
2625 return(0);
2626 }
2627 do {
2628 cur = *child;
2629 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2630 } while (ret == 1);
2631 if (ret == -1) return(-1);
2632 *child = cur;
2633 break;
2634 }
2635 while (*child != NULL) {
2636 if ((*child)->type == XML_PI_NODE) {
2637 *child = (*child)->next;
2638 continue;
2639 }
2640 if ((*child)->type == XML_COMMENT_NODE) {
2641 *child = (*child)->next;
2642 continue;
2643 }
2644 else if ((*child)->type != XML_ELEMENT_NODE) {
2645 return(-1);
2646 }
2647 break;
2648 }
2649 return(1);
2650}
2651
2652/**
2653 * xmlSprintfElementChilds:
2654 * @buf: an output buffer
2655 * @content: An element
2656 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2657 *
2658 * This will dump the list of childs to the buffer
2659 * Intended just for the debug routine
2660 */
2661void
2662xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2663 xmlNodePtr cur;
2664
2665 if (node == NULL) return;
2666 if (glob) strcat(buf, "(");
2667 cur = node->childs;
2668 while (cur != NULL) {
2669 switch (cur->type) {
2670 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002671 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002672 if (cur->next != NULL)
2673 strcat(buf, " ");
2674 break;
2675 case XML_TEXT_NODE:
2676 case XML_CDATA_SECTION_NODE:
2677 case XML_ENTITY_REF_NODE:
2678 strcat(buf, "CDATA");
2679 if (cur->next != NULL)
2680 strcat(buf, " ");
2681 break;
2682 case XML_ATTRIBUTE_NODE:
2683 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002684 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002685 case XML_DOCUMENT_TYPE_NODE:
2686 case XML_DOCUMENT_FRAG_NODE:
2687 case XML_NOTATION_NODE:
2688 strcat(buf, "???");
2689 if (cur->next != NULL)
2690 strcat(buf, " ");
2691 break;
2692 case XML_ENTITY_NODE:
2693 case XML_PI_NODE:
2694 case XML_COMMENT_NODE:
2695 break;
2696 }
2697 cur = cur->next;
2698 }
2699 if (glob) strcat(buf, ")");
2700}
2701
2702
2703/**
2704 * xmlValidateOneElement:
2705 * @ctxt: the validation context
2706 * @doc: a document instance
2707 * @elem: an element instance
2708 *
2709 * Try to validate a single element and it's attributes,
2710 * basically it does the following checks as described by the
2711 * XML-1.0 recommendation:
2712 * - [ VC: Element Valid ]
2713 * - [ VC: Required Attribute ]
2714 * Then call xmlValidateOneAttribute() for each attribute present.
2715 *
2716 * The ID/IDREF checkings are done separately
2717 *
2718 * returns 1 if valid or 0 otherwise
2719 */
2720
2721int
2722xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2723 xmlNodePtr elem) {
2724 xmlElementPtr elemDecl;
2725 xmlElementContentPtr cont;
2726 xmlNodePtr child;
2727 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002728 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002729
2730 CHECK_DTD;
2731
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002732 if (elem == NULL) return(0);
2733 if (elem->type == XML_TEXT_NODE) {
2734 }
2735 switch (elem->type) {
2736 case XML_ATTRIBUTE_NODE:
2737 VERROR(ctxt->userData,
2738 "Attribute element not expected here\n");
2739 return(0);
2740 case XML_TEXT_NODE:
2741 if (elem->childs != NULL) {
2742 VERROR(ctxt->userData, "Text element has childs !\n");
2743 return(0);
2744 }
2745 if (elem->properties != NULL) {
2746 VERROR(ctxt->userData, "Text element has attributes !\n");
2747 return(0);
2748 }
2749 if (elem->ns != NULL) {
2750 VERROR(ctxt->userData, "Text element has namespace !\n");
2751 return(0);
2752 }
2753 if (elem->ns != NULL) {
2754 VERROR(ctxt->userData,
2755 "Text element carries namespace definitions !\n");
2756 return(0);
2757 }
2758 if (elem->content == NULL) {
2759 VERROR(ctxt->userData,
2760 "Text element has no content !\n");
2761 return(0);
2762 }
2763 return(1);
2764 case XML_CDATA_SECTION_NODE:
2765 case XML_ENTITY_REF_NODE:
2766 case XML_PI_NODE:
2767 case XML_COMMENT_NODE:
2768 return(1);
2769 case XML_ENTITY_NODE:
2770 VERROR(ctxt->userData,
2771 "Entity element not expected here\n");
2772 return(0);
2773 case XML_NOTATION_NODE:
2774 VERROR(ctxt->userData,
2775 "Notation element not expected here\n");
2776 return(0);
2777 case XML_DOCUMENT_NODE:
2778 case XML_DOCUMENT_TYPE_NODE:
2779 case XML_DOCUMENT_FRAG_NODE:
2780 VERROR(ctxt->userData,
2781 "Document element not expected here\n");
2782 return(0);
2783 case XML_HTML_DOCUMENT_NODE:
2784 VERROR(ctxt->userData,
2785 "\n");
2786 return(0);
2787 case XML_ELEMENT_NODE:
2788 break;
2789 default:
2790 VERROR(ctxt->userData,
2791 "unknown element type %d\n", elem->type);
2792 return(0);
2793 }
2794 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002795
2796 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2797 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2798 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2799 if (elemDecl == NULL) {
2800 VERROR(ctxt->userData, "No declaration for element %s\n",
2801 elem->name);
2802 return(0);
2803 }
2804
2805 /* Check taht the element content matches the definition */
2806 switch (elemDecl->type) {
2807 case XML_ELEMENT_TYPE_EMPTY:
2808 if (elem->childs != NULL) {
2809 VERROR(ctxt->userData,
2810 "Element %s was declared EMPTY this one has content\n",
2811 elem->name);
2812 ret = 0;
2813 }
2814 break;
2815 case XML_ELEMENT_TYPE_ANY:
2816 /* I don't think anything is required then */
2817 break;
2818 case XML_ELEMENT_TYPE_MIXED:
2819 /* Hum, this start to get messy */
2820 child = elem->childs;
2821 while (child != NULL) {
2822 if (child->type == XML_ELEMENT_NODE) {
2823 name = child->name;
2824 cont = elemDecl->content;
2825 while (cont != NULL) {
2826 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2827 if (!xmlStrcmp(cont->name, name)) break;
2828 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2829 (cont->c1 != NULL) &&
2830 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2831 if (!xmlStrcmp(cont->c1->name, name)) break;
2832 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2833 (cont->c1 == NULL) ||
2834 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2835 /* Internal error !!! */
2836 fprintf(stderr, "Internal: MIXED struct bad\n");
2837 break;
2838 }
2839 cont = cont->c2;
2840 }
2841 if (cont == NULL) {
2842 VERROR(ctxt->userData,
2843 "Element %s is not declared in %s list of possible childs\n",
2844 name, elem->name);
2845 ret = 0;
2846 }
2847 }
2848 child = child->next;
2849 }
2850 break;
2851 case XML_ELEMENT_TYPE_ELEMENT:
2852 child = elem->childs;
2853 cont = elemDecl->content;
2854 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2855 if ((ret == 0) || (child != NULL)) {
2856 char expr[1000];
2857 char list[2000];
2858
2859 expr[0] = 0;
2860 xmlSprintfElementContent(expr, cont, 1);
2861 list[0] = 0;
2862 xmlSprintfElementChilds(list, elem, 1);
2863
2864 VERROR(ctxt->userData,
2865 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2866 elem->name, expr, list);
2867 ret = 0;
2868 }
2869 break;
2870 }
2871
Daniel Veillardb96e6431999-08-29 21:02:19 +00002872 /* TODO - [ VC: Required Attribute ] */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002873 return(ret);
2874}
2875
2876/**
2877 * xmlValidateRoot:
2878 * @ctxt: the validation context
2879 * @doc: a document instance
2880 *
2881 * Try to validate a the root element
2882 * basically it does the following check as described by the
2883 * XML-1.0 recommendation:
2884 * - [ VC: Root Element Type ]
2885 * it doesn't try to recurse or apply other check to the element
2886 *
2887 * returns 1 if valid or 0 otherwise
2888 */
2889
2890int
2891xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002892 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002893 if (doc == NULL) return(0);
2894
2895 if ((doc->intSubset == NULL) ||
2896 (doc->intSubset->name == NULL)) {
2897 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2898 return(0);
2899 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002900 root = xmlDocGetRootElement(doc);
2901 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002902 VERROR(ctxt->userData, "Not valid: no root element\n");
2903 return(0);
2904 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002905 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002906 VERROR(ctxt->userData,
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002907 "Not valid: root and DtD name do not match '%s' and '%s'\n",
2908 root->name, doc->intSubset->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002909 return(0);
2910 }
2911 return(1);
2912}
2913
2914
2915/**
2916 * xmlValidateElement:
2917 * @ctxt: the validation context
2918 * @doc: a document instance
2919 * @elem: an element instance
2920 *
2921 * Try to validate the subtree under an element
2922 *
2923 * returns 1 if valid or 0 otherwise
2924 */
2925
2926int
2927xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002928 xmlNodePtr child;
2929 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002930 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002931 int ret = 1;
2932
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002933 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002934 CHECK_DTD;
2935
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002936 ret &= xmlValidateOneElement(ctxt, doc, elem);
2937 attr = elem->properties;
2938 while(attr != NULL) {
2939 value = xmlNodeListGetString(doc, attr->val, 0);
2940 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
2941 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002942 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002943 attr= attr->next;
2944 }
2945 child = elem->childs;
2946 while (child != NULL) {
2947 ret &= xmlValidateElement(ctxt, doc, child);
2948 child = child->next;
2949 }
2950
2951 return(ret);
2952}
2953
2954/**
2955 * xmlValidateDocumentFinal:
2956 * @ctxt: the validation context
2957 * @doc: a document instance
2958 *
2959 * Does the final step for the document validation once all the
2960 * incremental validation steps have been completed
2961 *
2962 * basically it does the following checks described by the XML Rec
2963 *
2964 *
2965 * returns 1 if valid or 0 otherwise
2966 */
2967
2968int
2969xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2970 int ret = 1, i;
2971 xmlRefTablePtr table;
2972 xmlAttrPtr id;
2973
2974 if (doc == NULL) {
2975 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
2976 return(0);
2977 }
2978
2979 /*
2980 * Get the refs table
2981 */
2982 table = doc->refs;
2983 if (table != NULL) {
2984 for (i = 0; i < table->nb_refs; i++) {
2985 id = xmlGetID(doc, table->table[i]->value);
2986 if (id == NULL) {
2987 VERROR(ctxt->userData,
2988 "IDREF attribute %s reference an unknown ID '%s'\n",
2989 table->table[i]->attr->name, table->table[i]->value);
2990 ret = 0;
2991 }
2992 }
2993 }
2994 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002995}
2996
2997/**
2998 * xmlValidateDtd:
2999 * @ctxt: the validation context
3000 * @doc: a document instance
3001 * @dtd: a dtd instance
3002 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003003 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003004 *
3005 * basically it does check all the definitions in the DtD.
3006 *
3007 * returns 1 if valid or 0 otherwise
3008 */
3009
3010int
3011xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003012 int ret;
3013 xmlDtdPtr oldExt;
3014 xmlNodePtr root;
3015
3016 if (dtd == NULL) return(0);
3017 if (doc == NULL) return(0);
3018 oldExt = doc->extSubset;
3019 doc->extSubset = dtd;
3020 ret = xmlValidateRoot(ctxt, doc);
3021 if (ret == 0) {
3022 doc->extSubset = oldExt;
3023 return(ret);
3024 }
3025 root = xmlDocGetRootElement(doc);
3026 ret = xmlValidateElement(ctxt, doc, root);
3027 ret &= xmlValidateDocumentFinal(ctxt, doc);
3028 doc->extSubset = oldExt;
3029 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003030}
3031
3032/**
3033 * xmlValidateDocument:
3034 * @ctxt: the validation context
3035 * @doc: a document instance
3036 *
3037 * Try to validate the document instance
3038 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003039 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00003040 * i.e. validates the internal and external subset (if present)
3041 * and validate the document tree.
3042 *
3043 * returns 1 if valid or 0 otherwise
3044 */
3045
3046int
3047xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003048 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003049 xmlNodePtr root;
3050
3051 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3052 return(0);
3053 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
3054 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
3055 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
3056 doc->intSubset->SystemID);
3057 if (doc->extSubset == NULL) {
3058 if (doc->intSubset->SystemID != NULL) {
3059 VERROR(ctxt->userData,
3060 "Could not load the external subset '%s'\n",
3061 doc->intSubset->SystemID);
3062 } else {
3063 VERROR(ctxt->userData,
3064 "Could not load the external subset '%s'\n",
3065 doc->intSubset->ExternalID);
3066 }
3067 return(0);
3068 }
3069 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003070
Daniel Veillardb05deb71999-08-10 19:04:08 +00003071 if (!xmlValidateRoot(ctxt, doc)) return(0);
3072
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003073 root = xmlDocGetRootElement(doc);
3074 ret = xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003075 ret &= xmlValidateDocumentFinal(ctxt, doc);
3076 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003077}
3078
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003079
3080/************************************************************************
3081 * *
3082 * Routines for dynamic validation editing *
3083 * *
3084 ************************************************************************/
3085
3086/**
3087 * xmlValidGetPotentialChildren:
3088 * @ctree: an element content tree
3089 * @list: an array to store the list of child names
3090 * @len: a pointer to the number of element in the list
3091 * @max: the size of the array
3092 *
3093 * Build/extend a list of potential children allowed by the content tree
3094 *
3095 * returns the number of element in the list, or -1 in case of error.
3096 */
3097
3098int
3099xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
3100 int *len, int max) {
3101 int i;
3102
3103 if ((ctree == NULL) || (list == NULL) || (len == NULL))
3104 return(-1);
3105 if (*len >= max) return(*len);
3106
3107 switch (ctree->type) {
3108 case XML_ELEMENT_CONTENT_PCDATA:
3109 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00003110 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
3111 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003112 break;
3113 case XML_ELEMENT_CONTENT_ELEMENT:
3114 for (i = 0; i < *len;i++)
3115 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
3116 list[(*len)++] = ctree->name;
3117 break;
3118 case XML_ELEMENT_CONTENT_SEQ:
3119 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3120 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3121 break;
3122 case XML_ELEMENT_CONTENT_OR:
3123 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3124 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3125 break;
3126 }
3127
3128 return(*len);
3129}
3130
3131/**
3132 * xmlValidGetValidElements:
3133 * @prev: an element to insert after
3134 * @next: an element to insert next
3135 * @list: an array to store the list of child names
3136 * @max: the size of the array
3137 *
3138 * This function returns the list of authorized children to insert
3139 * within an existing tree while respecting the validity constraints
3140 * forced by the Dtd. The insertion point is defined using @prev and
3141 * @next in the following ways:
3142 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3143 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3144 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3145 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3146 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
3147 *
3148 * pointers to the element names are inserted at the beginning of the array
3149 * and do not need to be freed.
3150 *
3151 * returns the number of element in the list, or -1 in case of error. If
3152 * the function returns the value @max the caller is invited to grow the
3153 * receiving array and retry.
3154 */
3155
3156int
3157xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3158 int max) {
3159 int nb_valid_elements = 0;
3160 const xmlChar *elements[256];
3161 int nb_elements = 0, i;
3162
3163 xmlNode *ref_node;
3164 xmlNode *parent;
3165 xmlNode *test_node;
3166
3167 xmlNode *prev_next;
3168 xmlNode *next_prev;
3169 xmlNode *parent_childs;
3170 xmlNode *parent_last;
3171
3172 xmlElement *element_desc;
3173
3174 if (prev == NULL && next == NULL)
3175 return(-1);
3176
3177 if (list == NULL) return(-1);
3178 if (max <= 0) return(-1);
3179
3180 nb_valid_elements = 0;
3181 ref_node = prev ? prev : next;
3182 parent = ref_node->parent;
3183
3184 /*
3185 * Retrieves the parent element declaration
3186 */
3187 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3188 parent->name);
3189 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3190 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3191 parent->name);
3192 if (element_desc == NULL) return(-1);
3193
3194 /*
3195 * Do a backup of the current tree structure
3196 */
3197 prev_next = prev ? prev->next : NULL;
3198 next_prev = next ? next->prev : NULL;
3199 parent_childs = parent->childs;
3200 parent_last = parent->last;
3201
3202 /*
3203 * Creates a dummy node and insert it into the tree
3204 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003205 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003206 test_node->doc = ref_node->doc;
3207 test_node->parent = parent;
3208 test_node->prev = prev;
3209 test_node->next = next;
3210
3211 if (prev) prev->next = test_node;
3212 else parent->childs = test_node;
3213
3214 if (next) next->prev = test_node;
3215 else parent->last = test_node;
3216
3217 /*
3218 * Insert each potential child node and check if the parent is
3219 * still valid
3220 */
3221 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
3222 elements, &nb_elements, 256);
3223
3224 for (i = 0;i < nb_elements;i++) {
3225 test_node->name = elements[i];
3226 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
3227 int j;
3228
3229 for (j = 0; j < nb_valid_elements;j++)
3230 if (!xmlStrcmp(elements[i], list[j])) break;
3231 list[nb_valid_elements++] = elements[i];
3232 if (nb_valid_elements >= max) break;
3233 }
3234 }
3235
3236 /*
3237 * Restore the tree structure
3238 */
3239 if (prev) prev->next = prev_next;
3240 if (next) next->prev = next_prev;
3241 parent->childs = parent_childs;
3242 parent->last = parent_last;
3243
3244 return(nb_valid_elements);
3245}