blob: 7de29d02854c4699970e6ce6813692f8240e10c7 [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 Veillard51e3b151999-11-12 17:02:31 +0000312 xmlElementTypeVal 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);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002062}
2063
2064/**
2065 * xmlValidateNmtokensValue:
2066 * @value: an Mntokens value
2067 *
2068 * Validate that the given value match Nmtokens production
2069 *
2070 * [ VC: Name Token ]
2071 *
2072 * returns 1 if valid or 0 otherwise
2073 */
2074
2075int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002076xmlValidateNmtokensValue(const xmlChar *value) {
2077 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002078
2079 if (value == NULL) return(0);
2080 cur = value;
2081
2082 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2083 (*cur != '.') && (*cur != '-') &&
2084 (*cur != '_') && (*cur != ':') &&
2085 (!IS_COMBINING(*cur)) &&
2086 (!IS_EXTENDER(*cur)))
2087 return(0);
2088
2089 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2090 (*cur == '.') || (*cur == '-') ||
2091 (*cur == '_') || (*cur == ':') ||
2092 (IS_COMBINING(*cur)) ||
2093 (IS_EXTENDER(*cur)))
2094 cur++;
2095
2096 while (IS_BLANK(*cur)) {
2097 while (IS_BLANK(*cur)) cur++;
2098
2099 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2100 (*cur != '.') && (*cur != '-') &&
2101 (*cur != '_') && (*cur != ':') &&
2102 (!IS_COMBINING(*cur)) &&
2103 (!IS_EXTENDER(*cur)))
2104 return(0);
2105
2106 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2107 (*cur == '.') || (*cur == '-') ||
2108 (*cur == '_') || (*cur == ':') ||
2109 (IS_COMBINING(*cur)) ||
2110 (IS_EXTENDER(*cur)))
2111 cur++;
2112 }
2113
2114 if (*cur != 0) return(0);
2115
2116 return(1);
2117}
2118
2119/**
2120 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002121 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002122 * @doc: a document instance
2123 * @nota: a notation definition
2124 *
2125 * Try to validate a single notation definition
2126 * basically it does the following checks as described by the
2127 * XML-1.0 recommendation:
2128 * - it seems that no validity constraing exist on notation declarations
2129 * But this function get called anyway ...
2130 *
2131 * returns 1 if valid or 0 otherwise
2132 */
2133
2134int
2135xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2136 xmlNotationPtr nota) {
2137 int ret = 1;
2138
2139 return(ret);
2140}
2141
2142/**
2143 * xmlValidateAttributeValue:
2144 * @type: an attribute type
2145 * @value: an attribute value
2146 *
2147 * Validate that the given attribute value match the proper production
2148 *
2149 * [ VC: ID ]
2150 * Values of type ID must match the Name production....
2151 *
2152 * [ VC: IDREF ]
2153 * Values of type IDREF must match the Name production, and values
2154 * of type IDREFS must match Names ...
2155 *
2156 * [ VC: Entity Name ]
2157 * Values of type ENTITY must match the Name production, values
2158 * of type ENTITIES must match Names ...
2159 *
2160 * [ VC: Name Token ]
2161 * Values of type NMTOKEN must match the Nmtoken production; values
2162 * of type NMTOKENS must match Nmtokens.
2163 *
2164 * returns 1 if valid or 0 otherwise
2165 */
2166
2167int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002168xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002169 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002170 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002171 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002172 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002173 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002174 case XML_ATTRIBUTE_IDREF:
2175 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002176 case XML_ATTRIBUTE_NOTATION:
2177 return(xmlValidateNameValue(value));
2178 case XML_ATTRIBUTE_NMTOKENS:
2179 case XML_ATTRIBUTE_ENUMERATION:
2180 return(xmlValidateNmtokensValue(value));
2181 case XML_ATTRIBUTE_NMTOKEN:
2182 return(xmlValidateNmtokenValue(value));
2183 case XML_ATTRIBUTE_CDATA:
2184 break;
2185 }
2186 return(1);
2187}
2188
2189/**
2190 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002191 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002192 * @doc: a document instance
2193 * @attr: an attribute definition
2194 *
2195 * Try to validate a single attribute definition
2196 * basically it does the following checks as described by the
2197 * XML-1.0 recommendation:
2198 * - [ VC: Attribute Default Legal ]
2199 * - [ VC: Enumeration ]
2200 * - [ VC: ID Attribute Default ]
2201 *
2202 * The ID/IDREF uniqueness and matching are done separately
2203 *
2204 * returns 1 if valid or 0 otherwise
2205 */
2206
2207int
2208xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2209 xmlAttributePtr attr) {
2210 int ret = 1;
2211 int val;
2212 CHECK_DTD;
2213 if(attr == NULL) return(1);
2214
2215 /* Attribute Default Legal */
2216 /* Enumeration */
2217 if (attr->defaultValue != NULL) {
2218 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2219 if (val == 0) {
2220 VERROR(ctxt->userData,
2221 "Syntax of default value for attribute %s on %s is not valid\n",
2222 attr->name, attr->elem);
2223 }
2224 ret &= val;
2225 }
2226
2227 /* ID Attribute Default */
2228 if ((attr->type == XML_ATTRIBUTE_ID)&&
2229 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2230 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2231 VERROR(ctxt->userData,
2232 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2233 attr->name, attr->elem);
2234 ret = 0;
2235 }
2236
Daniel Veillardb96e6431999-08-29 21:02:19 +00002237 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002238 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2239 int nbId = 0;
2240
2241 /* the trick is taht we parse DtD as their own internal subset */
2242 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2243 attr->elem);
2244 if (elem != NULL) {
2245 nbId = xmlScanIDAttributeDecl(NULL, elem);
2246 }
2247 if (nbId >= 1)
2248 VERROR(ctxt->userData,
2249 "Element %s has ID attribute defined in the external subset : %s\n",
2250 attr->elem, attr->name);
2251 }
2252
2253 return(ret);
2254}
2255
2256/**
2257 * xmlValidateElementDecl:
2258 * @ctxt: the validation context
2259 * @doc: a document instance
2260 * @elem: an element definition
2261 *
2262 * Try to validate a single element definition
2263 * basically it does the following checks as described by the
2264 * XML-1.0 recommendation:
2265 * - [ VC: One ID per Element Type ]
2266 * - [ VC: No Duplicate Types ]
2267 * - [ VC: Unique Element Type Declaration ]
2268 *
2269 * returns 1 if valid or 0 otherwise
2270 */
2271
2272int
2273xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2274 xmlElementPtr elem) {
2275 int ret = 1;
2276 xmlElementPtr tst;
2277
2278 CHECK_DTD;
2279
2280 if (elem == NULL) return(1);
2281
2282 /* No Duplicate Types */
2283 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2284 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002285 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002286
2287 cur = elem->content;
2288 while (cur != NULL) {
2289 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2290 if (cur->c1 == NULL) break;
2291 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2292 name = cur->c1->name;
2293 next = cur->c2;
2294 while (next != NULL) {
2295 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2296 if (!xmlStrcmp(next->name, name)) {
2297 VERROR(ctxt->userData,
2298 "Definition of %s has duplicate references of %s\n",
2299 elem->name, name);
2300 ret = 0;
2301 }
2302 break;
2303 }
2304 if (next->c1 == NULL) break;
2305 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2306 if (!xmlStrcmp(next->c1->name, name)) {
2307 VERROR(ctxt->userData,
2308 "Definition of %s has duplicate references of %s\n",
2309 elem->name, name);
2310 ret = 0;
2311 }
2312 next = next->c2;
2313 }
2314 }
2315 cur = cur->c2;
2316 }
2317 }
2318
2319 /* VC: Unique Element Type Declaration */
2320 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2321 if ((tst != NULL ) && (tst != elem)) {
2322 VERROR(ctxt->userData, "Redefinition of element %s\n",
2323 elem->name);
2324 ret = 0;
2325 }
2326 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2327 if ((tst != NULL ) && (tst != elem)) {
2328 VERROR(ctxt->userData, "Redefinition of element %s\n",
2329 elem->name);
2330 ret = 0;
2331 }
2332
2333 /* One ID per Element Type */
2334 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2335 ret = 0;
2336 }
2337 return(ret);
2338}
2339
2340/**
2341 * xmlValidateOneAttribute:
2342 * @ctxt: the validation context
2343 * @doc: a document instance
2344 * @elem: an element instance
2345 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00002346 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002347 *
2348 * Try to validate a single attribute for an element
2349 * basically it * does the following checks as described by the
2350 * XML-1.0 recommendation:
2351 * - [ VC: Attribute Value Type ]
2352 * - [ VC: Fixed Attribute Default ]
2353 * - [ VC: Entity Name ]
2354 * - [ VC: Name Token ]
2355 * - [ VC: ID ]
2356 * - [ VC: IDREF ]
2357 * - [ VC: Entity Name ]
2358 * - [ VC: Notation Attributes ]
2359 *
2360 * The ID/IDREF uniqueness and matching are done separately
2361 *
2362 * returns 1 if valid or 0 otherwise
2363 */
2364
2365int
2366xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002367 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002368 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002369 xmlAttributePtr attrDecl;
2370 int val;
2371 int ret = 1;
2372
2373 CHECK_DTD;
2374 if ((elem == NULL) || (elem->name == NULL)) return(0);
2375 if ((attr == NULL) || (attr->name == NULL)) return(0);
2376
2377 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2378 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2379 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2380
2381
2382 /* Validity Constraint: Attribute Value Type */
2383 if (attrDecl == NULL) {
2384 VERROR(ctxt->userData,
2385 "No declaration for attribute %s on element %s\n",
2386 attr->name, elem->name);
2387 return(0);
2388 }
2389 val = xmlValidateAttributeValue(attrDecl->type, value);
2390 if (val == 0) {
2391 VERROR(ctxt->userData,
2392 "Syntax of value for attribute %s on %s is not valid\n",
2393 attr->name, elem->name);
2394 ret = 0;
2395 }
2396
Daniel Veillardb96e6431999-08-29 21:02:19 +00002397 /* Validity Constraint: ID uniqueness */
2398 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2399 xmlAddID(ctxt, doc, value, attr);
2400 }
2401
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002402 if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2403 xmlAddRef(ctxt, doc, value, attr);
2404 }
2405
Daniel Veillardb05deb71999-08-10 19:04:08 +00002406 /* Validity Constraint: Notation Attributes */
2407 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2408 xmlEnumerationPtr tree = attrDecl->tree;
2409 xmlNotationPtr nota;
2410
2411 /* First check that the given NOTATION was declared */
2412 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2413 if (nota == NULL)
2414 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2415
2416 if (nota == NULL) {
2417 VERROR(ctxt->userData,
2418 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2419 value, attr->name, elem->name);
2420 ret = 0;
2421 }
2422
2423 /* Second, verify that it's among the list */
2424 while (tree != NULL) {
2425 if (!xmlStrcmp(tree->name, value)) break;
2426 tree = tree->next;
2427 }
2428 if (tree == NULL) {
2429 VERROR(ctxt->userData,
2430 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2431 value, attr->name, elem->name);
2432 ret = 0;
2433 }
2434 }
2435
2436 /* Validity Constraint: Enumeration */
2437 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2438 xmlEnumerationPtr tree = attrDecl->tree;
2439 while (tree != NULL) {
2440 if (!xmlStrcmp(tree->name, value)) break;
2441 tree = tree->next;
2442 }
2443 if (tree == NULL) {
2444 VERROR(ctxt->userData,
2445 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2446 value, attr->name, elem->name);
2447 ret = 0;
2448 }
2449 }
2450
2451 /* Fixed Attribute Default */
2452 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2453 (xmlStrcmp(attrDecl->defaultValue, value))) {
2454 VERROR(ctxt->userData,
2455 "Value for attribute %s on %s must be \"%s\"\n",
2456 attr->name, elem->name, attrDecl->defaultValue);
2457 ret = 0;
2458 }
2459
Daniel Veillardb96e6431999-08-29 21:02:19 +00002460 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002461 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2462 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2463 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2464 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002465 return(0);
2466 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002467 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002468 return(ret);
2469}
2470
2471int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2472 xmlElementContentPtr cont);
2473
2474/**
2475 * xmlValidateElementTypeExpr:
2476 * @ctxt: the validation context
2477 * @child: pointer to the child list
2478 * @cont: pointer to the content declaration
2479 *
2480 * Try to validate the content of an element of type element
2481 * but don't handle the occurence factor
2482 *
2483 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2484 * also update child value in-situ.
2485 */
2486
2487int
2488xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2489 xmlElementContentPtr cont) {
2490 xmlNodePtr cur;
2491 int ret = 1;
2492
2493 if (cont == NULL) return(-1);
2494 while (*child != NULL) {
2495 if ((*child)->type == XML_PI_NODE) {
2496 *child = (*child)->next;
2497 continue;
2498 }
2499 if ((*child)->type == XML_COMMENT_NODE) {
2500 *child = (*child)->next;
2501 continue;
2502 }
2503 else if ((*child)->type != XML_ELEMENT_NODE) {
2504 return(-1);
2505 }
2506 break;
2507 }
2508 switch (cont->type) {
2509 case XML_ELEMENT_CONTENT_PCDATA:
2510 /* Internal error !!! */
2511 fprintf(stderr, "Internal: MIXED struct bad\n");
2512 return(-1);
2513 case XML_ELEMENT_CONTENT_ELEMENT:
2514 if (*child == NULL) return(0);
2515 ret = (!xmlStrcmp((*child)->name, cont->name));
2516 if (ret == 1)
2517 *child = (*child)->next;
2518 return(ret);
2519 case XML_ELEMENT_CONTENT_OR:
2520 cur = *child;
2521 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2522 if (ret == -1) return(-1);
2523 if (ret == 1) {
2524 return(1);
2525 }
2526 /* rollback and retry the other path */
2527 *child = cur;
2528 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2529 if (ret == -1) return(-1);
2530 if (ret == 0) {
2531 *child = cur;
2532 return(0);
2533 }
2534 return(1);
2535 case XML_ELEMENT_CONTENT_SEQ:
2536 cur = *child;
2537 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2538 if (ret == -1) return(-1);
2539 if (ret == 0) {
2540 *child = cur;
2541 return(0);
2542 }
2543 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2544 if (ret == -1) return(-1);
2545 if (ret == 0) {
2546 *child = cur;
2547 return(0);
2548 }
2549 return(1);
2550 }
2551 return(ret);
2552}
2553
2554/**
2555 * xmlValidateElementTypeElement:
2556 * @ctxt: the validation context
2557 * @child: pointer to the child list
2558 * @cont: pointer to the content declaration
2559 *
2560 * Try to validate the content of an element of type element
2561 * yeah, Yet Another Regexp Implementation, and recursive
2562 *
2563 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2564 * also update child and content values in-situ.
2565 */
2566
2567int
2568xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2569 xmlElementContentPtr cont) {
2570 xmlNodePtr cur;
2571 int ret = 1;
2572
2573 if (cont == NULL) return(-1);
2574 while (*child != NULL) {
2575 if ((*child)->type == XML_PI_NODE) {
2576 *child = (*child)->next;
2577 continue;
2578 }
2579 if ((*child)->type == XML_COMMENT_NODE) {
2580 *child = (*child)->next;
2581 continue;
2582 }
2583 else if ((*child)->type != XML_ELEMENT_NODE) {
2584 return(-1);
2585 }
2586 break;
2587 }
2588 cur = *child;
2589 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2590 if (ret == -1) return(-1);
2591 switch (cont->ocur) {
2592 case XML_ELEMENT_CONTENT_ONCE:
2593 if (ret == 1) {
2594 return(1);
2595 }
2596 *child = cur;
2597 return(0);
2598 case XML_ELEMENT_CONTENT_OPT:
2599 if (ret == 0) {
2600 *child = cur;
2601 return(1);
2602 }
2603 break;
2604 case XML_ELEMENT_CONTENT_MULT:
2605 if (ret == 0) {
2606 *child = cur;
2607 break;
2608 }
2609 /* no break on purpose */
2610 case XML_ELEMENT_CONTENT_PLUS:
2611 if (ret == 0) {
2612 *child = cur;
2613 return(0);
2614 }
2615 do {
2616 cur = *child;
2617 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2618 } while (ret == 1);
2619 if (ret == -1) return(-1);
2620 *child = cur;
2621 break;
2622 }
2623 while (*child != NULL) {
2624 if ((*child)->type == XML_PI_NODE) {
2625 *child = (*child)->next;
2626 continue;
2627 }
2628 if ((*child)->type == XML_COMMENT_NODE) {
2629 *child = (*child)->next;
2630 continue;
2631 }
2632 else if ((*child)->type != XML_ELEMENT_NODE) {
2633 return(-1);
2634 }
2635 break;
2636 }
2637 return(1);
2638}
2639
2640/**
2641 * xmlSprintfElementChilds:
2642 * @buf: an output buffer
2643 * @content: An element
2644 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2645 *
2646 * This will dump the list of childs to the buffer
2647 * Intended just for the debug routine
2648 */
2649void
2650xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2651 xmlNodePtr cur;
2652
2653 if (node == NULL) return;
2654 if (glob) strcat(buf, "(");
2655 cur = node->childs;
2656 while (cur != NULL) {
2657 switch (cur->type) {
2658 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002659 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002660 if (cur->next != NULL)
2661 strcat(buf, " ");
2662 break;
2663 case XML_TEXT_NODE:
2664 case XML_CDATA_SECTION_NODE:
2665 case XML_ENTITY_REF_NODE:
2666 strcat(buf, "CDATA");
2667 if (cur->next != NULL)
2668 strcat(buf, " ");
2669 break;
2670 case XML_ATTRIBUTE_NODE:
2671 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002672 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002673 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
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002965
2966/************************************************************************
2967 * *
2968 * Routines for dynamic validation editing *
2969 * *
2970 ************************************************************************/
2971
2972/**
2973 * xmlValidGetPotentialChildren:
2974 * @ctree: an element content tree
2975 * @list: an array to store the list of child names
2976 * @len: a pointer to the number of element in the list
2977 * @max: the size of the array
2978 *
2979 * Build/extend a list of potential children allowed by the content tree
2980 *
2981 * returns the number of element in the list, or -1 in case of error.
2982 */
2983
2984int
2985xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
2986 int *len, int max) {
2987 int i;
2988
2989 if ((ctree == NULL) || (list == NULL) || (len == NULL))
2990 return(-1);
2991 if (*len >= max) return(*len);
2992
2993 switch (ctree->type) {
2994 case XML_ELEMENT_CONTENT_PCDATA:
2995 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00002996 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
2997 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002998 break;
2999 case XML_ELEMENT_CONTENT_ELEMENT:
3000 for (i = 0; i < *len;i++)
3001 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
3002 list[(*len)++] = ctree->name;
3003 break;
3004 case XML_ELEMENT_CONTENT_SEQ:
3005 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3006 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3007 break;
3008 case XML_ELEMENT_CONTENT_OR:
3009 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3010 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3011 break;
3012 }
3013
3014 return(*len);
3015}
3016
3017/**
3018 * xmlValidGetValidElements:
3019 * @prev: an element to insert after
3020 * @next: an element to insert next
3021 * @list: an array to store the list of child names
3022 * @max: the size of the array
3023 *
3024 * This function returns the list of authorized children to insert
3025 * within an existing tree while respecting the validity constraints
3026 * forced by the Dtd. The insertion point is defined using @prev and
3027 * @next in the following ways:
3028 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3029 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3030 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3031 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3032 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
3033 *
3034 * pointers to the element names are inserted at the beginning of the array
3035 * and do not need to be freed.
3036 *
3037 * returns the number of element in the list, or -1 in case of error. If
3038 * the function returns the value @max the caller is invited to grow the
3039 * receiving array and retry.
3040 */
3041
3042int
3043xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3044 int max) {
3045 int nb_valid_elements = 0;
3046 const xmlChar *elements[256];
3047 int nb_elements = 0, i;
3048
3049 xmlNode *ref_node;
3050 xmlNode *parent;
3051 xmlNode *test_node;
3052
3053 xmlNode *prev_next;
3054 xmlNode *next_prev;
3055 xmlNode *parent_childs;
3056 xmlNode *parent_last;
3057
3058 xmlElement *element_desc;
3059
3060 if (prev == NULL && next == NULL)
3061 return(-1);
3062
3063 if (list == NULL) return(-1);
3064 if (max <= 0) return(-1);
3065
3066 nb_valid_elements = 0;
3067 ref_node = prev ? prev : next;
3068 parent = ref_node->parent;
3069
3070 /*
3071 * Retrieves the parent element declaration
3072 */
3073 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3074 parent->name);
3075 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3076 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3077 parent->name);
3078 if (element_desc == NULL) return(-1);
3079
3080 /*
3081 * Do a backup of the current tree structure
3082 */
3083 prev_next = prev ? prev->next : NULL;
3084 next_prev = next ? next->prev : NULL;
3085 parent_childs = parent->childs;
3086 parent_last = parent->last;
3087
3088 /*
3089 * Creates a dummy node and insert it into the tree
3090 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003091 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003092 test_node->doc = ref_node->doc;
3093 test_node->parent = parent;
3094 test_node->prev = prev;
3095 test_node->next = next;
3096
3097 if (prev) prev->next = test_node;
3098 else parent->childs = test_node;
3099
3100 if (next) next->prev = test_node;
3101 else parent->last = test_node;
3102
3103 /*
3104 * Insert each potential child node and check if the parent is
3105 * still valid
3106 */
3107 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
3108 elements, &nb_elements, 256);
3109
3110 for (i = 0;i < nb_elements;i++) {
3111 test_node->name = elements[i];
3112 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
3113 int j;
3114
3115 for (j = 0; j < nb_valid_elements;j++)
3116 if (!xmlStrcmp(elements[i], list[j])) break;
3117 list[nb_valid_elements++] = elements[i];
3118 if (nb_valid_elements >= max) break;
3119 }
3120 }
3121
3122 /*
3123 * Restore the tree structure
3124 */
3125 if (prev) prev->next = prev_next;
3126 if (next) next->prev = next_prev;
3127 parent->childs = parent_childs;
3128 parent->last = parent_last;
3129
3130 return(nb_valid_elements);
3131}