blob: e756b0da18d3ce41fea489a9ff94a6971ba15d14 [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
11#define HAVE_FCNTL_H
12#include <io.h>
13#else
14#include "config.h"
15#endif
16
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000017#include <stdio.h>
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000018#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000019
20#ifdef HAVE_STDLIB_H
21#include <stdlib.h>
22#endif
23
Daniel Veillard6454aec1999-09-02 22:04:43 +000024#include "xmlmemory.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000025#include "valid.h"
26#include "parser.h"
Daniel Veillardb05deb71999-08-10 19:04:08 +000027#include "parserInternals.h"
28
29#define VERROR \
30 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
31
32#define VWARNING \
33 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
34
35#define CHECK_DTD \
36 if (doc == NULL) return(0); \
37 else if (doc->intSubset == NULL) return(0)
38
Daniel Veillarddd6b3671999-09-23 22:19:22 +000039xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
40xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000041
42/****************************************************************
43 * *
44 * Util functions for data allocation/deallocation *
45 * *
46 ****************************************************************/
47
48/**
49 * xmlNewElementContent:
50 * @name: the subelement name or NULL
51 * @type: the type of element content decl
52 *
53 * Allocate an element content structure.
54 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000055 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000056 */
57xmlElementContentPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +000058xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000059 xmlElementContentPtr ret;
60
61 switch(type) {
62 case XML_ELEMENT_CONTENT_ELEMENT:
63 if (name == NULL) {
64 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
65 }
66 break;
67 case XML_ELEMENT_CONTENT_PCDATA:
68 case XML_ELEMENT_CONTENT_SEQ:
69 case XML_ELEMENT_CONTENT_OR:
70 if (name != NULL) {
71 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
72 }
73 break;
74 default:
75 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
76 exit(1);
77 }
Daniel Veillard6454aec1999-09-02 22:04:43 +000078 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000079 if (ret == NULL) {
80 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
81 return(NULL);
82 }
83 ret->type = type;
84 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +000085 if (name != NULL)
86 ret->name = xmlStrdup(name);
87 else
88 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +000089 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000090 return(ret);
91}
92
93/**
Daniel Veillard3b9def11999-01-31 22:15:06 +000094 * xmlCopyElementContent:
95 * @content: An element content pointer.
96 *
97 * Build a copy of an element content description.
98 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000099 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000100 */
101xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000102xmlCopyElementContent(xmlElementContentPtr cur) {
103 xmlElementContentPtr ret;
104
105 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000106 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +0000107 if (ret == NULL) {
108 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
109 return(NULL);
110 }
111 ret->ocur = cur->ocur;
112 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
113 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000114 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000115}
116
117/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000118 * xmlFreeElementContent:
119 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000120 *
121 * Free an element content structure. This is a recursive call !
122 */
123void
124xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000125 if (cur == NULL) return;
126 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
127 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000128 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000129 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000130 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000131}
132
Daniel Veillard1899e851999-02-01 12:18:54 +0000133/**
134 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000135 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000136 * @content: An element table
137 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
138 *
139 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000140 */
141void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000142xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000143 if (content == NULL) return;
144
Daniel Veillard5099ae81999-04-21 20:12:07 +0000145 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000146 switch (content->type) {
147 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000148 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000149 break;
150 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000151 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000152 break;
153 case XML_ELEMENT_CONTENT_SEQ:
154 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
155 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000156 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000157 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000158 xmlDumpElementContent(buf, content->c1, 0);
159 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000160 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000161 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000162 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000163 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000164 break;
165 case XML_ELEMENT_CONTENT_OR:
166 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
167 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000168 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000169 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000170 xmlDumpElementContent(buf, content->c1, 0);
171 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000172 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000173 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000174 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000175 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000176 break;
177 default:
178 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
179 content->type);
180 }
181 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000182 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000183 switch (content->ocur) {
184 case XML_ELEMENT_CONTENT_ONCE:
185 break;
186 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000187 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000188 break;
189 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000190 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000191 break;
192 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000193 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000194 break;
195 }
196}
197
Daniel Veillardb05deb71999-08-10 19:04:08 +0000198/**
199 * xmlSprintfElementContent:
200 * @buf: an output buffer
201 * @content: An element table
202 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
203 *
204 * This will dump the content of the element content definition
205 * Intended just for the debug routine
206 */
207void
208xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
209 if (content == NULL) return;
210 if (glob) strcat(buf, "(");
211 switch (content->type) {
212 case XML_ELEMENT_CONTENT_PCDATA:
213 strcat(buf, "#PCDATA");
214 break;
215 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000216 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000217 break;
218 case XML_ELEMENT_CONTENT_SEQ:
219 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
220 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
221 xmlSprintfElementContent(buf, content->c1, 1);
222 else
223 xmlSprintfElementContent(buf, content->c1, 0);
224 strcat(buf, " , ");
225 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
226 xmlSprintfElementContent(buf, content->c2, 1);
227 else
228 xmlSprintfElementContent(buf, content->c2, 0);
229 break;
230 case XML_ELEMENT_CONTENT_OR:
231 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
232 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
233 xmlSprintfElementContent(buf, content->c1, 1);
234 else
235 xmlSprintfElementContent(buf, content->c1, 0);
236 strcat(buf, " | ");
237 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
238 xmlSprintfElementContent(buf, content->c2, 1);
239 else
240 xmlSprintfElementContent(buf, content->c2, 0);
241 break;
242 }
243 if (glob)
244 strcat(buf, ")");
245 switch (content->ocur) {
246 case XML_ELEMENT_CONTENT_ONCE:
247 break;
248 case XML_ELEMENT_CONTENT_OPT:
249 strcat(buf, "?");
250 break;
251 case XML_ELEMENT_CONTENT_MULT:
252 strcat(buf, "*");
253 break;
254 case XML_ELEMENT_CONTENT_PLUS:
255 strcat(buf, "+");
256 break;
257 }
258}
259
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000260/****************************************************************
261 * *
262 * Registration of DTD declarations *
263 * *
264 ****************************************************************/
265
Daniel Veillard3b9def11999-01-31 22:15:06 +0000266/**
267 * xmlCreateElementTable:
268 *
269 * create and initialize an empty element hash table.
270 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000271 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000272 */
273xmlElementTablePtr
274xmlCreateElementTable(void) {
275 xmlElementTablePtr ret;
276
277 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000278 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000279 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000280 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000281 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000282 return(NULL);
283 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000284 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000285 ret->nb_elements = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000286 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000287 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000288 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000289 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000290 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000291 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000292 return(NULL);
293 }
294 return(ret);
295}
296
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000297
298/**
299 * xmlAddElementDecl:
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 Veillardc26087b1999-08-30 11:23:51 +0000311 xmlElementContentType 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 Veillard1e346af1999-02-22 10:33:01 +0000762 int i;
763
764 if (dtd == NULL) {
765 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
766 return(NULL);
767 }
768 if (name == NULL) {
769 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
770 return(NULL);
771 }
772 if (elem == NULL) {
773 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
774 return(NULL);
775 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000776 /*
777 * Check the type and possibly the default value.
778 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000779 switch (type) {
780 case XML_ATTRIBUTE_CDATA:
781 break;
782 case XML_ATTRIBUTE_ID:
783 break;
784 case XML_ATTRIBUTE_IDREF:
785 break;
786 case XML_ATTRIBUTE_IDREFS:
787 break;
788 case XML_ATTRIBUTE_ENTITY:
789 break;
790 case XML_ATTRIBUTE_ENTITIES:
791 break;
792 case XML_ATTRIBUTE_NMTOKEN:
793 break;
794 case XML_ATTRIBUTE_NMTOKENS:
795 break;
796 case XML_ATTRIBUTE_ENUMERATION:
797 break;
798 case XML_ATTRIBUTE_NOTATION:
799 break;
800 default:
801 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
802 return(NULL);
803 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000804 if ((defaultValue != NULL) &&
805 (!xmlValidateAttributeValue(type, defaultValue))) {
806 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
807 elem, name, defaultValue);
808 defaultValue = NULL;
809 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000810
811 /*
812 * Create the Attribute table if needed.
813 */
814 table = dtd->attributes;
815 if (table == NULL)
816 table = dtd->attributes = xmlCreateAttributeTable();
817 if (table == NULL) {
818 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
819 return(NULL);
820 }
821
822 /*
823 * Validity Check:
824 * Search the DTD for previous declarations of the ATTLIST
825 */
826 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000827 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +0000828 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
829 /*
830 * The attribute is already defined in this Dtd.
831 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000832 VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
833 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000834 }
835 }
836
837 /*
838 * Grow the table, if needed.
839 */
840 if (table->nb_attributes >= table->max_attributes) {
841 /*
842 * need more attributes.
843 */
844 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000845 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000846 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000847 sizeof(xmlAttributePtr));
848 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000849 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
850 return(NULL);
851 }
852 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000853 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000854 if (ret == NULL) {
855 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
856 return(NULL);
857 }
858 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000859
860 /*
861 * fill the structure.
862 */
863 ret->type = type;
864 ret->name = xmlStrdup(name);
865 ret->elem = xmlStrdup(elem);
866 ret->def = def;
867 ret->tree = tree;
868 if (defaultValue != NULL)
869 ret->defaultValue = xmlStrdup(defaultValue);
870 else
871 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000872 elemDef = xmlGetDtdElementDesc(dtd, elem);
873 if (elemDef != NULL) {
874 if ((type == XML_ATTRIBUTE_ID) &&
875 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
876 VERROR(ctxt->userData,
877 "Element %s has too may ID attributes defined : %s\n",
878 elem, name);
879 ret->next = elemDef->attributes;
880 elemDef->attributes = ret;
881 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000882 table->nb_attributes++;
883
884 return(ret);
885}
886
887/**
888 * xmlFreeAttribute:
889 * @elem: An attribute
890 *
891 * Deallocate the memory used by an attribute definition
892 */
893void
894xmlFreeAttribute(xmlAttributePtr attr) {
895 if (attr == NULL) return;
896 if (attr->tree != NULL)
897 xmlFreeEnumeration(attr->tree);
898 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000899 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000900 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000901 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000902 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000903 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000904 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000905 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000906}
907
908/**
909 * xmlFreeAttributeTable:
910 * @table: An attribute table
911 *
912 * Deallocate the memory used by an entities hash table.
913 */
914void
915xmlFreeAttributeTable(xmlAttributeTablePtr table) {
916 int i;
917
918 if (table == NULL) return;
919
920 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000921 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000922 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000923 xmlFree(table->table);
924 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000925}
926
927/**
928 * xmlCopyAttributeTable:
929 * @table: An attribute table
930 *
931 * Build a copy of an attribute table.
932 *
933 * Returns the new xmlAttributeTablePtr or NULL in case of error.
934 */
935xmlAttributeTablePtr
936xmlCopyAttributeTable(xmlAttributeTablePtr table) {
937 xmlAttributeTablePtr ret;
938 xmlAttributePtr cur, attr;
939 int i;
940
Daniel Veillard6454aec1999-09-02 22:04:43 +0000941 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000942 if (ret == NULL) {
943 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
944 return(NULL);
945 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000946 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000947 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000948 if (ret->table == NULL) {
949 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000950 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000951 return(NULL);
952 }
953 ret->max_attributes = table->max_attributes;
954 ret->nb_attributes = table->nb_attributes;
955 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000956 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +0000957 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000958 if (cur == NULL) {
959 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000960 xmlFree(ret);
961 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000962 return(NULL);
963 }
964 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000965 cur->type = attr->type;
966 cur->def = attr->def;
967 cur->tree = xmlCopyEnumeration(attr->tree);
968 if (attr->elem != NULL)
969 cur->elem = xmlStrdup(attr->elem);
970 else
971 cur->elem = NULL;
972 if (attr->name != NULL)
973 cur->name = xmlStrdup(attr->name);
974 else
975 cur->name = NULL;
976 if (attr->defaultValue != NULL)
977 cur->defaultValue = xmlStrdup(attr->defaultValue);
978 else
979 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000980 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000981 }
982 return(ret);
983}
984
985/**
986 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000987 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +0000988 * @table: An attribute table
989 *
990 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +0000991 */
992void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000993xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000994 int i;
995 xmlAttributePtr cur;
996
997 if (table == NULL) return;
998
999 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001000 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001001 xmlBufferWriteChar(buf, "<!ATTLIST ");
1002 xmlBufferWriteCHAR(buf, cur->elem);
1003 xmlBufferWriteChar(buf, " ");
1004 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001005 switch (cur->type) {
1006 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001007 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001008 break;
1009 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001010 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001011 break;
1012 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001013 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001014 break;
1015 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001016 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001017 break;
1018 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001019 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001020 break;
1021 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001022 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001023 break;
1024 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001025 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001026 break;
1027 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001028 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001029 break;
1030 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001031 xmlBufferWriteChar(buf, " (");
1032 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001033 break;
1034 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001035 xmlBufferWriteChar(buf, " NOTATION (");
1036 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001037 break;
1038 default:
1039 fprintf(stderr,
1040 "xmlDumpAttributeTable: internal: unknown type %d\n",
1041 cur->type);
1042 }
1043 switch (cur->def) {
1044 case XML_ATTRIBUTE_NONE:
1045 break;
1046 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001047 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001048 break;
1049 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001050 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001051 break;
1052 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001053 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001054 break;
1055 default:
1056 fprintf(stderr,
1057 "xmlDumpAttributeTable: internal: unknown default %d\n",
1058 cur->def);
1059 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001060 if (cur->defaultValue != NULL) {
1061 xmlBufferWriteChar(buf, " ");
1062 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1063 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001064 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001065 }
1066}
1067
1068/************************************************************************
1069 * *
1070 * NOTATIONs *
1071 * *
1072 ************************************************************************/
1073/**
1074 * xmlCreateNotationTable:
1075 *
1076 * create and initialize an empty notation hash table.
1077 *
1078 * Returns the xmlNotationTablePtr just created or NULL in case
1079 * of error.
1080 */
1081xmlNotationTablePtr
1082xmlCreateNotationTable(void) {
1083 xmlNotationTablePtr ret;
1084
1085 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001086 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001087 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001088 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001089 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001090 return(NULL);
1091 }
1092 ret->max_notations = XML_MIN_NOTATION_TABLE;
1093 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001094 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001095 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001096 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001097 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001098 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001099 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001100 return(NULL);
1101 }
1102 return(ret);
1103}
1104
1105
1106/**
1107 * xmlAddNotationDecl:
1108 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001109 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001110 * @name: the entity name
1111 * @PublicID: the public identifier or NULL
1112 * @SystemID: the system identifier or NULL
1113 *
1114 * Register a new notation declaration
1115 *
1116 * Returns NULL if not, othervise the entity
1117 */
1118xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001119xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1120 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001121 xmlNotationPtr ret, cur;
1122 xmlNotationTablePtr table;
1123 int i;
1124
1125 if (dtd == NULL) {
1126 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1127 return(NULL);
1128 }
1129 if (name == NULL) {
1130 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1131 return(NULL);
1132 }
1133 if ((PublicID == NULL) && (SystemID == NULL)) {
1134 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1135 }
1136
1137 /*
1138 * Create the Notation table if needed.
1139 */
1140 table = dtd->notations;
1141 if (table == NULL)
1142 table = dtd->notations = xmlCreateNotationTable();
1143 if (table == NULL) {
1144 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1145 return(NULL);
1146 }
1147
1148 /*
1149 * Validity Check:
1150 * Search the DTD for previous declarations of the ATTLIST
1151 */
1152 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001153 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001154 if (!xmlStrcmp(cur->name, name)) {
1155 /*
1156 * The notation is already defined in this Dtd.
1157 */
1158 fprintf(stderr,
1159 "xmlAddNotationDecl: %s already defined\n", name);
1160 }
1161 }
1162
1163 /*
1164 * Grow the table, if needed.
1165 */
1166 if (table->nb_notations >= table->max_notations) {
1167 /*
1168 * need more notations.
1169 */
1170 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001171 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001172 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001173 sizeof(xmlNotationPtr));
1174 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001175 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1176 return(NULL);
1177 }
1178 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001179 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001180 if (ret == NULL) {
1181 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1182 return(NULL);
1183 }
1184 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001185
1186 /*
1187 * fill the structure.
1188 */
1189 ret->name = xmlStrdup(name);
1190 if (SystemID != NULL)
1191 ret->SystemID = xmlStrdup(SystemID);
1192 else
1193 ret->SystemID = NULL;
1194 if (PublicID != NULL)
1195 ret->PublicID = xmlStrdup(PublicID);
1196 else
1197 ret->PublicID = NULL;
1198 table->nb_notations++;
1199
1200 return(ret);
1201}
1202
1203/**
1204 * xmlFreeNotation:
1205 * @not: A notation
1206 *
1207 * Deallocate the memory used by an notation definition
1208 */
1209void
1210xmlFreeNotation(xmlNotationPtr nota) {
1211 if (nota == NULL) return;
1212 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001213 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001214 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001215 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001216 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001217 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001218 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001219 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001220}
1221
1222/**
1223 * xmlFreeNotationTable:
1224 * @table: An notation table
1225 *
1226 * Deallocate the memory used by an entities hash table.
1227 */
1228void
1229xmlFreeNotationTable(xmlNotationTablePtr table) {
1230 int i;
1231
1232 if (table == NULL) return;
1233
1234 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001235 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001236 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001237 xmlFree(table->table);
1238 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001239}
1240
1241/**
1242 * xmlCopyNotationTable:
1243 * @table: A notation table
1244 *
1245 * Build a copy of a notation table.
1246 *
1247 * Returns the new xmlNotationTablePtr or NULL in case of error.
1248 */
1249xmlNotationTablePtr
1250xmlCopyNotationTable(xmlNotationTablePtr table) {
1251 xmlNotationTablePtr ret;
1252 xmlNotationPtr cur, nota;
1253 int i;
1254
Daniel Veillard6454aec1999-09-02 22:04:43 +00001255 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001256 if (ret == NULL) {
1257 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1258 return(NULL);
1259 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001260 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001261 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001262 if (ret->table == NULL) {
1263 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001264 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001265 return(NULL);
1266 }
1267 ret->max_notations = table->max_notations;
1268 ret->nb_notations = table->nb_notations;
1269 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001270 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001271 if (cur == NULL) {
1272 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001273 xmlFree(ret);
1274 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001275 return(NULL);
1276 }
1277 ret->table[i] = cur;
1278 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001279 if (nota->name != NULL)
1280 cur->name = xmlStrdup(nota->name);
1281 else
1282 cur->name = NULL;
1283 if (nota->PublicID != NULL)
1284 cur->PublicID = xmlStrdup(nota->PublicID);
1285 else
1286 cur->PublicID = NULL;
1287 if (nota->SystemID != NULL)
1288 cur->SystemID = xmlStrdup(nota->SystemID);
1289 else
1290 cur->SystemID = NULL;
1291 }
1292 return(ret);
1293}
1294
1295/**
1296 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001297 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001298 * @table: A notation table
1299 *
1300 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001301 */
1302void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001303xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001304 int i;
1305 xmlNotationPtr cur;
1306
1307 if (table == NULL) return;
1308
1309 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001310 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001311 xmlBufferWriteChar(buf, "<!NOTATION ");
1312 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001313 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001314 xmlBufferWriteChar(buf, " PUBLIC ");
1315 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001316 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001317 xmlBufferWriteChar(buf, " ");
1318 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001319 }
1320 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001321 xmlBufferWriteChar(buf, " SYSTEM ");
1322 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001323 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001324 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001325 }
1326}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001327
1328/************************************************************************
1329 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001330 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001331 * *
1332 ************************************************************************/
1333/**
1334 * xmlCreateIDTable:
1335 *
1336 * create and initialize an empty id hash table.
1337 *
1338 * Returns the xmlIDTablePtr just created or NULL in case
1339 * of error.
1340 */
1341xmlIDTablePtr
1342xmlCreateIDTable(void) {
1343 xmlIDTablePtr ret;
1344
1345 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001346 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001347 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001348 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001349 (long)sizeof(xmlIDTable));
1350 return(NULL);
1351 }
1352 ret->max_ids = XML_MIN_NOTATION_TABLE;
1353 ret->nb_ids = 0;
1354 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001355 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001356 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001357 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001358 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001359 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001360 return(NULL);
1361 }
1362 return(ret);
1363}
1364
1365
1366/**
1367 * xmlAddID:
1368 * @ctxt: the validation context
1369 * @doc: pointer to the document
1370 * @value: the value name
1371 * @attr: the attribute holding the ID
1372 *
1373 * Register a new id declaration
1374 *
1375 * Returns NULL if not, othervise the new xmlIDPtr
1376 */
1377xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001378xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001379 xmlAttrPtr attr) {
1380 xmlIDPtr ret, cur;
1381 xmlIDTablePtr table;
1382 int i;
1383
1384 if (doc == NULL) {
1385 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1386 return(NULL);
1387 }
1388 if (value == NULL) {
1389 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1390 return(NULL);
1391 }
1392 if (attr == NULL) {
1393 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1394 return(NULL);
1395 }
1396
1397 /*
1398 * Create the ID table if needed.
1399 */
1400 table = doc->ids;
1401 if (table == NULL)
1402 table = doc->ids = xmlCreateIDTable();
1403 if (table == NULL) {
1404 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1405 return(NULL);
1406 }
1407
1408 /*
1409 * Validity Check:
1410 * Search the DTD for previous declarations of the ATTLIST
1411 */
1412 for (i = 0;i < table->nb_ids;i++) {
1413 cur = table->table[i];
1414 if (!xmlStrcmp(cur->value, value)) {
1415 /*
1416 * The id is already defined in this Dtd.
1417 */
1418 VERROR(ctxt->userData, "ID %s already defined\n", value);
1419 return(NULL);
1420 }
1421 }
1422
1423 /*
1424 * Grow the table, if needed.
1425 */
1426 if (table->nb_ids >= table->max_ids) {
1427 /*
1428 * need more ids.
1429 */
1430 table->max_ids *= 2;
1431 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001432 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001433 sizeof(xmlIDPtr));
1434 if (table->table == NULL) {
1435 fprintf(stderr, "xmlAddID: out of memory\n");
1436 return(NULL);
1437 }
1438 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001439 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001440 if (ret == NULL) {
1441 fprintf(stderr, "xmlAddID: out of memory\n");
1442 return(NULL);
1443 }
1444 table->table[table->nb_ids] = ret;
1445
1446 /*
1447 * fill the structure.
1448 */
1449 ret->value = xmlStrdup(value);
1450 ret->attr = attr;
1451 table->nb_ids++;
1452
1453 return(ret);
1454}
1455
1456/**
1457 * xmlFreeID:
1458 * @not: A id
1459 *
1460 * Deallocate the memory used by an id definition
1461 */
1462void
1463xmlFreeID(xmlIDPtr id) {
1464 if (id == NULL) return;
1465 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001466 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001467 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001468 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001469}
1470
1471/**
1472 * xmlFreeIDTable:
1473 * @table: An id table
1474 *
1475 * Deallocate the memory used by an ID hash table.
1476 */
1477void
1478xmlFreeIDTable(xmlIDTablePtr table) {
1479 int i;
1480
1481 if (table == NULL) return;
1482
1483 for (i = 0;i < table->nb_ids;i++) {
1484 xmlFreeID(table->table[i]);
1485 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001486 xmlFree(table->table);
1487 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001488}
1489
1490/**
1491 * xmlIsID
1492 * @doc: the document
1493 * @elem: the element carrying the attribute
1494 * @attr: the attribute
1495 *
1496 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1497 * then this is simple, otherwise we use an heuristic: name ID (upper
1498 * or lowercase).
1499 *
1500 * Returns 0 or 1 depending on the lookup result
1501 */
1502int
1503xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1504 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1505 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1506 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1507 (attr->name[2] == 0)) return(1);
1508 } else {
1509 xmlAttributePtr attrDecl;
1510
1511 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1512 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1513 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1514 attr->name);
1515
Daniel Veillardb96e6431999-08-29 21:02:19 +00001516 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001517 return(1);
1518 }
1519 return(0);
1520}
1521
Daniel Veillardb96e6431999-08-29 21:02:19 +00001522/**
1523 * xmlGetID:
1524 * @doc: pointer to the document
1525 * @ID: the ID value
1526 *
1527 * Search the attribute declaring the given ID
1528 *
1529 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1530 */
1531xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001532xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001533 xmlIDPtr cur;
1534 xmlIDTablePtr table;
1535 int i;
1536
1537 if (doc == NULL) {
1538 fprintf(stderr, "xmlGetID: doc == NULL\n");
1539 return(NULL);
1540 }
1541
1542 if (ID == NULL) {
1543 fprintf(stderr, "xmlGetID: ID == NULL\n");
1544 return(NULL);
1545 }
1546
1547 table = doc->ids;
1548 if (table == NULL)
1549 return(NULL);
1550
1551 /*
1552 * Search the ID list.
1553 */
1554 for (i = 0;i < table->nb_ids;i++) {
1555 cur = table->table[i];
1556 if (!xmlStrcmp(cur->value, ID)) {
1557 return(cur->attr);
1558 }
1559 }
1560 return(NULL);
1561}
1562
Daniel Veillard991e63d1999-08-15 23:32:28 +00001563/************************************************************************
1564 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001565 * Refs *
1566 * *
1567 ************************************************************************/
1568/**
1569 * xmlCreateRefTable:
1570 *
1571 * create and initialize an empty ref hash table.
1572 *
1573 * Returns the xmlRefTablePtr just created or NULL in case
1574 * of error.
1575 */
1576xmlRefTablePtr
1577xmlCreateRefTable(void) {
1578 xmlRefTablePtr ret;
1579
1580 ret = (xmlRefTablePtr)
1581 xmlMalloc(sizeof(xmlRefTable));
1582 if (ret == NULL) {
1583 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1584 (long)sizeof(xmlRefTable));
1585 return(NULL);
1586 }
1587 ret->max_refs = XML_MIN_NOTATION_TABLE;
1588 ret->nb_refs = 0;
1589 ret->table = (xmlRefPtr *)
1590 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1591 if (ret == NULL) {
1592 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1593 ret->max_refs * (long)sizeof(xmlRef));
1594 xmlFree(ret);
1595 return(NULL);
1596 }
1597 return(ret);
1598}
1599
1600
1601/**
1602 * xmlAddRef:
1603 * @ctxt: the validation context
1604 * @doc: pointer to the document
1605 * @value: the value name
1606 * @attr: the attribute holding the Ref
1607 *
1608 * Register a new ref declaration
1609 *
1610 * Returns NULL if not, othervise the new xmlRefPtr
1611 */
1612xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001613xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001614 xmlAttrPtr attr) {
1615 xmlRefPtr ret;
1616 xmlRefTablePtr table;
1617
1618 if (doc == NULL) {
1619 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1620 return(NULL);
1621 }
1622 if (value == NULL) {
1623 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1624 return(NULL);
1625 }
1626 if (attr == NULL) {
1627 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1628 return(NULL);
1629 }
1630
1631 /*
1632 * Create the Ref table if needed.
1633 */
1634 table = doc->refs;
1635 if (table == NULL)
1636 table = doc->refs = xmlCreateRefTable();
1637 if (table == NULL) {
1638 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1639 return(NULL);
1640 }
1641
1642 /*
1643 * Grow the table, if needed.
1644 */
1645 if (table->nb_refs >= table->max_refs) {
1646 /*
1647 * need more refs.
1648 */
1649 table->max_refs *= 2;
1650 table->table = (xmlRefPtr *)
1651 xmlRealloc(table->table, table->max_refs *
1652 sizeof(xmlRefPtr));
1653 if (table->table == NULL) {
1654 fprintf(stderr, "xmlAddRef: out of memory\n");
1655 return(NULL);
1656 }
1657 }
1658 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1659 if (ret == NULL) {
1660 fprintf(stderr, "xmlAddRef: out of memory\n");
1661 return(NULL);
1662 }
1663 table->table[table->nb_refs] = ret;
1664
1665 /*
1666 * fill the structure.
1667 */
1668 ret->value = xmlStrdup(value);
1669 ret->attr = attr;
1670 table->nb_refs++;
1671
1672 return(ret);
1673}
1674
1675/**
1676 * xmlFreeRef:
1677 * @not: A ref
1678 *
1679 * Deallocate the memory used by an ref definition
1680 */
1681void
1682xmlFreeRef(xmlRefPtr ref) {
1683 if (ref == NULL) return;
1684 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001685 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001686 memset(ref, -1, sizeof(xmlRef));
1687 xmlFree(ref);
1688}
1689
1690/**
1691 * xmlFreeRefTable:
1692 * @table: An ref table
1693 *
1694 * Deallocate the memory used by an Ref hash table.
1695 */
1696void
1697xmlFreeRefTable(xmlRefTablePtr table) {
1698 int i;
1699
1700 if (table == NULL) return;
1701
1702 for (i = 0;i < table->nb_refs;i++) {
1703 xmlFreeRef(table->table[i]);
1704 }
1705 xmlFree(table->table);
1706 xmlFree(table);
1707}
1708
1709/**
1710 * xmlIsRef
1711 * @doc: the document
1712 * @elem: the element carrying the attribute
1713 * @attr: the attribute
1714 *
1715 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1716 * then this is simple, otherwise we use an heuristic: name Ref (upper
1717 * or lowercase).
1718 *
1719 * Returns 0 or 1 depending on the lookup result
1720 */
1721int
1722xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1723 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1724 return(0);
1725 /*******************
1726 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1727 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1728 (attr->name[2] == 0)) return(1);
1729 *******************/
1730 } else {
1731 xmlAttributePtr attrDecl;
1732
1733 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1734 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1735 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1736 attr->name);
1737
1738 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1739 return(1);
1740 }
1741 return(0);
1742}
1743
1744/**
1745 * xmlGetRef:
1746 * @doc: pointer to the document
1747 * @Ref: the Ref value
1748 *
1749 * Search the attribute declaring the given Ref
1750 *
1751 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1752 */
1753xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001754xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001755 xmlRefPtr cur;
1756 xmlRefTablePtr table;
1757 int i;
1758
1759 if (doc == NULL) {
1760 fprintf(stderr, "xmlGetRef: doc == NULL\n");
1761 return(NULL);
1762 }
1763
1764 if (Ref == NULL) {
1765 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1766 return(NULL);
1767 }
1768
1769 table = doc->refs;
1770 if (table == NULL)
1771 return(NULL);
1772
1773 /*
1774 * Search the Ref list.
1775 */
1776 for (i = 0;i < table->nb_refs;i++) {
1777 cur = table->table[i];
1778 if (!xmlStrcmp(cur->value, Ref)) {
1779 return(cur->attr);
1780 }
1781 }
1782 return(NULL);
1783}
1784
1785/************************************************************************
1786 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001787 * Routines for validity checking *
1788 * *
1789 ************************************************************************/
1790
1791/**
1792 * xmlGetDtdElementDesc:
1793 * @dtd: a pointer to the DtD to search
1794 * @name: the element name
1795 *
1796 * Search the Dtd for the description of this element
1797 *
1798 * returns the xmlElementPtr if found or NULL
1799 */
1800
1801xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001802xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001803 xmlElementTablePtr table;
1804 xmlElementPtr cur;
1805 int i;
1806
1807 if (dtd == NULL) return(NULL);
1808 if (dtd->elements == NULL) return(NULL);
1809 table = dtd->elements;
1810
1811 for (i = 0;i < table->nb_elements;i++) {
1812 cur = table->table[i];
1813 if (!xmlStrcmp(cur->name, name))
1814 return(cur);
1815 }
1816 return(NULL);
1817}
1818
1819/**
1820 * xmlGetDtdAttrDesc:
1821 * @dtd: a pointer to the DtD to search
1822 * @elem: the element name
1823 * @name: the attribute name
1824 *
1825 * Search the Dtd for the description of this attribute on
1826 * this element.
1827 *
1828 * returns the xmlAttributePtr if found or NULL
1829 */
1830
1831xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001832xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001833 xmlAttributeTablePtr table;
1834 xmlAttributePtr cur;
1835 int i;
1836
1837 if (dtd == NULL) return(NULL);
1838 if (dtd->attributes == NULL) return(NULL);
1839 table = dtd->attributes;
1840
1841 for (i = 0;i < table->nb_attributes;i++) {
1842 cur = table->table[i];
1843 if ((!xmlStrcmp(cur->name, name)) &&
1844 (!xmlStrcmp(cur->elem, elem)))
1845 return(cur);
1846 }
1847 return(NULL);
1848}
1849
1850/**
1851 * xmlGetDtdNotationDesc:
1852 * @dtd: a pointer to the DtD to search
1853 * @name: the notation name
1854 *
1855 * Search the Dtd for the description of this notation
1856 *
1857 * returns the xmlNotationPtr if found or NULL
1858 */
1859
1860xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001861xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001862 xmlNotationTablePtr table;
1863 xmlNotationPtr cur;
1864 int i;
1865
1866 if (dtd == NULL) return(NULL);
1867 if (dtd->notations == NULL) return(NULL);
1868 table = dtd->notations;
1869
1870 for (i = 0;i < table->nb_notations;i++) {
1871 cur = table->table[i];
1872 if (!xmlStrcmp(cur->name, name))
1873 return(cur);
1874 }
1875 return(NULL);
1876}
1877
1878/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001879 * xmlValidateNotationUse:
1880 * @ctxt: the validation context
1881 * @doc: the document
1882 * @notationName: the notation name to check
1883 *
1884 * Validate that the given mame match a notation declaration.
1885 * - [ VC: Notation Declared ]
1886 *
1887 * returns 1 if valid or 0 otherwise
1888 */
1889
1890int
1891xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001892 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001893 xmlNotationPtr notaDecl;
1894 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1895
1896 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1897 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1898 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1899
1900 if (notaDecl == NULL) {
1901 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1902 notationName);
1903 return(0);
1904 }
1905 return(1);
1906}
1907
1908/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001909 * xmlIsMixedElement
1910 * @doc: the document
1911 * @name: the element name
1912 *
1913 * Search in the DtDs whether an element accept Mixed content (or ANY)
1914 * basically if it is supposed to accept text childs
1915 *
1916 * returns 0 if no, 1 if yes, and -1 if no element description is available
1917 */
1918
1919int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001920xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001921 xmlElementPtr elemDecl;
1922
1923 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1924
1925 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1926 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1927 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1928 if (elemDecl == NULL) return(-1);
1929 switch (elemDecl->type) {
1930 case XML_ELEMENT_TYPE_ELEMENT:
1931 return(0);
1932 case XML_ELEMENT_TYPE_EMPTY:
1933 /*
1934 * return 1 for EMPTY since we want VC error to pop up
1935 * on <empty> </empty> for example
1936 */
1937 case XML_ELEMENT_TYPE_ANY:
1938 case XML_ELEMENT_TYPE_MIXED:
1939 return(1);
1940 }
1941 return(1);
1942}
1943
1944/**
1945 * xmlValidateNameValue:
1946 * @value: an Name value
1947 *
1948 * Validate that the given value match Name production
1949 *
1950 * returns 1 if valid or 0 otherwise
1951 */
1952
1953int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001954xmlValidateNameValue(const xmlChar *value) {
1955 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001956
1957 if (value == NULL) return(0);
1958 cur = value;
1959
1960 if (!IS_LETTER(*cur) && (*cur != '_') &&
1961 (*cur != ':')) {
1962 return(0);
1963 }
1964
1965 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1966 (*cur == '.') || (*cur == '-') ||
1967 (*cur == '_') || (*cur == ':') ||
1968 (IS_COMBINING(*cur)) ||
1969 (IS_EXTENDER(*cur)))
1970 cur++;
1971
1972 if (*cur != 0) return(0);
1973
1974 return(1);
1975}
1976
1977/**
1978 * xmlValidateNamesValue:
1979 * @value: an Names value
1980 *
1981 * Validate that the given value match Names production
1982 *
1983 * returns 1 if valid or 0 otherwise
1984 */
1985
1986int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001987xmlValidateNamesValue(const xmlChar *value) {
1988 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001989
1990 if (value == NULL) return(0);
1991 cur = value;
1992
1993 if (!IS_LETTER(*cur) && (*cur != '_') &&
1994 (*cur != ':')) {
1995 return(0);
1996 }
1997
1998 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1999 (*cur == '.') || (*cur == '-') ||
2000 (*cur == '_') || (*cur == ':') ||
2001 (IS_COMBINING(*cur)) ||
2002 (IS_EXTENDER(*cur)))
2003 cur++;
2004
2005 while (IS_BLANK(*cur)) {
2006 while (IS_BLANK(*cur)) cur++;
2007
2008 if (!IS_LETTER(*cur) && (*cur != '_') &&
2009 (*cur != ':')) {
2010 return(0);
2011 }
2012
2013 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2014 (*cur == '.') || (*cur == '-') ||
2015 (*cur == '_') || (*cur == ':') ||
2016 (IS_COMBINING(*cur)) ||
2017 (IS_EXTENDER(*cur)))
2018 cur++;
2019 }
2020
2021 if (*cur != 0) return(0);
2022
2023 return(1);
2024}
2025
2026/**
2027 * xmlValidateNmtokenValue:
2028 * @value: an Mntoken value
2029 *
2030 * Validate that the given value match Nmtoken production
2031 *
2032 * [ VC: Name Token ]
2033 *
2034 * returns 1 if valid or 0 otherwise
2035 */
2036
2037int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002038xmlValidateNmtokenValue(const xmlChar *value) {
2039 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002040
2041 if (value == NULL) return(0);
2042 cur = value;
2043
2044 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2045 (*cur != '.') && (*cur != '-') &&
2046 (*cur != '_') && (*cur != ':') &&
2047 (!IS_COMBINING(*cur)) &&
2048 (!IS_EXTENDER(*cur)))
2049 return(0);
2050
2051 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2052 (*cur == '.') || (*cur == '-') ||
2053 (*cur == '_') || (*cur == ':') ||
2054 (IS_COMBINING(*cur)) ||
2055 (IS_EXTENDER(*cur)))
2056 cur++;
2057
2058 if (*cur != 0) return(0);
2059
2060 return(1);
2061 return(1);
2062}
2063
2064/**
2065 * xmlValidateNmtokensValue:
2066 * @value: an Mntokens value
2067 *
2068 * Validate that the given value match Nmtokens production
2069 *
2070 * [ VC: Name Token ]
2071 *
2072 * returns 1 if valid or 0 otherwise
2073 */
2074
2075int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002076xmlValidateNmtokensValue(const xmlChar *value) {
2077 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002078
2079 if (value == NULL) return(0);
2080 cur = value;
2081
2082 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2083 (*cur != '.') && (*cur != '-') &&
2084 (*cur != '_') && (*cur != ':') &&
2085 (!IS_COMBINING(*cur)) &&
2086 (!IS_EXTENDER(*cur)))
2087 return(0);
2088
2089 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2090 (*cur == '.') || (*cur == '-') ||
2091 (*cur == '_') || (*cur == ':') ||
2092 (IS_COMBINING(*cur)) ||
2093 (IS_EXTENDER(*cur)))
2094 cur++;
2095
2096 while (IS_BLANK(*cur)) {
2097 while (IS_BLANK(*cur)) cur++;
2098
2099 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2100 (*cur != '.') && (*cur != '-') &&
2101 (*cur != '_') && (*cur != ':') &&
2102 (!IS_COMBINING(*cur)) &&
2103 (!IS_EXTENDER(*cur)))
2104 return(0);
2105
2106 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2107 (*cur == '.') || (*cur == '-') ||
2108 (*cur == '_') || (*cur == ':') ||
2109 (IS_COMBINING(*cur)) ||
2110 (IS_EXTENDER(*cur)))
2111 cur++;
2112 }
2113
2114 if (*cur != 0) return(0);
2115
2116 return(1);
2117}
2118
2119/**
2120 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002121 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002122 * @doc: a document instance
2123 * @nota: a notation definition
2124 *
2125 * Try to validate a single notation definition
2126 * basically it does the following checks as described by the
2127 * XML-1.0 recommendation:
2128 * - it seems that no validity constraing exist on notation declarations
2129 * But this function get called anyway ...
2130 *
2131 * returns 1 if valid or 0 otherwise
2132 */
2133
2134int
2135xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2136 xmlNotationPtr nota) {
2137 int ret = 1;
2138
2139 return(ret);
2140}
2141
2142/**
2143 * xmlValidateAttributeValue:
2144 * @type: an attribute type
2145 * @value: an attribute value
2146 *
2147 * Validate that the given attribute value match the proper production
2148 *
2149 * [ VC: ID ]
2150 * Values of type ID must match the Name production....
2151 *
2152 * [ VC: IDREF ]
2153 * Values of type IDREF must match the Name production, and values
2154 * of type IDREFS must match Names ...
2155 *
2156 * [ VC: Entity Name ]
2157 * Values of type ENTITY must match the Name production, values
2158 * of type ENTITIES must match Names ...
2159 *
2160 * [ VC: Name Token ]
2161 * Values of type NMTOKEN must match the Nmtoken production; values
2162 * of type NMTOKENS must match Nmtokens.
2163 *
2164 * returns 1 if valid or 0 otherwise
2165 */
2166
2167int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002168xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002169 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002170 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002171 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002172 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002173 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002174 case XML_ATTRIBUTE_IDREF:
2175 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002176 case XML_ATTRIBUTE_NOTATION:
2177 return(xmlValidateNameValue(value));
2178 case XML_ATTRIBUTE_NMTOKENS:
2179 case XML_ATTRIBUTE_ENUMERATION:
2180 return(xmlValidateNmtokensValue(value));
2181 case XML_ATTRIBUTE_NMTOKEN:
2182 return(xmlValidateNmtokenValue(value));
2183 case XML_ATTRIBUTE_CDATA:
2184 break;
2185 }
2186 return(1);
2187}
2188
2189/**
2190 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002191 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002192 * @doc: a document instance
2193 * @attr: an attribute definition
2194 *
2195 * Try to validate a single attribute definition
2196 * basically it does the following checks as described by the
2197 * XML-1.0 recommendation:
2198 * - [ VC: Attribute Default Legal ]
2199 * - [ VC: Enumeration ]
2200 * - [ VC: ID Attribute Default ]
2201 *
2202 * The ID/IDREF uniqueness and matching are done separately
2203 *
2204 * returns 1 if valid or 0 otherwise
2205 */
2206
2207int
2208xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2209 xmlAttributePtr attr) {
2210 int ret = 1;
2211 int val;
2212 CHECK_DTD;
2213 if(attr == NULL) return(1);
2214
2215 /* Attribute Default Legal */
2216 /* Enumeration */
2217 if (attr->defaultValue != NULL) {
2218 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2219 if (val == 0) {
2220 VERROR(ctxt->userData,
2221 "Syntax of default value for attribute %s on %s is not valid\n",
2222 attr->name, attr->elem);
2223 }
2224 ret &= val;
2225 }
2226
2227 /* ID Attribute Default */
2228 if ((attr->type == XML_ATTRIBUTE_ID)&&
2229 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2230 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2231 VERROR(ctxt->userData,
2232 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2233 attr->name, attr->elem);
2234 ret = 0;
2235 }
2236
Daniel Veillardb96e6431999-08-29 21:02:19 +00002237 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002238 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2239 int nbId = 0;
2240
2241 /* the trick is taht we parse DtD as their own internal subset */
2242 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2243 attr->elem);
2244 if (elem != NULL) {
2245 nbId = xmlScanIDAttributeDecl(NULL, elem);
2246 }
2247 if (nbId >= 1)
2248 VERROR(ctxt->userData,
2249 "Element %s has ID attribute defined in the external subset : %s\n",
2250 attr->elem, attr->name);
2251 }
2252
2253 return(ret);
2254}
2255
2256/**
2257 * xmlValidateElementDecl:
2258 * @ctxt: the validation context
2259 * @doc: a document instance
2260 * @elem: an element definition
2261 *
2262 * Try to validate a single element definition
2263 * basically it does the following checks as described by the
2264 * XML-1.0 recommendation:
2265 * - [ VC: One ID per Element Type ]
2266 * - [ VC: No Duplicate Types ]
2267 * - [ VC: Unique Element Type Declaration ]
2268 *
2269 * returns 1 if valid or 0 otherwise
2270 */
2271
2272int
2273xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2274 xmlElementPtr elem) {
2275 int ret = 1;
2276 xmlElementPtr tst;
2277
2278 CHECK_DTD;
2279
2280 if (elem == NULL) return(1);
2281
2282 /* No Duplicate Types */
2283 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2284 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002285 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002286
2287 cur = elem->content;
2288 while (cur != NULL) {
2289 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2290 if (cur->c1 == NULL) break;
2291 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2292 name = cur->c1->name;
2293 next = cur->c2;
2294 while (next != NULL) {
2295 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2296 if (!xmlStrcmp(next->name, name)) {
2297 VERROR(ctxt->userData,
2298 "Definition of %s has duplicate references of %s\n",
2299 elem->name, name);
2300 ret = 0;
2301 }
2302 break;
2303 }
2304 if (next->c1 == NULL) break;
2305 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2306 if (!xmlStrcmp(next->c1->name, name)) {
2307 VERROR(ctxt->userData,
2308 "Definition of %s has duplicate references of %s\n",
2309 elem->name, name);
2310 ret = 0;
2311 }
2312 next = next->c2;
2313 }
2314 }
2315 cur = cur->c2;
2316 }
2317 }
2318
2319 /* VC: Unique Element Type Declaration */
2320 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2321 if ((tst != NULL ) && (tst != elem)) {
2322 VERROR(ctxt->userData, "Redefinition of element %s\n",
2323 elem->name);
2324 ret = 0;
2325 }
2326 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2327 if ((tst != NULL ) && (tst != elem)) {
2328 VERROR(ctxt->userData, "Redefinition of element %s\n",
2329 elem->name);
2330 ret = 0;
2331 }
2332
2333 /* One ID per Element Type */
2334 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2335 ret = 0;
2336 }
2337 return(ret);
2338}
2339
2340/**
2341 * xmlValidateOneAttribute:
2342 * @ctxt: the validation context
2343 * @doc: a document instance
2344 * @elem: an element instance
2345 * @attr: an attribute instance
2346 *
2347 * Try to validate a single attribute for an element
2348 * basically it * does the following checks as described by the
2349 * XML-1.0 recommendation:
2350 * - [ VC: Attribute Value Type ]
2351 * - [ VC: Fixed Attribute Default ]
2352 * - [ VC: Entity Name ]
2353 * - [ VC: Name Token ]
2354 * - [ VC: ID ]
2355 * - [ VC: IDREF ]
2356 * - [ VC: Entity Name ]
2357 * - [ VC: Notation Attributes ]
2358 *
2359 * The ID/IDREF uniqueness and matching are done separately
2360 *
2361 * returns 1 if valid or 0 otherwise
2362 */
2363
2364int
2365xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002366 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002367 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002368 xmlAttributePtr attrDecl;
2369 int val;
2370 int ret = 1;
2371
2372 CHECK_DTD;
2373 if ((elem == NULL) || (elem->name == NULL)) return(0);
2374 if ((attr == NULL) || (attr->name == NULL)) return(0);
2375
2376 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2377 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2378 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2379
2380
2381 /* Validity Constraint: Attribute Value Type */
2382 if (attrDecl == NULL) {
2383 VERROR(ctxt->userData,
2384 "No declaration for attribute %s on element %s\n",
2385 attr->name, elem->name);
2386 return(0);
2387 }
2388 val = xmlValidateAttributeValue(attrDecl->type, value);
2389 if (val == 0) {
2390 VERROR(ctxt->userData,
2391 "Syntax of value for attribute %s on %s is not valid\n",
2392 attr->name, elem->name);
2393 ret = 0;
2394 }
2395
Daniel Veillardb96e6431999-08-29 21:02:19 +00002396 /* Validity Constraint: ID uniqueness */
2397 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2398 xmlAddID(ctxt, doc, value, attr);
2399 }
2400
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002401 if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2402 xmlAddRef(ctxt, doc, value, attr);
2403 }
2404
Daniel Veillardb05deb71999-08-10 19:04:08 +00002405 /* Validity Constraint: Notation Attributes */
2406 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2407 xmlEnumerationPtr tree = attrDecl->tree;
2408 xmlNotationPtr nota;
2409
2410 /* First check that the given NOTATION was declared */
2411 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2412 if (nota == NULL)
2413 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2414
2415 if (nota == NULL) {
2416 VERROR(ctxt->userData,
2417 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2418 value, attr->name, elem->name);
2419 ret = 0;
2420 }
2421
2422 /* Second, verify that it's among the list */
2423 while (tree != NULL) {
2424 if (!xmlStrcmp(tree->name, value)) break;
2425 tree = tree->next;
2426 }
2427 if (tree == NULL) {
2428 VERROR(ctxt->userData,
2429 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2430 value, attr->name, elem->name);
2431 ret = 0;
2432 }
2433 }
2434
2435 /* Validity Constraint: Enumeration */
2436 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2437 xmlEnumerationPtr tree = attrDecl->tree;
2438 while (tree != NULL) {
2439 if (!xmlStrcmp(tree->name, value)) break;
2440 tree = tree->next;
2441 }
2442 if (tree == NULL) {
2443 VERROR(ctxt->userData,
2444 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2445 value, attr->name, elem->name);
2446 ret = 0;
2447 }
2448 }
2449
2450 /* Fixed Attribute Default */
2451 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2452 (xmlStrcmp(attrDecl->defaultValue, value))) {
2453 VERROR(ctxt->userData,
2454 "Value for attribute %s on %s must be \"%s\"\n",
2455 attr->name, elem->name, attrDecl->defaultValue);
2456 ret = 0;
2457 }
2458
Daniel Veillardb96e6431999-08-29 21:02:19 +00002459 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002460 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2461 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2462 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2463 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002464 return(0);
2465 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002466 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002467 return(ret);
2468}
2469
2470int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2471 xmlElementContentPtr cont);
2472
2473/**
2474 * xmlValidateElementTypeExpr:
2475 * @ctxt: the validation context
2476 * @child: pointer to the child list
2477 * @cont: pointer to the content declaration
2478 *
2479 * Try to validate the content of an element of type element
2480 * but don't handle the occurence factor
2481 *
2482 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2483 * also update child value in-situ.
2484 */
2485
2486int
2487xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2488 xmlElementContentPtr cont) {
2489 xmlNodePtr cur;
2490 int ret = 1;
2491
2492 if (cont == NULL) return(-1);
2493 while (*child != NULL) {
2494 if ((*child)->type == XML_PI_NODE) {
2495 *child = (*child)->next;
2496 continue;
2497 }
2498 if ((*child)->type == XML_COMMENT_NODE) {
2499 *child = (*child)->next;
2500 continue;
2501 }
2502 else if ((*child)->type != XML_ELEMENT_NODE) {
2503 return(-1);
2504 }
2505 break;
2506 }
2507 switch (cont->type) {
2508 case XML_ELEMENT_CONTENT_PCDATA:
2509 /* Internal error !!! */
2510 fprintf(stderr, "Internal: MIXED struct bad\n");
2511 return(-1);
2512 case XML_ELEMENT_CONTENT_ELEMENT:
2513 if (*child == NULL) return(0);
2514 ret = (!xmlStrcmp((*child)->name, cont->name));
2515 if (ret == 1)
2516 *child = (*child)->next;
2517 return(ret);
2518 case XML_ELEMENT_CONTENT_OR:
2519 cur = *child;
2520 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2521 if (ret == -1) return(-1);
2522 if (ret == 1) {
2523 return(1);
2524 }
2525 /* rollback and retry the other path */
2526 *child = cur;
2527 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2528 if (ret == -1) return(-1);
2529 if (ret == 0) {
2530 *child = cur;
2531 return(0);
2532 }
2533 return(1);
2534 case XML_ELEMENT_CONTENT_SEQ:
2535 cur = *child;
2536 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2537 if (ret == -1) return(-1);
2538 if (ret == 0) {
2539 *child = cur;
2540 return(0);
2541 }
2542 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2543 if (ret == -1) return(-1);
2544 if (ret == 0) {
2545 *child = cur;
2546 return(0);
2547 }
2548 return(1);
2549 }
2550 return(ret);
2551}
2552
2553/**
2554 * xmlValidateElementTypeElement:
2555 * @ctxt: the validation context
2556 * @child: pointer to the child list
2557 * @cont: pointer to the content declaration
2558 *
2559 * Try to validate the content of an element of type element
2560 * yeah, Yet Another Regexp Implementation, and recursive
2561 *
2562 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2563 * also update child and content values in-situ.
2564 */
2565
2566int
2567xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2568 xmlElementContentPtr cont) {
2569 xmlNodePtr cur;
2570 int ret = 1;
2571
2572 if (cont == NULL) return(-1);
2573 while (*child != NULL) {
2574 if ((*child)->type == XML_PI_NODE) {
2575 *child = (*child)->next;
2576 continue;
2577 }
2578 if ((*child)->type == XML_COMMENT_NODE) {
2579 *child = (*child)->next;
2580 continue;
2581 }
2582 else if ((*child)->type != XML_ELEMENT_NODE) {
2583 return(-1);
2584 }
2585 break;
2586 }
2587 cur = *child;
2588 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2589 if (ret == -1) return(-1);
2590 switch (cont->ocur) {
2591 case XML_ELEMENT_CONTENT_ONCE:
2592 if (ret == 1) {
2593 return(1);
2594 }
2595 *child = cur;
2596 return(0);
2597 case XML_ELEMENT_CONTENT_OPT:
2598 if (ret == 0) {
2599 *child = cur;
2600 return(1);
2601 }
2602 break;
2603 case XML_ELEMENT_CONTENT_MULT:
2604 if (ret == 0) {
2605 *child = cur;
2606 break;
2607 }
2608 /* no break on purpose */
2609 case XML_ELEMENT_CONTENT_PLUS:
2610 if (ret == 0) {
2611 *child = cur;
2612 return(0);
2613 }
2614 do {
2615 cur = *child;
2616 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2617 } while (ret == 1);
2618 if (ret == -1) return(-1);
2619 *child = cur;
2620 break;
2621 }
2622 while (*child != NULL) {
2623 if ((*child)->type == XML_PI_NODE) {
2624 *child = (*child)->next;
2625 continue;
2626 }
2627 if ((*child)->type == XML_COMMENT_NODE) {
2628 *child = (*child)->next;
2629 continue;
2630 }
2631 else if ((*child)->type != XML_ELEMENT_NODE) {
2632 return(-1);
2633 }
2634 break;
2635 }
2636 return(1);
2637}
2638
2639/**
2640 * xmlSprintfElementChilds:
2641 * @buf: an output buffer
2642 * @content: An element
2643 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2644 *
2645 * This will dump the list of childs to the buffer
2646 * Intended just for the debug routine
2647 */
2648void
2649xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2650 xmlNodePtr cur;
2651
2652 if (node == NULL) return;
2653 if (glob) strcat(buf, "(");
2654 cur = node->childs;
2655 while (cur != NULL) {
2656 switch (cur->type) {
2657 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002658 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002659 if (cur->next != NULL)
2660 strcat(buf, " ");
2661 break;
2662 case XML_TEXT_NODE:
2663 case XML_CDATA_SECTION_NODE:
2664 case XML_ENTITY_REF_NODE:
2665 strcat(buf, "CDATA");
2666 if (cur->next != NULL)
2667 strcat(buf, " ");
2668 break;
2669 case XML_ATTRIBUTE_NODE:
2670 case XML_DOCUMENT_NODE:
2671 case XML_DOCUMENT_TYPE_NODE:
2672 case XML_DOCUMENT_FRAG_NODE:
2673 case XML_NOTATION_NODE:
2674 strcat(buf, "???");
2675 if (cur->next != NULL)
2676 strcat(buf, " ");
2677 break;
2678 case XML_ENTITY_NODE:
2679 case XML_PI_NODE:
2680 case XML_COMMENT_NODE:
2681 break;
2682 }
2683 cur = cur->next;
2684 }
2685 if (glob) strcat(buf, ")");
2686}
2687
2688
2689/**
2690 * xmlValidateOneElement:
2691 * @ctxt: the validation context
2692 * @doc: a document instance
2693 * @elem: an element instance
2694 *
2695 * Try to validate a single element and it's attributes,
2696 * basically it does the following checks as described by the
2697 * XML-1.0 recommendation:
2698 * - [ VC: Element Valid ]
2699 * - [ VC: Required Attribute ]
2700 * Then call xmlValidateOneAttribute() for each attribute present.
2701 *
2702 * The ID/IDREF checkings are done separately
2703 *
2704 * returns 1 if valid or 0 otherwise
2705 */
2706
2707int
2708xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2709 xmlNodePtr elem) {
2710 xmlElementPtr elemDecl;
2711 xmlElementContentPtr cont;
2712 xmlNodePtr child;
2713 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002714 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002715
2716 CHECK_DTD;
2717
2718 if ((elem == NULL) || (elem->name == NULL)) return(0);
2719
2720 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2721 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2722 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2723 if (elemDecl == NULL) {
2724 VERROR(ctxt->userData, "No declaration for element %s\n",
2725 elem->name);
2726 return(0);
2727 }
2728
2729 /* Check taht the element content matches the definition */
2730 switch (elemDecl->type) {
2731 case XML_ELEMENT_TYPE_EMPTY:
2732 if (elem->childs != NULL) {
2733 VERROR(ctxt->userData,
2734 "Element %s was declared EMPTY this one has content\n",
2735 elem->name);
2736 ret = 0;
2737 }
2738 break;
2739 case XML_ELEMENT_TYPE_ANY:
2740 /* I don't think anything is required then */
2741 break;
2742 case XML_ELEMENT_TYPE_MIXED:
2743 /* Hum, this start to get messy */
2744 child = elem->childs;
2745 while (child != NULL) {
2746 if (child->type == XML_ELEMENT_NODE) {
2747 name = child->name;
2748 cont = elemDecl->content;
2749 while (cont != NULL) {
2750 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2751 if (!xmlStrcmp(cont->name, name)) break;
2752 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2753 (cont->c1 != NULL) &&
2754 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2755 if (!xmlStrcmp(cont->c1->name, name)) break;
2756 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2757 (cont->c1 == NULL) ||
2758 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2759 /* Internal error !!! */
2760 fprintf(stderr, "Internal: MIXED struct bad\n");
2761 break;
2762 }
2763 cont = cont->c2;
2764 }
2765 if (cont == NULL) {
2766 VERROR(ctxt->userData,
2767 "Element %s is not declared in %s list of possible childs\n",
2768 name, elem->name);
2769 ret = 0;
2770 }
2771 }
2772 child = child->next;
2773 }
2774 break;
2775 case XML_ELEMENT_TYPE_ELEMENT:
2776 child = elem->childs;
2777 cont = elemDecl->content;
2778 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2779 if ((ret == 0) || (child != NULL)) {
2780 char expr[1000];
2781 char list[2000];
2782
2783 expr[0] = 0;
2784 xmlSprintfElementContent(expr, cont, 1);
2785 list[0] = 0;
2786 xmlSprintfElementChilds(list, elem, 1);
2787
2788 VERROR(ctxt->userData,
2789 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2790 elem->name, expr, list);
2791 ret = 0;
2792 }
2793 break;
2794 }
2795
Daniel Veillardb96e6431999-08-29 21:02:19 +00002796 /* TODO - [ VC: Required Attribute ] */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002797 return(ret);
2798}
2799
2800/**
2801 * xmlValidateRoot:
2802 * @ctxt: the validation context
2803 * @doc: a document instance
2804 *
2805 * Try to validate a the root element
2806 * basically it does the following check as described by the
2807 * XML-1.0 recommendation:
2808 * - [ VC: Root Element Type ]
2809 * it doesn't try to recurse or apply other check to the element
2810 *
2811 * returns 1 if valid or 0 otherwise
2812 */
2813
2814int
2815xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2816 if (doc == NULL) return(0);
2817
2818 if ((doc->intSubset == NULL) ||
2819 (doc->intSubset->name == NULL)) {
2820 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2821 return(0);
2822 }
2823 if ((doc->root == NULL) || (doc->root->name == NULL)) {
2824 VERROR(ctxt->userData, "Not valid: no root element\n");
2825 return(0);
2826 }
2827 if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2828 VERROR(ctxt->userData,
2829 "Not valid: root and DtD name do not match %s and %s\n",
2830 doc->root->name, doc->intSubset->name);
2831 return(0);
2832 }
2833 return(1);
2834}
2835
2836
2837/**
2838 * xmlValidateElement:
2839 * @ctxt: the validation context
2840 * @doc: a document instance
2841 * @elem: an element instance
2842 *
2843 * Try to validate the subtree under an element
2844 *
2845 * returns 1 if valid or 0 otherwise
2846 */
2847
2848int
2849xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002850 xmlNodePtr child;
2851 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002852 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002853 int ret = 1;
2854
2855 /* TODO xmlValidateElement */
2856
2857 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002858 CHECK_DTD;
2859
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002860 ret &= xmlValidateOneElement(ctxt, doc, elem);
2861 attr = elem->properties;
2862 while(attr != NULL) {
2863 value = xmlNodeListGetString(doc, attr->val, 0);
2864 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
2865 if (value != NULL)
2866 free(value);
2867 attr= attr->next;
2868 }
2869 child = elem->childs;
2870 while (child != NULL) {
2871 ret &= xmlValidateElement(ctxt, doc, child);
2872 child = child->next;
2873 }
2874
2875 return(ret);
2876}
2877
2878/**
2879 * xmlValidateDocumentFinal:
2880 * @ctxt: the validation context
2881 * @doc: a document instance
2882 *
2883 * Does the final step for the document validation once all the
2884 * incremental validation steps have been completed
2885 *
2886 * basically it does the following checks described by the XML Rec
2887 *
2888 *
2889 * returns 1 if valid or 0 otherwise
2890 */
2891
2892int
2893xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2894 int ret = 1, i;
2895 xmlRefTablePtr table;
2896 xmlAttrPtr id;
2897
2898 if (doc == NULL) {
2899 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
2900 return(0);
2901 }
2902
2903 /*
2904 * Get the refs table
2905 */
2906 table = doc->refs;
2907 if (table != NULL) {
2908 for (i = 0; i < table->nb_refs; i++) {
2909 id = xmlGetID(doc, table->table[i]->value);
2910 if (id == NULL) {
2911 VERROR(ctxt->userData,
2912 "IDREF attribute %s reference an unknown ID '%s'\n",
2913 table->table[i]->attr->name, table->table[i]->value);
2914 ret = 0;
2915 }
2916 }
2917 }
2918 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002919}
2920
2921/**
2922 * xmlValidateDtd:
2923 * @ctxt: the validation context
2924 * @doc: a document instance
2925 * @dtd: a dtd instance
2926 *
2927 * Try to validate the dtd instance
2928 *
2929 * basically it does check all the definitions in the DtD.
2930 *
2931 * returns 1 if valid or 0 otherwise
2932 */
2933
2934int
2935xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002936 /* TODO xmlValidateDtd */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002937 return(1);
2938}
2939
2940/**
2941 * xmlValidateDocument:
2942 * @ctxt: the validation context
2943 * @doc: a document instance
2944 *
2945 * Try to validate the document instance
2946 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002947 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00002948 * i.e. validates the internal and external subset (if present)
2949 * and validate the document tree.
2950 *
2951 * returns 1 if valid or 0 otherwise
2952 */
2953
2954int
2955xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002956 int ret;
2957
Daniel Veillardb05deb71999-08-10 19:04:08 +00002958 if (!xmlValidateRoot(ctxt, doc)) return(0);
2959
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002960 ret = xmlValidateElement(ctxt, doc, doc->root);
2961 ret &= xmlValidateDocumentFinal(ctxt, doc);
2962 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002963}
2964