blob: 123a93c3b89dfe504caf4fc606445a2e9624a88b [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 Veillard00fdf371999-10-08 09:40:39 +0000300 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000301 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000302 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000303 * @type: the element type
304 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000305 *
306 * Register a new element declaration
307 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000308 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000309 */
310xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000311xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillardc26087b1999-08-30 11:23:51 +0000312 xmlElementContentType type, xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000313 xmlElementPtr ret, cur;
314 xmlElementTablePtr table;
315 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000316
317 if (dtd == NULL) {
318 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
319 return(NULL);
320 }
321 if (name == NULL) {
322 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
323 return(NULL);
324 }
325 switch (type) {
326 case XML_ELEMENT_TYPE_EMPTY:
327 if (content != NULL) {
328 fprintf(stderr,
329 "xmlAddElementDecl: content != NULL for EMPTY\n");
330 return(NULL);
331 }
332 break;
333 case XML_ELEMENT_TYPE_ANY:
334 if (content != NULL) {
335 fprintf(stderr,
336 "xmlAddElementDecl: content != NULL for ANY\n");
337 return(NULL);
338 }
339 break;
340 case XML_ELEMENT_TYPE_MIXED:
341 if (content == NULL) {
342 fprintf(stderr,
343 "xmlAddElementDecl: content == NULL for MIXED\n");
344 return(NULL);
345 }
346 break;
347 case XML_ELEMENT_TYPE_ELEMENT:
348 if (content == NULL) {
349 fprintf(stderr,
350 "xmlAddElementDecl: content == NULL for ELEMENT\n");
351 return(NULL);
352 }
353 break;
354 default:
355 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
356 return(NULL);
357 }
358
359 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000360 * Create the Element table if needed.
361 */
362 table = dtd->elements;
363 if (table == NULL)
364 table = dtd->elements = xmlCreateElementTable();
365 if (table == NULL) {
366 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
367 return(NULL);
368 }
369
370 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000371 * Validity Check:
372 * Search the DTD for previous declarations of the ELEMENT
373 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000374 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000375 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000376 if (!xmlStrcmp(cur->name, name)) {
377 /*
378 * The element is already defined in this Dtd.
379 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000380 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000381 return(NULL);
382 }
383 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000384
385 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000386 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000387 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000388 if (table->nb_elements >= table->max_elements) {
389 /*
390 * need more elements.
391 */
392 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000393 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000394 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000395 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000396 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
397 return(NULL);
398 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000399 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000400 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000401 if (ret == NULL) {
402 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
403 return(NULL);
404 }
405 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000406
407 /*
408 * fill the structure.
409 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000410 ret->type = type;
411 ret->name = xmlStrdup(name);
Daniel Veillard14fff061999-06-22 21:49:07 +0000412 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000413 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000414 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000415
416 return(ret);
417}
418
Daniel Veillard3b9def11999-01-31 22:15:06 +0000419/**
420 * xmlFreeElement:
421 * @elem: An element
422 *
423 * Deallocate the memory used by an element definition
424 */
425void
426xmlFreeElement(xmlElementPtr elem) {
427 if (elem == NULL) return;
428 xmlFreeElementContent(elem->content);
429 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000430 xmlFree((xmlChar *) elem->name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000431 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000432 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000433}
434
435/**
436 * xmlFreeElementTable:
437 * @table: An element table
438 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000439 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000440 */
441void
442xmlFreeElementTable(xmlElementTablePtr table) {
443 int i;
444
445 if (table == NULL) return;
446
447 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000448 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000449 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000450 xmlFree(table->table);
451 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000452}
453
454/**
455 * xmlCopyElementTable:
456 * @table: An element table
457 *
458 * Build a copy of an element table.
459 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000460 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000461 */
462xmlElementTablePtr
463xmlCopyElementTable(xmlElementTablePtr table) {
464 xmlElementTablePtr ret;
465 xmlElementPtr cur, ent;
466 int i;
467
Daniel Veillard6454aec1999-09-02 22:04:43 +0000468 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000469 if (ret == NULL) {
470 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
471 return(NULL);
472 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000473 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000474 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000475 if (ret->table == NULL) {
476 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000477 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000478 return(NULL);
479 }
480 ret->max_elements = table->max_elements;
481 ret->nb_elements = table->nb_elements;
482 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000483 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000484 if (cur == NULL) {
485 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000486 xmlFree(ret);
487 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000488 return(NULL);
489 }
490 ret->table[i] = cur;
491 ent = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000492 cur->type = ent->type;
493 if (ent->name != NULL)
494 cur->name = xmlStrdup(ent->name);
495 else
496 cur->name = NULL;
497 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000498 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000499 }
500 return(ret);
501}
502
503/**
504 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000505 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000506 * @table: An element table
507 *
508 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000509 */
510void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000511xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000512 int i;
513 xmlElementPtr cur;
514
515 if (table == NULL) return;
516
517 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000518 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000519 switch (cur->type) {
520 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000521 xmlBufferWriteChar(buf, "<!ELEMENT ");
522 xmlBufferWriteCHAR(buf, cur->name);
523 xmlBufferWriteChar(buf, " EMPTY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000524 break;
525 case XML_ELEMENT_TYPE_ANY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000526 xmlBufferWriteChar(buf, "<!ELEMENT ");
527 xmlBufferWriteCHAR(buf, cur->name);
528 xmlBufferWriteChar(buf, " ANY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000529 break;
530 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000531 xmlBufferWriteChar(buf, "<!ELEMENT ");
532 xmlBufferWriteCHAR(buf, cur->name);
533 xmlBufferWriteChar(buf, " ");
534 xmlDumpElementContent(buf, cur->content, 1);
535 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000536 break;
537 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000538 xmlBufferWriteChar(buf, "<!ELEMENT ");
539 xmlBufferWriteCHAR(buf, cur->name);
540 xmlBufferWriteChar(buf, " ");
541 xmlDumpElementContent(buf, cur->content, 1);
542 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000543 break;
544 default:
545 fprintf(stderr,
546 "xmlDumpElementTable: internal: unknown type %d\n",
547 cur->type);
548 }
549 }
550}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000551
552/**
553 * xmlCreateEnumeration:
554 * @name: the enumeration name or NULL
555 *
556 * create and initialize an enumeration attribute node.
557 *
558 * Returns the xmlEnumerationPtr just created or NULL in case
559 * of error.
560 */
561xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000562xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000563 xmlEnumerationPtr ret;
564
Daniel Veillard6454aec1999-09-02 22:04:43 +0000565 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000566 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000567 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000568 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000569 return(NULL);
570 }
571
572 if (name != NULL)
573 ret->name = xmlStrdup(name);
574 else
575 ret->name = NULL;
576 ret->next = NULL;
577 return(ret);
578}
579
580/**
581 * xmlFreeEnumeration:
582 * @cur: the tree to free.
583 *
584 * free an enumeration attribute node (recursive).
585 */
586void
587xmlFreeEnumeration(xmlEnumerationPtr cur) {
588 if (cur == NULL) return;
589
590 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
591
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000592 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000593 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000594 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000595}
596
597/**
598 * xmlCopyEnumeration:
599 * @cur: the tree to copy.
600 *
601 * Copy an enumeration attribute node (recursive).
602 *
603 * Returns the xmlEnumerationPtr just created or NULL in case
604 * of error.
605 */
606xmlEnumerationPtr
607xmlCopyEnumeration(xmlEnumerationPtr cur) {
608 xmlEnumerationPtr ret;
609
610 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000611 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000612
613 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
614 else ret->next = NULL;
615
616 return(ret);
617}
618
619/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000620 * xmlDumpEnumeration:
621 * @buf: the XML buffer output
622 * @enum: An enumeration
623 *
624 * This will dump the content of the enumeration
625 */
626void
627xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
628 if (cur == NULL) return;
629
630 xmlBufferWriteCHAR(buf, cur->name);
631 if (cur->next == NULL)
632 xmlBufferWriteChar(buf, ")");
633 else {
634 xmlBufferWriteChar(buf, " | ");
635 xmlDumpEnumeration(buf, cur->next);
636 }
637}
638
639/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000640 * xmlCreateAttributeTable:
641 *
642 * create and initialize an empty attribute hash table.
643 *
644 * Returns the xmlAttributeTablePtr just created or NULL in case
645 * of error.
646 */
647xmlAttributeTablePtr
648xmlCreateAttributeTable(void) {
649 xmlAttributeTablePtr ret;
650
651 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000652 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000653 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000654 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000655 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000656 return(NULL);
657 }
658 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
659 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000660 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000661 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000662 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000663 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000664 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000665 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000666 return(NULL);
667 }
668 return(ret);
669}
670
Daniel Veillardb05deb71999-08-10 19:04:08 +0000671/**
672 * xmlScanAttributeDecl:
673 * @dtd: pointer to the DTD
674 * @elem: the element name
675 *
676 * When inserting a new element scan the DtD for existing attributes
677 * for taht element and initialize the Attribute chain
678 *
679 * Returns the pointer to the first attribute decl in the chain,
680 * possibly NULL.
681 */
682xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000683xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000684 xmlAttributePtr ret = NULL;
685 xmlAttributeTablePtr table;
686 int i;
687
688 if (dtd == NULL) {
689 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
690 return(NULL);
691 }
692 if (elem == NULL) {
693 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
694 return(NULL);
695 }
696 table = dtd->attributes;
697 if (table == NULL)
698 return(NULL);
699
700 for (i = 0;i < table->nb_attributes;i++) {
701 if (!xmlStrcmp(table->table[i]->elem, elem)) {
702 table->table[i]->next = ret;
703 ret = table->table[i];
704 }
705 }
706 return(ret);
707}
708
709/**
710 * xmlScanIDAttributeDecl:
711 * @ctxt: the validation context
712 * @elem: the element name
713 *
714 * Veryfy that the element don't have too many ID attributes
715 * declared.
716 *
717 * Returns the number of ID attributes found.
718 */
719int
720xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
721 xmlAttributePtr cur;
722 int ret = 0;
723
724 if (elem == NULL) return(0);
725 cur = elem->attributes;
726 while (cur != NULL) {
727 if (cur->type == XML_ATTRIBUTE_ID) {
728 ret ++;
729 if (ret > 1)
730 VERROR(ctxt->userData,
731 "Element %s has too may ID attributes defined : %s\n",
732 elem->name, cur->name);
733 }
734 cur = cur->next;
735 }
736 return(ret);
737}
738
Daniel Veillard1e346af1999-02-22 10:33:01 +0000739
740/**
741 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000742 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000743 * @dtd: pointer to the DTD
744 * @elem: the element name
745 * @name: the attribute name
746 * @type: the attribute type
747 * @def: the attribute default type
748 * @defaultValue: the attribute default value
749 * @tree: if it's an enumeration, the associated list
750 *
751 * Register a new attribute declaration
752 *
753 * Returns NULL if not, othervise the entity
754 */
755xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000756xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
757 const xmlChar *name, xmlAttributeType type,
758 xmlAttributeDefault def, const xmlChar *defaultValue,
Daniel Veillardc26087b1999-08-30 11:23:51 +0000759 xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000760 xmlAttributePtr ret, cur;
761 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000762 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000763 int i;
764
765 if (dtd == NULL) {
766 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
767 return(NULL);
768 }
769 if (name == NULL) {
770 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
771 return(NULL);
772 }
773 if (elem == NULL) {
774 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
775 return(NULL);
776 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000777 /*
778 * Check the type and possibly the default value.
779 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000780 switch (type) {
781 case XML_ATTRIBUTE_CDATA:
782 break;
783 case XML_ATTRIBUTE_ID:
784 break;
785 case XML_ATTRIBUTE_IDREF:
786 break;
787 case XML_ATTRIBUTE_IDREFS:
788 break;
789 case XML_ATTRIBUTE_ENTITY:
790 break;
791 case XML_ATTRIBUTE_ENTITIES:
792 break;
793 case XML_ATTRIBUTE_NMTOKEN:
794 break;
795 case XML_ATTRIBUTE_NMTOKENS:
796 break;
797 case XML_ATTRIBUTE_ENUMERATION:
798 break;
799 case XML_ATTRIBUTE_NOTATION:
800 break;
801 default:
802 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
803 return(NULL);
804 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000805 if ((defaultValue != NULL) &&
806 (!xmlValidateAttributeValue(type, defaultValue))) {
807 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
808 elem, name, defaultValue);
809 defaultValue = NULL;
810 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000811
812 /*
813 * Create the Attribute table if needed.
814 */
815 table = dtd->attributes;
816 if (table == NULL)
817 table = dtd->attributes = xmlCreateAttributeTable();
818 if (table == NULL) {
819 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
820 return(NULL);
821 }
822
823 /*
824 * Validity Check:
825 * Search the DTD for previous declarations of the ATTLIST
826 */
827 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000828 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +0000829 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
830 /*
831 * The attribute is already defined in this Dtd.
832 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000833 VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
834 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000835 }
836 }
837
838 /*
839 * Grow the table, if needed.
840 */
841 if (table->nb_attributes >= table->max_attributes) {
842 /*
843 * need more attributes.
844 */
845 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000846 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000847 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000848 sizeof(xmlAttributePtr));
849 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000850 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
851 return(NULL);
852 }
853 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000854 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000855 if (ret == NULL) {
856 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
857 return(NULL);
858 }
859 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000860
861 /*
862 * fill the structure.
863 */
864 ret->type = type;
865 ret->name = xmlStrdup(name);
866 ret->elem = xmlStrdup(elem);
867 ret->def = def;
868 ret->tree = tree;
869 if (defaultValue != NULL)
870 ret->defaultValue = xmlStrdup(defaultValue);
871 else
872 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000873 elemDef = xmlGetDtdElementDesc(dtd, elem);
874 if (elemDef != NULL) {
875 if ((type == XML_ATTRIBUTE_ID) &&
876 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
877 VERROR(ctxt->userData,
878 "Element %s has too may ID attributes defined : %s\n",
879 elem, name);
880 ret->next = elemDef->attributes;
881 elemDef->attributes = ret;
882 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000883 table->nb_attributes++;
884
885 return(ret);
886}
887
888/**
889 * xmlFreeAttribute:
890 * @elem: An attribute
891 *
892 * Deallocate the memory used by an attribute definition
893 */
894void
895xmlFreeAttribute(xmlAttributePtr attr) {
896 if (attr == NULL) return;
897 if (attr->tree != NULL)
898 xmlFreeEnumeration(attr->tree);
899 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000900 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000901 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000902 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000903 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000904 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000905 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000906 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000907}
908
909/**
910 * xmlFreeAttributeTable:
911 * @table: An attribute table
912 *
913 * Deallocate the memory used by an entities hash table.
914 */
915void
916xmlFreeAttributeTable(xmlAttributeTablePtr table) {
917 int i;
918
919 if (table == NULL) return;
920
921 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000922 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000923 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000924 xmlFree(table->table);
925 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000926}
927
928/**
929 * xmlCopyAttributeTable:
930 * @table: An attribute table
931 *
932 * Build a copy of an attribute table.
933 *
934 * Returns the new xmlAttributeTablePtr or NULL in case of error.
935 */
936xmlAttributeTablePtr
937xmlCopyAttributeTable(xmlAttributeTablePtr table) {
938 xmlAttributeTablePtr ret;
939 xmlAttributePtr cur, attr;
940 int i;
941
Daniel Veillard6454aec1999-09-02 22:04:43 +0000942 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000943 if (ret == NULL) {
944 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
945 return(NULL);
946 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000947 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000948 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000949 if (ret->table == NULL) {
950 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000951 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000952 return(NULL);
953 }
954 ret->max_attributes = table->max_attributes;
955 ret->nb_attributes = table->nb_attributes;
956 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000957 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +0000958 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000959 if (cur == NULL) {
960 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000961 xmlFree(ret);
962 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000963 return(NULL);
964 }
965 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000966 cur->type = attr->type;
967 cur->def = attr->def;
968 cur->tree = xmlCopyEnumeration(attr->tree);
969 if (attr->elem != NULL)
970 cur->elem = xmlStrdup(attr->elem);
971 else
972 cur->elem = NULL;
973 if (attr->name != NULL)
974 cur->name = xmlStrdup(attr->name);
975 else
976 cur->name = NULL;
977 if (attr->defaultValue != NULL)
978 cur->defaultValue = xmlStrdup(attr->defaultValue);
979 else
980 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000981 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000982 }
983 return(ret);
984}
985
986/**
987 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000988 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +0000989 * @table: An attribute table
990 *
991 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +0000992 */
993void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000994xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000995 int i;
996 xmlAttributePtr cur;
997
998 if (table == NULL) return;
999
1000 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001001 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001002 xmlBufferWriteChar(buf, "<!ATTLIST ");
1003 xmlBufferWriteCHAR(buf, cur->elem);
1004 xmlBufferWriteChar(buf, " ");
1005 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001006 switch (cur->type) {
1007 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001008 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001009 break;
1010 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001011 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001012 break;
1013 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001014 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001015 break;
1016 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001017 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001018 break;
1019 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001020 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001021 break;
1022 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001023 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001024 break;
1025 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001026 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001027 break;
1028 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001029 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001030 break;
1031 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001032 xmlBufferWriteChar(buf, " (");
1033 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001034 break;
1035 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001036 xmlBufferWriteChar(buf, " NOTATION (");
1037 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001038 break;
1039 default:
1040 fprintf(stderr,
1041 "xmlDumpAttributeTable: internal: unknown type %d\n",
1042 cur->type);
1043 }
1044 switch (cur->def) {
1045 case XML_ATTRIBUTE_NONE:
1046 break;
1047 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001048 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001049 break;
1050 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001051 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001052 break;
1053 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001054 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001055 break;
1056 default:
1057 fprintf(stderr,
1058 "xmlDumpAttributeTable: internal: unknown default %d\n",
1059 cur->def);
1060 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001061 if (cur->defaultValue != NULL) {
1062 xmlBufferWriteChar(buf, " ");
1063 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1064 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001065 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001066 }
1067}
1068
1069/************************************************************************
1070 * *
1071 * NOTATIONs *
1072 * *
1073 ************************************************************************/
1074/**
1075 * xmlCreateNotationTable:
1076 *
1077 * create and initialize an empty notation hash table.
1078 *
1079 * Returns the xmlNotationTablePtr just created or NULL in case
1080 * of error.
1081 */
1082xmlNotationTablePtr
1083xmlCreateNotationTable(void) {
1084 xmlNotationTablePtr ret;
1085
1086 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001087 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001088 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001089 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001090 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001091 return(NULL);
1092 }
1093 ret->max_notations = XML_MIN_NOTATION_TABLE;
1094 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001095 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001096 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001097 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001098 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001099 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001100 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001101 return(NULL);
1102 }
1103 return(ret);
1104}
1105
1106
1107/**
1108 * xmlAddNotationDecl:
1109 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001110 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001111 * @name: the entity name
1112 * @PublicID: the public identifier or NULL
1113 * @SystemID: the system identifier or NULL
1114 *
1115 * Register a new notation declaration
1116 *
1117 * Returns NULL if not, othervise the entity
1118 */
1119xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001120xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1121 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001122 xmlNotationPtr ret, cur;
1123 xmlNotationTablePtr table;
1124 int i;
1125
1126 if (dtd == NULL) {
1127 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1128 return(NULL);
1129 }
1130 if (name == NULL) {
1131 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1132 return(NULL);
1133 }
1134 if ((PublicID == NULL) && (SystemID == NULL)) {
1135 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1136 }
1137
1138 /*
1139 * Create the Notation table if needed.
1140 */
1141 table = dtd->notations;
1142 if (table == NULL)
1143 table = dtd->notations = xmlCreateNotationTable();
1144 if (table == NULL) {
1145 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1146 return(NULL);
1147 }
1148
1149 /*
1150 * Validity Check:
1151 * Search the DTD for previous declarations of the ATTLIST
1152 */
1153 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001154 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001155 if (!xmlStrcmp(cur->name, name)) {
1156 /*
1157 * The notation is already defined in this Dtd.
1158 */
1159 fprintf(stderr,
1160 "xmlAddNotationDecl: %s already defined\n", name);
1161 }
1162 }
1163
1164 /*
1165 * Grow the table, if needed.
1166 */
1167 if (table->nb_notations >= table->max_notations) {
1168 /*
1169 * need more notations.
1170 */
1171 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001172 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001173 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001174 sizeof(xmlNotationPtr));
1175 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001176 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1177 return(NULL);
1178 }
1179 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001180 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001181 if (ret == NULL) {
1182 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1183 return(NULL);
1184 }
1185 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001186
1187 /*
1188 * fill the structure.
1189 */
1190 ret->name = xmlStrdup(name);
1191 if (SystemID != NULL)
1192 ret->SystemID = xmlStrdup(SystemID);
1193 else
1194 ret->SystemID = NULL;
1195 if (PublicID != NULL)
1196 ret->PublicID = xmlStrdup(PublicID);
1197 else
1198 ret->PublicID = NULL;
1199 table->nb_notations++;
1200
1201 return(ret);
1202}
1203
1204/**
1205 * xmlFreeNotation:
1206 * @not: A notation
1207 *
1208 * Deallocate the memory used by an notation definition
1209 */
1210void
1211xmlFreeNotation(xmlNotationPtr nota) {
1212 if (nota == NULL) return;
1213 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001214 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001215 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001216 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001217 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001218 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001219 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001220 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001221}
1222
1223/**
1224 * xmlFreeNotationTable:
1225 * @table: An notation table
1226 *
1227 * Deallocate the memory used by an entities hash table.
1228 */
1229void
1230xmlFreeNotationTable(xmlNotationTablePtr table) {
1231 int i;
1232
1233 if (table == NULL) return;
1234
1235 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001236 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001237 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001238 xmlFree(table->table);
1239 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001240}
1241
1242/**
1243 * xmlCopyNotationTable:
1244 * @table: A notation table
1245 *
1246 * Build a copy of a notation table.
1247 *
1248 * Returns the new xmlNotationTablePtr or NULL in case of error.
1249 */
1250xmlNotationTablePtr
1251xmlCopyNotationTable(xmlNotationTablePtr table) {
1252 xmlNotationTablePtr ret;
1253 xmlNotationPtr cur, nota;
1254 int i;
1255
Daniel Veillard6454aec1999-09-02 22:04:43 +00001256 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001257 if (ret == NULL) {
1258 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1259 return(NULL);
1260 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001261 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001262 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001263 if (ret->table == NULL) {
1264 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001265 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001266 return(NULL);
1267 }
1268 ret->max_notations = table->max_notations;
1269 ret->nb_notations = table->nb_notations;
1270 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001271 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001272 if (cur == NULL) {
1273 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001274 xmlFree(ret);
1275 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001276 return(NULL);
1277 }
1278 ret->table[i] = cur;
1279 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001280 if (nota->name != NULL)
1281 cur->name = xmlStrdup(nota->name);
1282 else
1283 cur->name = NULL;
1284 if (nota->PublicID != NULL)
1285 cur->PublicID = xmlStrdup(nota->PublicID);
1286 else
1287 cur->PublicID = NULL;
1288 if (nota->SystemID != NULL)
1289 cur->SystemID = xmlStrdup(nota->SystemID);
1290 else
1291 cur->SystemID = NULL;
1292 }
1293 return(ret);
1294}
1295
1296/**
1297 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001298 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001299 * @table: A notation table
1300 *
1301 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001302 */
1303void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001304xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001305 int i;
1306 xmlNotationPtr cur;
1307
1308 if (table == NULL) return;
1309
1310 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001311 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001312 xmlBufferWriteChar(buf, "<!NOTATION ");
1313 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001314 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001315 xmlBufferWriteChar(buf, " PUBLIC ");
1316 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001317 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001318 xmlBufferWriteChar(buf, " ");
1319 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001320 }
1321 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001322 xmlBufferWriteChar(buf, " SYSTEM ");
1323 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001324 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001325 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001326 }
1327}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001328
1329/************************************************************************
1330 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001331 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001332 * *
1333 ************************************************************************/
1334/**
1335 * xmlCreateIDTable:
1336 *
1337 * create and initialize an empty id hash table.
1338 *
1339 * Returns the xmlIDTablePtr just created or NULL in case
1340 * of error.
1341 */
1342xmlIDTablePtr
1343xmlCreateIDTable(void) {
1344 xmlIDTablePtr ret;
1345
1346 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001347 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001348 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001349 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001350 (long)sizeof(xmlIDTable));
1351 return(NULL);
1352 }
1353 ret->max_ids = XML_MIN_NOTATION_TABLE;
1354 ret->nb_ids = 0;
1355 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001356 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001357 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001358 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001359 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001360 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001361 return(NULL);
1362 }
1363 return(ret);
1364}
1365
1366
1367/**
1368 * xmlAddID:
1369 * @ctxt: the validation context
1370 * @doc: pointer to the document
1371 * @value: the value name
1372 * @attr: the attribute holding the ID
1373 *
1374 * Register a new id declaration
1375 *
1376 * Returns NULL if not, othervise the new xmlIDPtr
1377 */
1378xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001379xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001380 xmlAttrPtr attr) {
1381 xmlIDPtr ret, cur;
1382 xmlIDTablePtr table;
1383 int i;
1384
1385 if (doc == NULL) {
1386 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1387 return(NULL);
1388 }
1389 if (value == NULL) {
1390 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1391 return(NULL);
1392 }
1393 if (attr == NULL) {
1394 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1395 return(NULL);
1396 }
1397
1398 /*
1399 * Create the ID table if needed.
1400 */
1401 table = doc->ids;
1402 if (table == NULL)
1403 table = doc->ids = xmlCreateIDTable();
1404 if (table == NULL) {
1405 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1406 return(NULL);
1407 }
1408
1409 /*
1410 * Validity Check:
1411 * Search the DTD for previous declarations of the ATTLIST
1412 */
1413 for (i = 0;i < table->nb_ids;i++) {
1414 cur = table->table[i];
1415 if (!xmlStrcmp(cur->value, value)) {
1416 /*
1417 * The id is already defined in this Dtd.
1418 */
1419 VERROR(ctxt->userData, "ID %s already defined\n", value);
1420 return(NULL);
1421 }
1422 }
1423
1424 /*
1425 * Grow the table, if needed.
1426 */
1427 if (table->nb_ids >= table->max_ids) {
1428 /*
1429 * need more ids.
1430 */
1431 table->max_ids *= 2;
1432 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001433 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001434 sizeof(xmlIDPtr));
1435 if (table->table == NULL) {
1436 fprintf(stderr, "xmlAddID: out of memory\n");
1437 return(NULL);
1438 }
1439 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001440 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001441 if (ret == NULL) {
1442 fprintf(stderr, "xmlAddID: out of memory\n");
1443 return(NULL);
1444 }
1445 table->table[table->nb_ids] = ret;
1446
1447 /*
1448 * fill the structure.
1449 */
1450 ret->value = xmlStrdup(value);
1451 ret->attr = attr;
1452 table->nb_ids++;
1453
1454 return(ret);
1455}
1456
1457/**
1458 * xmlFreeID:
1459 * @not: A id
1460 *
1461 * Deallocate the memory used by an id definition
1462 */
1463void
1464xmlFreeID(xmlIDPtr id) {
1465 if (id == NULL) return;
1466 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001467 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001468 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001469 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001470}
1471
1472/**
1473 * xmlFreeIDTable:
1474 * @table: An id table
1475 *
1476 * Deallocate the memory used by an ID hash table.
1477 */
1478void
1479xmlFreeIDTable(xmlIDTablePtr table) {
1480 int i;
1481
1482 if (table == NULL) return;
1483
1484 for (i = 0;i < table->nb_ids;i++) {
1485 xmlFreeID(table->table[i]);
1486 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001487 xmlFree(table->table);
1488 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001489}
1490
1491/**
1492 * xmlIsID
1493 * @doc: the document
1494 * @elem: the element carrying the attribute
1495 * @attr: the attribute
1496 *
1497 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1498 * then this is simple, otherwise we use an heuristic: name ID (upper
1499 * or lowercase).
1500 *
1501 * Returns 0 or 1 depending on the lookup result
1502 */
1503int
1504xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1505 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1506 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1507 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1508 (attr->name[2] == 0)) return(1);
1509 } else {
1510 xmlAttributePtr attrDecl;
1511
1512 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1513 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1514 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1515 attr->name);
1516
Daniel Veillardb96e6431999-08-29 21:02:19 +00001517 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001518 return(1);
1519 }
1520 return(0);
1521}
1522
Daniel Veillardb96e6431999-08-29 21:02:19 +00001523/**
1524 * xmlGetID:
1525 * @doc: pointer to the document
1526 * @ID: the ID value
1527 *
1528 * Search the attribute declaring the given ID
1529 *
1530 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1531 */
1532xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001533xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001534 xmlIDPtr cur;
1535 xmlIDTablePtr table;
1536 int i;
1537
1538 if (doc == NULL) {
1539 fprintf(stderr, "xmlGetID: doc == NULL\n");
1540 return(NULL);
1541 }
1542
1543 if (ID == NULL) {
1544 fprintf(stderr, "xmlGetID: ID == NULL\n");
1545 return(NULL);
1546 }
1547
1548 table = doc->ids;
1549 if (table == NULL)
1550 return(NULL);
1551
1552 /*
1553 * Search the ID list.
1554 */
1555 for (i = 0;i < table->nb_ids;i++) {
1556 cur = table->table[i];
1557 if (!xmlStrcmp(cur->value, ID)) {
1558 return(cur->attr);
1559 }
1560 }
1561 return(NULL);
1562}
1563
Daniel Veillard991e63d1999-08-15 23:32:28 +00001564/************************************************************************
1565 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001566 * Refs *
1567 * *
1568 ************************************************************************/
1569/**
1570 * xmlCreateRefTable:
1571 *
1572 * create and initialize an empty ref hash table.
1573 *
1574 * Returns the xmlRefTablePtr just created or NULL in case
1575 * of error.
1576 */
1577xmlRefTablePtr
1578xmlCreateRefTable(void) {
1579 xmlRefTablePtr ret;
1580
1581 ret = (xmlRefTablePtr)
1582 xmlMalloc(sizeof(xmlRefTable));
1583 if (ret == NULL) {
1584 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1585 (long)sizeof(xmlRefTable));
1586 return(NULL);
1587 }
1588 ret->max_refs = XML_MIN_NOTATION_TABLE;
1589 ret->nb_refs = 0;
1590 ret->table = (xmlRefPtr *)
1591 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1592 if (ret == NULL) {
1593 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1594 ret->max_refs * (long)sizeof(xmlRef));
1595 xmlFree(ret);
1596 return(NULL);
1597 }
1598 return(ret);
1599}
1600
1601
1602/**
1603 * xmlAddRef:
1604 * @ctxt: the validation context
1605 * @doc: pointer to the document
1606 * @value: the value name
1607 * @attr: the attribute holding the Ref
1608 *
1609 * Register a new ref declaration
1610 *
1611 * Returns NULL if not, othervise the new xmlRefPtr
1612 */
1613xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001614xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001615 xmlAttrPtr attr) {
1616 xmlRefPtr ret;
1617 xmlRefTablePtr table;
1618
1619 if (doc == NULL) {
1620 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1621 return(NULL);
1622 }
1623 if (value == NULL) {
1624 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1625 return(NULL);
1626 }
1627 if (attr == NULL) {
1628 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1629 return(NULL);
1630 }
1631
1632 /*
1633 * Create the Ref table if needed.
1634 */
1635 table = doc->refs;
1636 if (table == NULL)
1637 table = doc->refs = xmlCreateRefTable();
1638 if (table == NULL) {
1639 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1640 return(NULL);
1641 }
1642
1643 /*
1644 * Grow the table, if needed.
1645 */
1646 if (table->nb_refs >= table->max_refs) {
1647 /*
1648 * need more refs.
1649 */
1650 table->max_refs *= 2;
1651 table->table = (xmlRefPtr *)
1652 xmlRealloc(table->table, table->max_refs *
1653 sizeof(xmlRefPtr));
1654 if (table->table == NULL) {
1655 fprintf(stderr, "xmlAddRef: out of memory\n");
1656 return(NULL);
1657 }
1658 }
1659 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1660 if (ret == NULL) {
1661 fprintf(stderr, "xmlAddRef: out of memory\n");
1662 return(NULL);
1663 }
1664 table->table[table->nb_refs] = ret;
1665
1666 /*
1667 * fill the structure.
1668 */
1669 ret->value = xmlStrdup(value);
1670 ret->attr = attr;
1671 table->nb_refs++;
1672
1673 return(ret);
1674}
1675
1676/**
1677 * xmlFreeRef:
1678 * @not: A ref
1679 *
1680 * Deallocate the memory used by an ref definition
1681 */
1682void
1683xmlFreeRef(xmlRefPtr ref) {
1684 if (ref == NULL) return;
1685 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001686 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001687 memset(ref, -1, sizeof(xmlRef));
1688 xmlFree(ref);
1689}
1690
1691/**
1692 * xmlFreeRefTable:
1693 * @table: An ref table
1694 *
1695 * Deallocate the memory used by an Ref hash table.
1696 */
1697void
1698xmlFreeRefTable(xmlRefTablePtr table) {
1699 int i;
1700
1701 if (table == NULL) return;
1702
1703 for (i = 0;i < table->nb_refs;i++) {
1704 xmlFreeRef(table->table[i]);
1705 }
1706 xmlFree(table->table);
1707 xmlFree(table);
1708}
1709
1710/**
1711 * xmlIsRef
1712 * @doc: the document
1713 * @elem: the element carrying the attribute
1714 * @attr: the attribute
1715 *
1716 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1717 * then this is simple, otherwise we use an heuristic: name Ref (upper
1718 * or lowercase).
1719 *
1720 * Returns 0 or 1 depending on the lookup result
1721 */
1722int
1723xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1724 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1725 return(0);
1726 /*******************
1727 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1728 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1729 (attr->name[2] == 0)) return(1);
1730 *******************/
1731 } else {
1732 xmlAttributePtr attrDecl;
1733
1734 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1735 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1736 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1737 attr->name);
1738
1739 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1740 return(1);
1741 }
1742 return(0);
1743}
1744
1745/**
1746 * xmlGetRef:
1747 * @doc: pointer to the document
1748 * @Ref: the Ref value
1749 *
1750 * Search the attribute declaring the given Ref
1751 *
1752 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1753 */
1754xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001755xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001756 xmlRefPtr cur;
1757 xmlRefTablePtr table;
1758 int i;
1759
1760 if (doc == NULL) {
1761 fprintf(stderr, "xmlGetRef: doc == NULL\n");
1762 return(NULL);
1763 }
1764
1765 if (Ref == NULL) {
1766 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1767 return(NULL);
1768 }
1769
1770 table = doc->refs;
1771 if (table == NULL)
1772 return(NULL);
1773
1774 /*
1775 * Search the Ref list.
1776 */
1777 for (i = 0;i < table->nb_refs;i++) {
1778 cur = table->table[i];
1779 if (!xmlStrcmp(cur->value, Ref)) {
1780 return(cur->attr);
1781 }
1782 }
1783 return(NULL);
1784}
1785
1786/************************************************************************
1787 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001788 * Routines for validity checking *
1789 * *
1790 ************************************************************************/
1791
1792/**
1793 * xmlGetDtdElementDesc:
1794 * @dtd: a pointer to the DtD to search
1795 * @name: the element name
1796 *
1797 * Search the Dtd for the description of this element
1798 *
1799 * returns the xmlElementPtr if found or NULL
1800 */
1801
1802xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001803xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001804 xmlElementTablePtr table;
1805 xmlElementPtr cur;
1806 int i;
1807
1808 if (dtd == NULL) return(NULL);
1809 if (dtd->elements == NULL) return(NULL);
1810 table = dtd->elements;
1811
1812 for (i = 0;i < table->nb_elements;i++) {
1813 cur = table->table[i];
1814 if (!xmlStrcmp(cur->name, name))
1815 return(cur);
1816 }
1817 return(NULL);
1818}
1819
1820/**
1821 * xmlGetDtdAttrDesc:
1822 * @dtd: a pointer to the DtD to search
1823 * @elem: the element name
1824 * @name: the attribute name
1825 *
1826 * Search the Dtd for the description of this attribute on
1827 * this element.
1828 *
1829 * returns the xmlAttributePtr if found or NULL
1830 */
1831
1832xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001833xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001834 xmlAttributeTablePtr table;
1835 xmlAttributePtr cur;
1836 int i;
1837
1838 if (dtd == NULL) return(NULL);
1839 if (dtd->attributes == NULL) return(NULL);
1840 table = dtd->attributes;
1841
1842 for (i = 0;i < table->nb_attributes;i++) {
1843 cur = table->table[i];
1844 if ((!xmlStrcmp(cur->name, name)) &&
1845 (!xmlStrcmp(cur->elem, elem)))
1846 return(cur);
1847 }
1848 return(NULL);
1849}
1850
1851/**
1852 * xmlGetDtdNotationDesc:
1853 * @dtd: a pointer to the DtD to search
1854 * @name: the notation name
1855 *
1856 * Search the Dtd for the description of this notation
1857 *
1858 * returns the xmlNotationPtr if found or NULL
1859 */
1860
1861xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001862xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001863 xmlNotationTablePtr table;
1864 xmlNotationPtr cur;
1865 int i;
1866
1867 if (dtd == NULL) return(NULL);
1868 if (dtd->notations == NULL) return(NULL);
1869 table = dtd->notations;
1870
1871 for (i = 0;i < table->nb_notations;i++) {
1872 cur = table->table[i];
1873 if (!xmlStrcmp(cur->name, name))
1874 return(cur);
1875 }
1876 return(NULL);
1877}
1878
1879/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001880 * xmlValidateNotationUse:
1881 * @ctxt: the validation context
1882 * @doc: the document
1883 * @notationName: the notation name to check
1884 *
1885 * Validate that the given mame match a notation declaration.
1886 * - [ VC: Notation Declared ]
1887 *
1888 * returns 1 if valid or 0 otherwise
1889 */
1890
1891int
1892xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001893 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001894 xmlNotationPtr notaDecl;
1895 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1896
1897 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1898 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1899 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1900
1901 if (notaDecl == NULL) {
1902 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1903 notationName);
1904 return(0);
1905 }
1906 return(1);
1907}
1908
1909/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001910 * xmlIsMixedElement
1911 * @doc: the document
1912 * @name: the element name
1913 *
1914 * Search in the DtDs whether an element accept Mixed content (or ANY)
1915 * basically if it is supposed to accept text childs
1916 *
1917 * returns 0 if no, 1 if yes, and -1 if no element description is available
1918 */
1919
1920int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001921xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001922 xmlElementPtr elemDecl;
1923
1924 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1925
1926 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1927 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1928 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1929 if (elemDecl == NULL) return(-1);
1930 switch (elemDecl->type) {
1931 case XML_ELEMENT_TYPE_ELEMENT:
1932 return(0);
1933 case XML_ELEMENT_TYPE_EMPTY:
1934 /*
1935 * return 1 for EMPTY since we want VC error to pop up
1936 * on <empty> </empty> for example
1937 */
1938 case XML_ELEMENT_TYPE_ANY:
1939 case XML_ELEMENT_TYPE_MIXED:
1940 return(1);
1941 }
1942 return(1);
1943}
1944
1945/**
1946 * xmlValidateNameValue:
1947 * @value: an Name value
1948 *
1949 * Validate that the given value match Name production
1950 *
1951 * returns 1 if valid or 0 otherwise
1952 */
1953
1954int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001955xmlValidateNameValue(const xmlChar *value) {
1956 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001957
1958 if (value == NULL) return(0);
1959 cur = value;
1960
1961 if (!IS_LETTER(*cur) && (*cur != '_') &&
1962 (*cur != ':')) {
1963 return(0);
1964 }
1965
1966 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1967 (*cur == '.') || (*cur == '-') ||
1968 (*cur == '_') || (*cur == ':') ||
1969 (IS_COMBINING(*cur)) ||
1970 (IS_EXTENDER(*cur)))
1971 cur++;
1972
1973 if (*cur != 0) return(0);
1974
1975 return(1);
1976}
1977
1978/**
1979 * xmlValidateNamesValue:
1980 * @value: an Names value
1981 *
1982 * Validate that the given value match Names production
1983 *
1984 * returns 1 if valid or 0 otherwise
1985 */
1986
1987int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001988xmlValidateNamesValue(const xmlChar *value) {
1989 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001990
1991 if (value == NULL) return(0);
1992 cur = value;
1993
1994 if (!IS_LETTER(*cur) && (*cur != '_') &&
1995 (*cur != ':')) {
1996 return(0);
1997 }
1998
1999 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2000 (*cur == '.') || (*cur == '-') ||
2001 (*cur == '_') || (*cur == ':') ||
2002 (IS_COMBINING(*cur)) ||
2003 (IS_EXTENDER(*cur)))
2004 cur++;
2005
2006 while (IS_BLANK(*cur)) {
2007 while (IS_BLANK(*cur)) cur++;
2008
2009 if (!IS_LETTER(*cur) && (*cur != '_') &&
2010 (*cur != ':')) {
2011 return(0);
2012 }
2013
2014 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2015 (*cur == '.') || (*cur == '-') ||
2016 (*cur == '_') || (*cur == ':') ||
2017 (IS_COMBINING(*cur)) ||
2018 (IS_EXTENDER(*cur)))
2019 cur++;
2020 }
2021
2022 if (*cur != 0) return(0);
2023
2024 return(1);
2025}
2026
2027/**
2028 * xmlValidateNmtokenValue:
2029 * @value: an Mntoken value
2030 *
2031 * Validate that the given value match Nmtoken production
2032 *
2033 * [ VC: Name Token ]
2034 *
2035 * returns 1 if valid or 0 otherwise
2036 */
2037
2038int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002039xmlValidateNmtokenValue(const xmlChar *value) {
2040 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002041
2042 if (value == NULL) return(0);
2043 cur = value;
2044
2045 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2046 (*cur != '.') && (*cur != '-') &&
2047 (*cur != '_') && (*cur != ':') &&
2048 (!IS_COMBINING(*cur)) &&
2049 (!IS_EXTENDER(*cur)))
2050 return(0);
2051
2052 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2053 (*cur == '.') || (*cur == '-') ||
2054 (*cur == '_') || (*cur == ':') ||
2055 (IS_COMBINING(*cur)) ||
2056 (IS_EXTENDER(*cur)))
2057 cur++;
2058
2059 if (*cur != 0) return(0);
2060
2061 return(1);
2062 return(1);
2063}
2064
2065/**
2066 * xmlValidateNmtokensValue:
2067 * @value: an Mntokens value
2068 *
2069 * Validate that the given value match Nmtokens production
2070 *
2071 * [ VC: Name Token ]
2072 *
2073 * returns 1 if valid or 0 otherwise
2074 */
2075
2076int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002077xmlValidateNmtokensValue(const xmlChar *value) {
2078 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002079
2080 if (value == NULL) return(0);
2081 cur = value;
2082
2083 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2084 (*cur != '.') && (*cur != '-') &&
2085 (*cur != '_') && (*cur != ':') &&
2086 (!IS_COMBINING(*cur)) &&
2087 (!IS_EXTENDER(*cur)))
2088 return(0);
2089
2090 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2091 (*cur == '.') || (*cur == '-') ||
2092 (*cur == '_') || (*cur == ':') ||
2093 (IS_COMBINING(*cur)) ||
2094 (IS_EXTENDER(*cur)))
2095 cur++;
2096
2097 while (IS_BLANK(*cur)) {
2098 while (IS_BLANK(*cur)) cur++;
2099
2100 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2101 (*cur != '.') && (*cur != '-') &&
2102 (*cur != '_') && (*cur != ':') &&
2103 (!IS_COMBINING(*cur)) &&
2104 (!IS_EXTENDER(*cur)))
2105 return(0);
2106
2107 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2108 (*cur == '.') || (*cur == '-') ||
2109 (*cur == '_') || (*cur == ':') ||
2110 (IS_COMBINING(*cur)) ||
2111 (IS_EXTENDER(*cur)))
2112 cur++;
2113 }
2114
2115 if (*cur != 0) return(0);
2116
2117 return(1);
2118}
2119
2120/**
2121 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002122 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002123 * @doc: a document instance
2124 * @nota: a notation definition
2125 *
2126 * Try to validate a single notation definition
2127 * basically it does the following checks as described by the
2128 * XML-1.0 recommendation:
2129 * - it seems that no validity constraing exist on notation declarations
2130 * But this function get called anyway ...
2131 *
2132 * returns 1 if valid or 0 otherwise
2133 */
2134
2135int
2136xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2137 xmlNotationPtr nota) {
2138 int ret = 1;
2139
2140 return(ret);
2141}
2142
2143/**
2144 * xmlValidateAttributeValue:
2145 * @type: an attribute type
2146 * @value: an attribute value
2147 *
2148 * Validate that the given attribute value match the proper production
2149 *
2150 * [ VC: ID ]
2151 * Values of type ID must match the Name production....
2152 *
2153 * [ VC: IDREF ]
2154 * Values of type IDREF must match the Name production, and values
2155 * of type IDREFS must match Names ...
2156 *
2157 * [ VC: Entity Name ]
2158 * Values of type ENTITY must match the Name production, values
2159 * of type ENTITIES must match Names ...
2160 *
2161 * [ VC: Name Token ]
2162 * Values of type NMTOKEN must match the Nmtoken production; values
2163 * of type NMTOKENS must match Nmtokens.
2164 *
2165 * returns 1 if valid or 0 otherwise
2166 */
2167
2168int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002169xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002170 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002171 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002172 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002173 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002174 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002175 case XML_ATTRIBUTE_IDREF:
2176 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002177 case XML_ATTRIBUTE_NOTATION:
2178 return(xmlValidateNameValue(value));
2179 case XML_ATTRIBUTE_NMTOKENS:
2180 case XML_ATTRIBUTE_ENUMERATION:
2181 return(xmlValidateNmtokensValue(value));
2182 case XML_ATTRIBUTE_NMTOKEN:
2183 return(xmlValidateNmtokenValue(value));
2184 case XML_ATTRIBUTE_CDATA:
2185 break;
2186 }
2187 return(1);
2188}
2189
2190/**
2191 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002192 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002193 * @doc: a document instance
2194 * @attr: an attribute definition
2195 *
2196 * Try to validate a single attribute definition
2197 * basically it does the following checks as described by the
2198 * XML-1.0 recommendation:
2199 * - [ VC: Attribute Default Legal ]
2200 * - [ VC: Enumeration ]
2201 * - [ VC: ID Attribute Default ]
2202 *
2203 * The ID/IDREF uniqueness and matching are done separately
2204 *
2205 * returns 1 if valid or 0 otherwise
2206 */
2207
2208int
2209xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2210 xmlAttributePtr attr) {
2211 int ret = 1;
2212 int val;
2213 CHECK_DTD;
2214 if(attr == NULL) return(1);
2215
2216 /* Attribute Default Legal */
2217 /* Enumeration */
2218 if (attr->defaultValue != NULL) {
2219 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2220 if (val == 0) {
2221 VERROR(ctxt->userData,
2222 "Syntax of default value for attribute %s on %s is not valid\n",
2223 attr->name, attr->elem);
2224 }
2225 ret &= val;
2226 }
2227
2228 /* ID Attribute Default */
2229 if ((attr->type == XML_ATTRIBUTE_ID)&&
2230 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2231 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2232 VERROR(ctxt->userData,
2233 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2234 attr->name, attr->elem);
2235 ret = 0;
2236 }
2237
Daniel Veillardb96e6431999-08-29 21:02:19 +00002238 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002239 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2240 int nbId = 0;
2241
2242 /* the trick is taht we parse DtD as their own internal subset */
2243 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2244 attr->elem);
2245 if (elem != NULL) {
2246 nbId = xmlScanIDAttributeDecl(NULL, elem);
2247 }
2248 if (nbId >= 1)
2249 VERROR(ctxt->userData,
2250 "Element %s has ID attribute defined in the external subset : %s\n",
2251 attr->elem, attr->name);
2252 }
2253
2254 return(ret);
2255}
2256
2257/**
2258 * xmlValidateElementDecl:
2259 * @ctxt: the validation context
2260 * @doc: a document instance
2261 * @elem: an element definition
2262 *
2263 * Try to validate a single element definition
2264 * basically it does the following checks as described by the
2265 * XML-1.0 recommendation:
2266 * - [ VC: One ID per Element Type ]
2267 * - [ VC: No Duplicate Types ]
2268 * - [ VC: Unique Element Type Declaration ]
2269 *
2270 * returns 1 if valid or 0 otherwise
2271 */
2272
2273int
2274xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2275 xmlElementPtr elem) {
2276 int ret = 1;
2277 xmlElementPtr tst;
2278
2279 CHECK_DTD;
2280
2281 if (elem == NULL) return(1);
2282
2283 /* No Duplicate Types */
2284 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2285 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002286 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002287
2288 cur = elem->content;
2289 while (cur != NULL) {
2290 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2291 if (cur->c1 == NULL) break;
2292 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2293 name = cur->c1->name;
2294 next = cur->c2;
2295 while (next != NULL) {
2296 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2297 if (!xmlStrcmp(next->name, name)) {
2298 VERROR(ctxt->userData,
2299 "Definition of %s has duplicate references of %s\n",
2300 elem->name, name);
2301 ret = 0;
2302 }
2303 break;
2304 }
2305 if (next->c1 == NULL) break;
2306 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2307 if (!xmlStrcmp(next->c1->name, name)) {
2308 VERROR(ctxt->userData,
2309 "Definition of %s has duplicate references of %s\n",
2310 elem->name, name);
2311 ret = 0;
2312 }
2313 next = next->c2;
2314 }
2315 }
2316 cur = cur->c2;
2317 }
2318 }
2319
2320 /* VC: Unique Element Type Declaration */
2321 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2322 if ((tst != NULL ) && (tst != elem)) {
2323 VERROR(ctxt->userData, "Redefinition of element %s\n",
2324 elem->name);
2325 ret = 0;
2326 }
2327 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2328 if ((tst != NULL ) && (tst != elem)) {
2329 VERROR(ctxt->userData, "Redefinition of element %s\n",
2330 elem->name);
2331 ret = 0;
2332 }
2333
2334 /* One ID per Element Type */
2335 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2336 ret = 0;
2337 }
2338 return(ret);
2339}
2340
2341/**
2342 * xmlValidateOneAttribute:
2343 * @ctxt: the validation context
2344 * @doc: a document instance
2345 * @elem: an element instance
2346 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00002347 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002348 *
2349 * Try to validate a single attribute for an element
2350 * basically it * does the following checks as described by the
2351 * XML-1.0 recommendation:
2352 * - [ VC: Attribute Value Type ]
2353 * - [ VC: Fixed Attribute Default ]
2354 * - [ VC: Entity Name ]
2355 * - [ VC: Name Token ]
2356 * - [ VC: ID ]
2357 * - [ VC: IDREF ]
2358 * - [ VC: Entity Name ]
2359 * - [ VC: Notation Attributes ]
2360 *
2361 * The ID/IDREF uniqueness and matching are done separately
2362 *
2363 * returns 1 if valid or 0 otherwise
2364 */
2365
2366int
2367xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002368 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002369 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002370 xmlAttributePtr attrDecl;
2371 int val;
2372 int ret = 1;
2373
2374 CHECK_DTD;
2375 if ((elem == NULL) || (elem->name == NULL)) return(0);
2376 if ((attr == NULL) || (attr->name == NULL)) return(0);
2377
2378 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2379 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2380 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2381
2382
2383 /* Validity Constraint: Attribute Value Type */
2384 if (attrDecl == NULL) {
2385 VERROR(ctxt->userData,
2386 "No declaration for attribute %s on element %s\n",
2387 attr->name, elem->name);
2388 return(0);
2389 }
2390 val = xmlValidateAttributeValue(attrDecl->type, value);
2391 if (val == 0) {
2392 VERROR(ctxt->userData,
2393 "Syntax of value for attribute %s on %s is not valid\n",
2394 attr->name, elem->name);
2395 ret = 0;
2396 }
2397
Daniel Veillardb96e6431999-08-29 21:02:19 +00002398 /* Validity Constraint: ID uniqueness */
2399 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2400 xmlAddID(ctxt, doc, value, attr);
2401 }
2402
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002403 if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2404 xmlAddRef(ctxt, doc, value, attr);
2405 }
2406
Daniel Veillardb05deb71999-08-10 19:04:08 +00002407 /* Validity Constraint: Notation Attributes */
2408 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2409 xmlEnumerationPtr tree = attrDecl->tree;
2410 xmlNotationPtr nota;
2411
2412 /* First check that the given NOTATION was declared */
2413 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2414 if (nota == NULL)
2415 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2416
2417 if (nota == NULL) {
2418 VERROR(ctxt->userData,
2419 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2420 value, attr->name, elem->name);
2421 ret = 0;
2422 }
2423
2424 /* Second, verify that it's among the list */
2425 while (tree != NULL) {
2426 if (!xmlStrcmp(tree->name, value)) break;
2427 tree = tree->next;
2428 }
2429 if (tree == NULL) {
2430 VERROR(ctxt->userData,
2431 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2432 value, attr->name, elem->name);
2433 ret = 0;
2434 }
2435 }
2436
2437 /* Validity Constraint: Enumeration */
2438 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2439 xmlEnumerationPtr tree = attrDecl->tree;
2440 while (tree != NULL) {
2441 if (!xmlStrcmp(tree->name, value)) break;
2442 tree = tree->next;
2443 }
2444 if (tree == NULL) {
2445 VERROR(ctxt->userData,
2446 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2447 value, attr->name, elem->name);
2448 ret = 0;
2449 }
2450 }
2451
2452 /* Fixed Attribute Default */
2453 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2454 (xmlStrcmp(attrDecl->defaultValue, value))) {
2455 VERROR(ctxt->userData,
2456 "Value for attribute %s on %s must be \"%s\"\n",
2457 attr->name, elem->name, attrDecl->defaultValue);
2458 ret = 0;
2459 }
2460
Daniel Veillardb96e6431999-08-29 21:02:19 +00002461 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002462 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2463 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2464 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2465 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002466 return(0);
2467 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002468 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002469 return(ret);
2470}
2471
2472int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2473 xmlElementContentPtr cont);
2474
2475/**
2476 * xmlValidateElementTypeExpr:
2477 * @ctxt: the validation context
2478 * @child: pointer to the child list
2479 * @cont: pointer to the content declaration
2480 *
2481 * Try to validate the content of an element of type element
2482 * but don't handle the occurence factor
2483 *
2484 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2485 * also update child value in-situ.
2486 */
2487
2488int
2489xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2490 xmlElementContentPtr cont) {
2491 xmlNodePtr cur;
2492 int ret = 1;
2493
2494 if (cont == NULL) return(-1);
2495 while (*child != NULL) {
2496 if ((*child)->type == XML_PI_NODE) {
2497 *child = (*child)->next;
2498 continue;
2499 }
2500 if ((*child)->type == XML_COMMENT_NODE) {
2501 *child = (*child)->next;
2502 continue;
2503 }
2504 else if ((*child)->type != XML_ELEMENT_NODE) {
2505 return(-1);
2506 }
2507 break;
2508 }
2509 switch (cont->type) {
2510 case XML_ELEMENT_CONTENT_PCDATA:
2511 /* Internal error !!! */
2512 fprintf(stderr, "Internal: MIXED struct bad\n");
2513 return(-1);
2514 case XML_ELEMENT_CONTENT_ELEMENT:
2515 if (*child == NULL) return(0);
2516 ret = (!xmlStrcmp((*child)->name, cont->name));
2517 if (ret == 1)
2518 *child = (*child)->next;
2519 return(ret);
2520 case XML_ELEMENT_CONTENT_OR:
2521 cur = *child;
2522 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2523 if (ret == -1) return(-1);
2524 if (ret == 1) {
2525 return(1);
2526 }
2527 /* rollback and retry the other path */
2528 *child = cur;
2529 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2530 if (ret == -1) return(-1);
2531 if (ret == 0) {
2532 *child = cur;
2533 return(0);
2534 }
2535 return(1);
2536 case XML_ELEMENT_CONTENT_SEQ:
2537 cur = *child;
2538 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2539 if (ret == -1) return(-1);
2540 if (ret == 0) {
2541 *child = cur;
2542 return(0);
2543 }
2544 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2545 if (ret == -1) return(-1);
2546 if (ret == 0) {
2547 *child = cur;
2548 return(0);
2549 }
2550 return(1);
2551 }
2552 return(ret);
2553}
2554
2555/**
2556 * xmlValidateElementTypeElement:
2557 * @ctxt: the validation context
2558 * @child: pointer to the child list
2559 * @cont: pointer to the content declaration
2560 *
2561 * Try to validate the content of an element of type element
2562 * yeah, Yet Another Regexp Implementation, and recursive
2563 *
2564 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2565 * also update child and content values in-situ.
2566 */
2567
2568int
2569xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2570 xmlElementContentPtr cont) {
2571 xmlNodePtr cur;
2572 int ret = 1;
2573
2574 if (cont == NULL) return(-1);
2575 while (*child != NULL) {
2576 if ((*child)->type == XML_PI_NODE) {
2577 *child = (*child)->next;
2578 continue;
2579 }
2580 if ((*child)->type == XML_COMMENT_NODE) {
2581 *child = (*child)->next;
2582 continue;
2583 }
2584 else if ((*child)->type != XML_ELEMENT_NODE) {
2585 return(-1);
2586 }
2587 break;
2588 }
2589 cur = *child;
2590 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2591 if (ret == -1) return(-1);
2592 switch (cont->ocur) {
2593 case XML_ELEMENT_CONTENT_ONCE:
2594 if (ret == 1) {
2595 return(1);
2596 }
2597 *child = cur;
2598 return(0);
2599 case XML_ELEMENT_CONTENT_OPT:
2600 if (ret == 0) {
2601 *child = cur;
2602 return(1);
2603 }
2604 break;
2605 case XML_ELEMENT_CONTENT_MULT:
2606 if (ret == 0) {
2607 *child = cur;
2608 break;
2609 }
2610 /* no break on purpose */
2611 case XML_ELEMENT_CONTENT_PLUS:
2612 if (ret == 0) {
2613 *child = cur;
2614 return(0);
2615 }
2616 do {
2617 cur = *child;
2618 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2619 } while (ret == 1);
2620 if (ret == -1) return(-1);
2621 *child = cur;
2622 break;
2623 }
2624 while (*child != NULL) {
2625 if ((*child)->type == XML_PI_NODE) {
2626 *child = (*child)->next;
2627 continue;
2628 }
2629 if ((*child)->type == XML_COMMENT_NODE) {
2630 *child = (*child)->next;
2631 continue;
2632 }
2633 else if ((*child)->type != XML_ELEMENT_NODE) {
2634 return(-1);
2635 }
2636 break;
2637 }
2638 return(1);
2639}
2640
2641/**
2642 * xmlSprintfElementChilds:
2643 * @buf: an output buffer
2644 * @content: An element
2645 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2646 *
2647 * This will dump the list of childs to the buffer
2648 * Intended just for the debug routine
2649 */
2650void
2651xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2652 xmlNodePtr cur;
2653
2654 if (node == NULL) return;
2655 if (glob) strcat(buf, "(");
2656 cur = node->childs;
2657 while (cur != NULL) {
2658 switch (cur->type) {
2659 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002660 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002661 if (cur->next != NULL)
2662 strcat(buf, " ");
2663 break;
2664 case XML_TEXT_NODE:
2665 case XML_CDATA_SECTION_NODE:
2666 case XML_ENTITY_REF_NODE:
2667 strcat(buf, "CDATA");
2668 if (cur->next != NULL)
2669 strcat(buf, " ");
2670 break;
2671 case XML_ATTRIBUTE_NODE:
2672 case XML_DOCUMENT_NODE:
2673 case XML_DOCUMENT_TYPE_NODE:
2674 case XML_DOCUMENT_FRAG_NODE:
2675 case XML_NOTATION_NODE:
2676 strcat(buf, "???");
2677 if (cur->next != NULL)
2678 strcat(buf, " ");
2679 break;
2680 case XML_ENTITY_NODE:
2681 case XML_PI_NODE:
2682 case XML_COMMENT_NODE:
2683 break;
2684 }
2685 cur = cur->next;
2686 }
2687 if (glob) strcat(buf, ")");
2688}
2689
2690
2691/**
2692 * xmlValidateOneElement:
2693 * @ctxt: the validation context
2694 * @doc: a document instance
2695 * @elem: an element instance
2696 *
2697 * Try to validate a single element and it's attributes,
2698 * basically it does the following checks as described by the
2699 * XML-1.0 recommendation:
2700 * - [ VC: Element Valid ]
2701 * - [ VC: Required Attribute ]
2702 * Then call xmlValidateOneAttribute() for each attribute present.
2703 *
2704 * The ID/IDREF checkings are done separately
2705 *
2706 * returns 1 if valid or 0 otherwise
2707 */
2708
2709int
2710xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2711 xmlNodePtr elem) {
2712 xmlElementPtr elemDecl;
2713 xmlElementContentPtr cont;
2714 xmlNodePtr child;
2715 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002716 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002717
2718 CHECK_DTD;
2719
2720 if ((elem == NULL) || (elem->name == NULL)) return(0);
2721
2722 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2723 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2724 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2725 if (elemDecl == NULL) {
2726 VERROR(ctxt->userData, "No declaration for element %s\n",
2727 elem->name);
2728 return(0);
2729 }
2730
2731 /* Check taht the element content matches the definition */
2732 switch (elemDecl->type) {
2733 case XML_ELEMENT_TYPE_EMPTY:
2734 if (elem->childs != NULL) {
2735 VERROR(ctxt->userData,
2736 "Element %s was declared EMPTY this one has content\n",
2737 elem->name);
2738 ret = 0;
2739 }
2740 break;
2741 case XML_ELEMENT_TYPE_ANY:
2742 /* I don't think anything is required then */
2743 break;
2744 case XML_ELEMENT_TYPE_MIXED:
2745 /* Hum, this start to get messy */
2746 child = elem->childs;
2747 while (child != NULL) {
2748 if (child->type == XML_ELEMENT_NODE) {
2749 name = child->name;
2750 cont = elemDecl->content;
2751 while (cont != NULL) {
2752 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2753 if (!xmlStrcmp(cont->name, name)) break;
2754 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2755 (cont->c1 != NULL) &&
2756 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2757 if (!xmlStrcmp(cont->c1->name, name)) break;
2758 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2759 (cont->c1 == NULL) ||
2760 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2761 /* Internal error !!! */
2762 fprintf(stderr, "Internal: MIXED struct bad\n");
2763 break;
2764 }
2765 cont = cont->c2;
2766 }
2767 if (cont == NULL) {
2768 VERROR(ctxt->userData,
2769 "Element %s is not declared in %s list of possible childs\n",
2770 name, elem->name);
2771 ret = 0;
2772 }
2773 }
2774 child = child->next;
2775 }
2776 break;
2777 case XML_ELEMENT_TYPE_ELEMENT:
2778 child = elem->childs;
2779 cont = elemDecl->content;
2780 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2781 if ((ret == 0) || (child != NULL)) {
2782 char expr[1000];
2783 char list[2000];
2784
2785 expr[0] = 0;
2786 xmlSprintfElementContent(expr, cont, 1);
2787 list[0] = 0;
2788 xmlSprintfElementChilds(list, elem, 1);
2789
2790 VERROR(ctxt->userData,
2791 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2792 elem->name, expr, list);
2793 ret = 0;
2794 }
2795 break;
2796 }
2797
Daniel Veillardb96e6431999-08-29 21:02:19 +00002798 /* TODO - [ VC: Required Attribute ] */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002799 return(ret);
2800}
2801
2802/**
2803 * xmlValidateRoot:
2804 * @ctxt: the validation context
2805 * @doc: a document instance
2806 *
2807 * Try to validate a the root element
2808 * basically it does the following check as described by the
2809 * XML-1.0 recommendation:
2810 * - [ VC: Root Element Type ]
2811 * it doesn't try to recurse or apply other check to the element
2812 *
2813 * returns 1 if valid or 0 otherwise
2814 */
2815
2816int
2817xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2818 if (doc == NULL) return(0);
2819
2820 if ((doc->intSubset == NULL) ||
2821 (doc->intSubset->name == NULL)) {
2822 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2823 return(0);
2824 }
2825 if ((doc->root == NULL) || (doc->root->name == NULL)) {
2826 VERROR(ctxt->userData, "Not valid: no root element\n");
2827 return(0);
2828 }
2829 if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2830 VERROR(ctxt->userData,
2831 "Not valid: root and DtD name do not match %s and %s\n",
2832 doc->root->name, doc->intSubset->name);
2833 return(0);
2834 }
2835 return(1);
2836}
2837
2838
2839/**
2840 * xmlValidateElement:
2841 * @ctxt: the validation context
2842 * @doc: a document instance
2843 * @elem: an element instance
2844 *
2845 * Try to validate the subtree under an element
2846 *
2847 * returns 1 if valid or 0 otherwise
2848 */
2849
2850int
2851xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002852 xmlNodePtr child;
2853 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002854 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002855 int ret = 1;
2856
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002857 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