blob: 1efdbd06da2e8de200682e117ec31ec0f7b198a0 [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 Veillard10a2c651999-12-12 13:03:50 +0000763 xmlChar *rname;
764 xmlChar *ns;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000765 int i;
766
767 if (dtd == NULL) {
768 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
769 return(NULL);
770 }
771 if (name == NULL) {
772 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
773 return(NULL);
774 }
775 if (elem == NULL) {
776 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
777 return(NULL);
778 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000779 /*
780 * Check the type and possibly the default value.
781 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000782 switch (type) {
783 case XML_ATTRIBUTE_CDATA:
784 break;
785 case XML_ATTRIBUTE_ID:
786 break;
787 case XML_ATTRIBUTE_IDREF:
788 break;
789 case XML_ATTRIBUTE_IDREFS:
790 break;
791 case XML_ATTRIBUTE_ENTITY:
792 break;
793 case XML_ATTRIBUTE_ENTITIES:
794 break;
795 case XML_ATTRIBUTE_NMTOKEN:
796 break;
797 case XML_ATTRIBUTE_NMTOKENS:
798 break;
799 case XML_ATTRIBUTE_ENUMERATION:
800 break;
801 case XML_ATTRIBUTE_NOTATION:
802 break;
803 default:
804 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
805 return(NULL);
806 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000807 if ((defaultValue != NULL) &&
808 (!xmlValidateAttributeValue(type, defaultValue))) {
809 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
810 elem, name, defaultValue);
811 defaultValue = NULL;
812 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000813
814 /*
815 * Create the Attribute table if needed.
816 */
817 table = dtd->attributes;
818 if (table == NULL)
819 table = dtd->attributes = xmlCreateAttributeTable();
820 if (table == NULL) {
821 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
822 return(NULL);
823 }
824
825 /*
Daniel Veillard10a2c651999-12-12 13:03:50 +0000826 * Split the full name into a namespace prefix and the tag name
827 */
828 rname = xmlSplitQName(name, &ns);
829
830 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +0000831 * Validity Check:
832 * Search the DTD for previous declarations of the ATTLIST
833 */
834 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000835 cur = table->table[i];
Daniel Veillard10a2c651999-12-12 13:03:50 +0000836 if ((ns != NULL) && (cur->prefix == NULL)) continue;
837 if ((ns == NULL) && (cur->prefix != NULL)) continue;
838 if ((!xmlStrcmp(cur->name, rname)) && (!xmlStrcmp(cur->elem, elem)) &&
839 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000840 /*
841 * The attribute is already defined in this Dtd.
842 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000843 VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
844 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000845 }
846 }
847
848 /*
849 * Grow the table, if needed.
850 */
851 if (table->nb_attributes >= table->max_attributes) {
852 /*
853 * need more attributes.
854 */
855 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000856 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000857 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000858 sizeof(xmlAttributePtr));
859 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000860 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
861 return(NULL);
862 }
863 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000864 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000865 if (ret == NULL) {
866 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
867 return(NULL);
868 }
869 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000870
871 /*
872 * fill the structure.
873 */
874 ret->type = type;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000875 ret->name = rname;
876 ret->prefix = ns;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000877 ret->elem = xmlStrdup(elem);
878 ret->def = def;
879 ret->tree = tree;
880 if (defaultValue != NULL)
881 ret->defaultValue = xmlStrdup(defaultValue);
882 else
883 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000884 elemDef = xmlGetDtdElementDesc(dtd, elem);
885 if (elemDef != NULL) {
886 if ((type == XML_ATTRIBUTE_ID) &&
887 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
888 VERROR(ctxt->userData,
889 "Element %s has too may ID attributes defined : %s\n",
890 elem, name);
891 ret->next = elemDef->attributes;
892 elemDef->attributes = ret;
893 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000894 table->nb_attributes++;
895
896 return(ret);
897}
898
899/**
900 * xmlFreeAttribute:
901 * @elem: An attribute
902 *
903 * Deallocate the memory used by an attribute definition
904 */
905void
906xmlFreeAttribute(xmlAttributePtr attr) {
907 if (attr == NULL) return;
908 if (attr->tree != NULL)
909 xmlFreeEnumeration(attr->tree);
910 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000911 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000912 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000913 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000914 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000915 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +0000916 if (attr->prefix != NULL)
917 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000918 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000919 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000920}
921
922/**
923 * xmlFreeAttributeTable:
924 * @table: An attribute table
925 *
926 * Deallocate the memory used by an entities hash table.
927 */
928void
929xmlFreeAttributeTable(xmlAttributeTablePtr table) {
930 int i;
931
932 if (table == NULL) return;
933
934 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000935 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000936 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000937 xmlFree(table->table);
938 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000939}
940
941/**
942 * xmlCopyAttributeTable:
943 * @table: An attribute table
944 *
945 * Build a copy of an attribute table.
946 *
947 * Returns the new xmlAttributeTablePtr or NULL in case of error.
948 */
949xmlAttributeTablePtr
950xmlCopyAttributeTable(xmlAttributeTablePtr table) {
951 xmlAttributeTablePtr ret;
952 xmlAttributePtr cur, attr;
953 int i;
954
Daniel Veillard6454aec1999-09-02 22:04:43 +0000955 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000956 if (ret == NULL) {
957 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
958 return(NULL);
959 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000960 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000961 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000962 if (ret->table == NULL) {
963 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000964 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000965 return(NULL);
966 }
967 ret->max_attributes = table->max_attributes;
968 ret->nb_attributes = table->nb_attributes;
969 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000970 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +0000971 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000972 if (cur == NULL) {
973 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000974 xmlFree(ret);
975 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000976 return(NULL);
977 }
978 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000979 cur->type = attr->type;
980 cur->def = attr->def;
981 cur->tree = xmlCopyEnumeration(attr->tree);
982 if (attr->elem != NULL)
983 cur->elem = xmlStrdup(attr->elem);
984 else
985 cur->elem = NULL;
986 if (attr->name != NULL)
987 cur->name = xmlStrdup(attr->name);
988 else
989 cur->name = NULL;
990 if (attr->defaultValue != NULL)
991 cur->defaultValue = xmlStrdup(attr->defaultValue);
992 else
993 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000994 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000995 }
996 return(ret);
997}
998
999/**
1000 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001001 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001002 * @table: An attribute table
1003 *
1004 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001005 */
1006void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001007xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001008 int i;
1009 xmlAttributePtr cur;
1010
1011 if (table == NULL) return;
1012
1013 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001014 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001015 xmlBufferWriteChar(buf, "<!ATTLIST ");
1016 xmlBufferWriteCHAR(buf, cur->elem);
1017 xmlBufferWriteChar(buf, " ");
1018 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001019 switch (cur->type) {
1020 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001021 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001022 break;
1023 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001024 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001025 break;
1026 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001027 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001028 break;
1029 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001030 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001031 break;
1032 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001033 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001034 break;
1035 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001036 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001037 break;
1038 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001039 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001040 break;
1041 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001042 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001043 break;
1044 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001045 xmlBufferWriteChar(buf, " (");
1046 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001047 break;
1048 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001049 xmlBufferWriteChar(buf, " NOTATION (");
1050 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001051 break;
1052 default:
1053 fprintf(stderr,
1054 "xmlDumpAttributeTable: internal: unknown type %d\n",
1055 cur->type);
1056 }
1057 switch (cur->def) {
1058 case XML_ATTRIBUTE_NONE:
1059 break;
1060 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001061 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001062 break;
1063 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001064 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001065 break;
1066 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001067 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001068 break;
1069 default:
1070 fprintf(stderr,
1071 "xmlDumpAttributeTable: internal: unknown default %d\n",
1072 cur->def);
1073 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001074 if (cur->defaultValue != NULL) {
1075 xmlBufferWriteChar(buf, " ");
1076 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1077 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001078 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001079 }
1080}
1081
1082/************************************************************************
1083 * *
1084 * NOTATIONs *
1085 * *
1086 ************************************************************************/
1087/**
1088 * xmlCreateNotationTable:
1089 *
1090 * create and initialize an empty notation hash table.
1091 *
1092 * Returns the xmlNotationTablePtr just created or NULL in case
1093 * of error.
1094 */
1095xmlNotationTablePtr
1096xmlCreateNotationTable(void) {
1097 xmlNotationTablePtr ret;
1098
1099 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001100 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001101 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001102 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001103 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001104 return(NULL);
1105 }
1106 ret->max_notations = XML_MIN_NOTATION_TABLE;
1107 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001108 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001109 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001110 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001111 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001112 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001113 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001114 return(NULL);
1115 }
1116 return(ret);
1117}
1118
1119
1120/**
1121 * xmlAddNotationDecl:
1122 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001123 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001124 * @name: the entity name
1125 * @PublicID: the public identifier or NULL
1126 * @SystemID: the system identifier or NULL
1127 *
1128 * Register a new notation declaration
1129 *
1130 * Returns NULL if not, othervise the entity
1131 */
1132xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001133xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1134 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001135 xmlNotationPtr ret, cur;
1136 xmlNotationTablePtr table;
1137 int i;
1138
1139 if (dtd == NULL) {
1140 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1141 return(NULL);
1142 }
1143 if (name == NULL) {
1144 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1145 return(NULL);
1146 }
1147 if ((PublicID == NULL) && (SystemID == NULL)) {
1148 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1149 }
1150
1151 /*
1152 * Create the Notation table if needed.
1153 */
1154 table = dtd->notations;
1155 if (table == NULL)
1156 table = dtd->notations = xmlCreateNotationTable();
1157 if (table == NULL) {
1158 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1159 return(NULL);
1160 }
1161
1162 /*
1163 * Validity Check:
1164 * Search the DTD for previous declarations of the ATTLIST
1165 */
1166 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001167 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001168 if (!xmlStrcmp(cur->name, name)) {
1169 /*
1170 * The notation is already defined in this Dtd.
1171 */
1172 fprintf(stderr,
1173 "xmlAddNotationDecl: %s already defined\n", name);
1174 }
1175 }
1176
1177 /*
1178 * Grow the table, if needed.
1179 */
1180 if (table->nb_notations >= table->max_notations) {
1181 /*
1182 * need more notations.
1183 */
1184 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001185 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001186 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001187 sizeof(xmlNotationPtr));
1188 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001189 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1190 return(NULL);
1191 }
1192 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001193 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001194 if (ret == NULL) {
1195 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1196 return(NULL);
1197 }
1198 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001199
1200 /*
1201 * fill the structure.
1202 */
1203 ret->name = xmlStrdup(name);
1204 if (SystemID != NULL)
1205 ret->SystemID = xmlStrdup(SystemID);
1206 else
1207 ret->SystemID = NULL;
1208 if (PublicID != NULL)
1209 ret->PublicID = xmlStrdup(PublicID);
1210 else
1211 ret->PublicID = NULL;
1212 table->nb_notations++;
1213
1214 return(ret);
1215}
1216
1217/**
1218 * xmlFreeNotation:
1219 * @not: A notation
1220 *
1221 * Deallocate the memory used by an notation definition
1222 */
1223void
1224xmlFreeNotation(xmlNotationPtr nota) {
1225 if (nota == NULL) return;
1226 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001227 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001228 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001229 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001230 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001231 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001232 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001233 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001234}
1235
1236/**
1237 * xmlFreeNotationTable:
1238 * @table: An notation table
1239 *
1240 * Deallocate the memory used by an entities hash table.
1241 */
1242void
1243xmlFreeNotationTable(xmlNotationTablePtr table) {
1244 int i;
1245
1246 if (table == NULL) return;
1247
1248 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001249 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001250 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001251 xmlFree(table->table);
1252 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001253}
1254
1255/**
1256 * xmlCopyNotationTable:
1257 * @table: A notation table
1258 *
1259 * Build a copy of a notation table.
1260 *
1261 * Returns the new xmlNotationTablePtr or NULL in case of error.
1262 */
1263xmlNotationTablePtr
1264xmlCopyNotationTable(xmlNotationTablePtr table) {
1265 xmlNotationTablePtr ret;
1266 xmlNotationPtr cur, nota;
1267 int i;
1268
Daniel Veillard6454aec1999-09-02 22:04:43 +00001269 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001270 if (ret == NULL) {
1271 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1272 return(NULL);
1273 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001274 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001275 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001276 if (ret->table == NULL) {
1277 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001278 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001279 return(NULL);
1280 }
1281 ret->max_notations = table->max_notations;
1282 ret->nb_notations = table->nb_notations;
1283 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001284 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001285 if (cur == NULL) {
1286 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001287 xmlFree(ret);
1288 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001289 return(NULL);
1290 }
1291 ret->table[i] = cur;
1292 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001293 if (nota->name != NULL)
1294 cur->name = xmlStrdup(nota->name);
1295 else
1296 cur->name = NULL;
1297 if (nota->PublicID != NULL)
1298 cur->PublicID = xmlStrdup(nota->PublicID);
1299 else
1300 cur->PublicID = NULL;
1301 if (nota->SystemID != NULL)
1302 cur->SystemID = xmlStrdup(nota->SystemID);
1303 else
1304 cur->SystemID = NULL;
1305 }
1306 return(ret);
1307}
1308
1309/**
1310 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001311 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001312 * @table: A notation table
1313 *
1314 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001315 */
1316void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001317xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001318 int i;
1319 xmlNotationPtr cur;
1320
1321 if (table == NULL) return;
1322
1323 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001324 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001325 xmlBufferWriteChar(buf, "<!NOTATION ");
1326 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001327 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001328 xmlBufferWriteChar(buf, " PUBLIC ");
1329 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001330 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001331 xmlBufferWriteChar(buf, " ");
1332 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001333 }
1334 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001335 xmlBufferWriteChar(buf, " SYSTEM ");
1336 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001337 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001338 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001339 }
1340}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001341
1342/************************************************************************
1343 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001344 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001345 * *
1346 ************************************************************************/
1347/**
1348 * xmlCreateIDTable:
1349 *
1350 * create and initialize an empty id hash table.
1351 *
1352 * Returns the xmlIDTablePtr just created or NULL in case
1353 * of error.
1354 */
1355xmlIDTablePtr
1356xmlCreateIDTable(void) {
1357 xmlIDTablePtr ret;
1358
1359 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001360 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001361 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001362 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001363 (long)sizeof(xmlIDTable));
1364 return(NULL);
1365 }
1366 ret->max_ids = XML_MIN_NOTATION_TABLE;
1367 ret->nb_ids = 0;
1368 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001369 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001370 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001371 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001372 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001373 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001374 return(NULL);
1375 }
1376 return(ret);
1377}
1378
1379
1380/**
1381 * xmlAddID:
1382 * @ctxt: the validation context
1383 * @doc: pointer to the document
1384 * @value: the value name
1385 * @attr: the attribute holding the ID
1386 *
1387 * Register a new id declaration
1388 *
1389 * Returns NULL if not, othervise the new xmlIDPtr
1390 */
1391xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001392xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001393 xmlAttrPtr attr) {
1394 xmlIDPtr ret, cur;
1395 xmlIDTablePtr table;
1396 int i;
1397
1398 if (doc == NULL) {
1399 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1400 return(NULL);
1401 }
1402 if (value == NULL) {
1403 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1404 return(NULL);
1405 }
1406 if (attr == NULL) {
1407 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1408 return(NULL);
1409 }
1410
1411 /*
1412 * Create the ID table if needed.
1413 */
1414 table = doc->ids;
1415 if (table == NULL)
1416 table = doc->ids = xmlCreateIDTable();
1417 if (table == NULL) {
1418 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1419 return(NULL);
1420 }
1421
1422 /*
1423 * Validity Check:
1424 * Search the DTD for previous declarations of the ATTLIST
1425 */
1426 for (i = 0;i < table->nb_ids;i++) {
1427 cur = table->table[i];
1428 if (!xmlStrcmp(cur->value, value)) {
1429 /*
1430 * The id is already defined in this Dtd.
1431 */
1432 VERROR(ctxt->userData, "ID %s already defined\n", value);
1433 return(NULL);
1434 }
1435 }
1436
1437 /*
1438 * Grow the table, if needed.
1439 */
1440 if (table->nb_ids >= table->max_ids) {
1441 /*
1442 * need more ids.
1443 */
1444 table->max_ids *= 2;
1445 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001446 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001447 sizeof(xmlIDPtr));
1448 if (table->table == NULL) {
1449 fprintf(stderr, "xmlAddID: out of memory\n");
1450 return(NULL);
1451 }
1452 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001453 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001454 if (ret == NULL) {
1455 fprintf(stderr, "xmlAddID: out of memory\n");
1456 return(NULL);
1457 }
1458 table->table[table->nb_ids] = ret;
1459
1460 /*
1461 * fill the structure.
1462 */
1463 ret->value = xmlStrdup(value);
1464 ret->attr = attr;
1465 table->nb_ids++;
1466
1467 return(ret);
1468}
1469
1470/**
1471 * xmlFreeID:
1472 * @not: A id
1473 *
1474 * Deallocate the memory used by an id definition
1475 */
1476void
1477xmlFreeID(xmlIDPtr id) {
1478 if (id == NULL) return;
1479 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001480 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001481 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001482 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001483}
1484
1485/**
1486 * xmlFreeIDTable:
1487 * @table: An id table
1488 *
1489 * Deallocate the memory used by an ID hash table.
1490 */
1491void
1492xmlFreeIDTable(xmlIDTablePtr table) {
1493 int i;
1494
1495 if (table == NULL) return;
1496
1497 for (i = 0;i < table->nb_ids;i++) {
1498 xmlFreeID(table->table[i]);
1499 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001500 xmlFree(table->table);
1501 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001502}
1503
1504/**
1505 * xmlIsID
1506 * @doc: the document
1507 * @elem: the element carrying the attribute
1508 * @attr: the attribute
1509 *
1510 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1511 * then this is simple, otherwise we use an heuristic: name ID (upper
1512 * or lowercase).
1513 *
1514 * Returns 0 or 1 depending on the lookup result
1515 */
1516int
1517xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1518 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1519 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1520 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1521 (attr->name[2] == 0)) return(1);
1522 } else {
1523 xmlAttributePtr attrDecl;
1524
1525 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1526 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1527 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1528 attr->name);
1529
Daniel Veillardb96e6431999-08-29 21:02:19 +00001530 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001531 return(1);
1532 }
1533 return(0);
1534}
1535
Daniel Veillardb96e6431999-08-29 21:02:19 +00001536/**
1537 * xmlGetID:
1538 * @doc: pointer to the document
1539 * @ID: the ID value
1540 *
1541 * Search the attribute declaring the given ID
1542 *
1543 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1544 */
1545xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001546xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001547 xmlIDPtr cur;
1548 xmlIDTablePtr table;
1549 int i;
1550
1551 if (doc == NULL) {
1552 fprintf(stderr, "xmlGetID: doc == NULL\n");
1553 return(NULL);
1554 }
1555
1556 if (ID == NULL) {
1557 fprintf(stderr, "xmlGetID: ID == NULL\n");
1558 return(NULL);
1559 }
1560
1561 table = doc->ids;
1562 if (table == NULL)
1563 return(NULL);
1564
1565 /*
1566 * Search the ID list.
1567 */
1568 for (i = 0;i < table->nb_ids;i++) {
1569 cur = table->table[i];
1570 if (!xmlStrcmp(cur->value, ID)) {
1571 return(cur->attr);
1572 }
1573 }
1574 return(NULL);
1575}
1576
Daniel Veillard991e63d1999-08-15 23:32:28 +00001577/************************************************************************
1578 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001579 * Refs *
1580 * *
1581 ************************************************************************/
1582/**
1583 * xmlCreateRefTable:
1584 *
1585 * create and initialize an empty ref hash table.
1586 *
1587 * Returns the xmlRefTablePtr just created or NULL in case
1588 * of error.
1589 */
1590xmlRefTablePtr
1591xmlCreateRefTable(void) {
1592 xmlRefTablePtr ret;
1593
1594 ret = (xmlRefTablePtr)
1595 xmlMalloc(sizeof(xmlRefTable));
1596 if (ret == NULL) {
1597 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1598 (long)sizeof(xmlRefTable));
1599 return(NULL);
1600 }
1601 ret->max_refs = XML_MIN_NOTATION_TABLE;
1602 ret->nb_refs = 0;
1603 ret->table = (xmlRefPtr *)
1604 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1605 if (ret == NULL) {
1606 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1607 ret->max_refs * (long)sizeof(xmlRef));
1608 xmlFree(ret);
1609 return(NULL);
1610 }
1611 return(ret);
1612}
1613
1614
1615/**
1616 * xmlAddRef:
1617 * @ctxt: the validation context
1618 * @doc: pointer to the document
1619 * @value: the value name
1620 * @attr: the attribute holding the Ref
1621 *
1622 * Register a new ref declaration
1623 *
1624 * Returns NULL if not, othervise the new xmlRefPtr
1625 */
1626xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001627xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001628 xmlAttrPtr attr) {
1629 xmlRefPtr ret;
1630 xmlRefTablePtr table;
1631
1632 if (doc == NULL) {
1633 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1634 return(NULL);
1635 }
1636 if (value == NULL) {
1637 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1638 return(NULL);
1639 }
1640 if (attr == NULL) {
1641 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1642 return(NULL);
1643 }
1644
1645 /*
1646 * Create the Ref table if needed.
1647 */
1648 table = doc->refs;
1649 if (table == NULL)
1650 table = doc->refs = xmlCreateRefTable();
1651 if (table == NULL) {
1652 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1653 return(NULL);
1654 }
1655
1656 /*
1657 * Grow the table, if needed.
1658 */
1659 if (table->nb_refs >= table->max_refs) {
1660 /*
1661 * need more refs.
1662 */
1663 table->max_refs *= 2;
1664 table->table = (xmlRefPtr *)
1665 xmlRealloc(table->table, table->max_refs *
1666 sizeof(xmlRefPtr));
1667 if (table->table == NULL) {
1668 fprintf(stderr, "xmlAddRef: out of memory\n");
1669 return(NULL);
1670 }
1671 }
1672 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1673 if (ret == NULL) {
1674 fprintf(stderr, "xmlAddRef: out of memory\n");
1675 return(NULL);
1676 }
1677 table->table[table->nb_refs] = ret;
1678
1679 /*
1680 * fill the structure.
1681 */
1682 ret->value = xmlStrdup(value);
1683 ret->attr = attr;
1684 table->nb_refs++;
1685
1686 return(ret);
1687}
1688
1689/**
1690 * xmlFreeRef:
1691 * @not: A ref
1692 *
1693 * Deallocate the memory used by an ref definition
1694 */
1695void
1696xmlFreeRef(xmlRefPtr ref) {
1697 if (ref == NULL) return;
1698 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001699 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001700 memset(ref, -1, sizeof(xmlRef));
1701 xmlFree(ref);
1702}
1703
1704/**
1705 * xmlFreeRefTable:
1706 * @table: An ref table
1707 *
1708 * Deallocate the memory used by an Ref hash table.
1709 */
1710void
1711xmlFreeRefTable(xmlRefTablePtr table) {
1712 int i;
1713
1714 if (table == NULL) return;
1715
1716 for (i = 0;i < table->nb_refs;i++) {
1717 xmlFreeRef(table->table[i]);
1718 }
1719 xmlFree(table->table);
1720 xmlFree(table);
1721}
1722
1723/**
1724 * xmlIsRef
1725 * @doc: the document
1726 * @elem: the element carrying the attribute
1727 * @attr: the attribute
1728 *
1729 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1730 * then this is simple, otherwise we use an heuristic: name Ref (upper
1731 * or lowercase).
1732 *
1733 * Returns 0 or 1 depending on the lookup result
1734 */
1735int
1736xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1737 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1738 return(0);
1739 /*******************
1740 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1741 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1742 (attr->name[2] == 0)) return(1);
1743 *******************/
1744 } else {
1745 xmlAttributePtr attrDecl;
1746
1747 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1748 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1749 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1750 attr->name);
1751
1752 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1753 return(1);
1754 }
1755 return(0);
1756}
1757
1758/**
1759 * xmlGetRef:
1760 * @doc: pointer to the document
1761 * @Ref: the Ref value
1762 *
1763 * Search the attribute declaring the given Ref
1764 *
1765 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1766 */
1767xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001768xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001769 xmlRefPtr cur;
1770 xmlRefTablePtr table;
1771 int i;
1772
1773 if (doc == NULL) {
1774 fprintf(stderr, "xmlGetRef: doc == NULL\n");
1775 return(NULL);
1776 }
1777
1778 if (Ref == NULL) {
1779 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1780 return(NULL);
1781 }
1782
1783 table = doc->refs;
1784 if (table == NULL)
1785 return(NULL);
1786
1787 /*
1788 * Search the Ref list.
1789 */
1790 for (i = 0;i < table->nb_refs;i++) {
1791 cur = table->table[i];
1792 if (!xmlStrcmp(cur->value, Ref)) {
1793 return(cur->attr);
1794 }
1795 }
1796 return(NULL);
1797}
1798
1799/************************************************************************
1800 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001801 * Routines for validity checking *
1802 * *
1803 ************************************************************************/
1804
1805/**
1806 * xmlGetDtdElementDesc:
1807 * @dtd: a pointer to the DtD to search
1808 * @name: the element name
1809 *
1810 * Search the Dtd for the description of this element
1811 *
1812 * returns the xmlElementPtr if found or NULL
1813 */
1814
1815xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001816xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001817 xmlElementTablePtr table;
1818 xmlElementPtr cur;
1819 int i;
1820
1821 if (dtd == NULL) return(NULL);
1822 if (dtd->elements == NULL) return(NULL);
1823 table = dtd->elements;
1824
1825 for (i = 0;i < table->nb_elements;i++) {
1826 cur = table->table[i];
1827 if (!xmlStrcmp(cur->name, name))
1828 return(cur);
1829 }
1830 return(NULL);
1831}
1832
1833/**
1834 * xmlGetDtdAttrDesc:
1835 * @dtd: a pointer to the DtD to search
1836 * @elem: the element name
1837 * @name: the attribute name
1838 *
1839 * Search the Dtd for the description of this attribute on
1840 * this element.
1841 *
1842 * returns the xmlAttributePtr if found or NULL
1843 */
1844
1845xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001846xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001847 xmlAttributeTablePtr table;
1848 xmlAttributePtr cur;
1849 int i;
1850
1851 if (dtd == NULL) return(NULL);
1852 if (dtd->attributes == NULL) return(NULL);
1853 table = dtd->attributes;
1854
1855 for (i = 0;i < table->nb_attributes;i++) {
1856 cur = table->table[i];
1857 if ((!xmlStrcmp(cur->name, name)) &&
1858 (!xmlStrcmp(cur->elem, elem)))
1859 return(cur);
1860 }
1861 return(NULL);
1862}
1863
1864/**
1865 * xmlGetDtdNotationDesc:
1866 * @dtd: a pointer to the DtD to search
1867 * @name: the notation name
1868 *
1869 * Search the Dtd for the description of this notation
1870 *
1871 * returns the xmlNotationPtr if found or NULL
1872 */
1873
1874xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001875xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001876 xmlNotationTablePtr table;
1877 xmlNotationPtr cur;
1878 int i;
1879
1880 if (dtd == NULL) return(NULL);
1881 if (dtd->notations == NULL) return(NULL);
1882 table = dtd->notations;
1883
1884 for (i = 0;i < table->nb_notations;i++) {
1885 cur = table->table[i];
1886 if (!xmlStrcmp(cur->name, name))
1887 return(cur);
1888 }
1889 return(NULL);
1890}
1891
1892/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001893 * xmlValidateNotationUse:
1894 * @ctxt: the validation context
1895 * @doc: the document
1896 * @notationName: the notation name to check
1897 *
1898 * Validate that the given mame match a notation declaration.
1899 * - [ VC: Notation Declared ]
1900 *
1901 * returns 1 if valid or 0 otherwise
1902 */
1903
1904int
1905xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001906 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001907 xmlNotationPtr notaDecl;
1908 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1909
1910 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1911 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1912 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1913
1914 if (notaDecl == NULL) {
1915 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1916 notationName);
1917 return(0);
1918 }
1919 return(1);
1920}
1921
1922/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001923 * xmlIsMixedElement
1924 * @doc: the document
1925 * @name: the element name
1926 *
1927 * Search in the DtDs whether an element accept Mixed content (or ANY)
1928 * basically if it is supposed to accept text childs
1929 *
1930 * returns 0 if no, 1 if yes, and -1 if no element description is available
1931 */
1932
1933int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001934xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001935 xmlElementPtr elemDecl;
1936
1937 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1938
1939 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1940 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1941 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1942 if (elemDecl == NULL) return(-1);
1943 switch (elemDecl->type) {
1944 case XML_ELEMENT_TYPE_ELEMENT:
1945 return(0);
1946 case XML_ELEMENT_TYPE_EMPTY:
1947 /*
1948 * return 1 for EMPTY since we want VC error to pop up
1949 * on <empty> </empty> for example
1950 */
1951 case XML_ELEMENT_TYPE_ANY:
1952 case XML_ELEMENT_TYPE_MIXED:
1953 return(1);
1954 }
1955 return(1);
1956}
1957
1958/**
1959 * xmlValidateNameValue:
1960 * @value: an Name value
1961 *
1962 * Validate that the given value match Name production
1963 *
1964 * returns 1 if valid or 0 otherwise
1965 */
1966
1967int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001968xmlValidateNameValue(const xmlChar *value) {
1969 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001970
1971 if (value == NULL) return(0);
1972 cur = value;
1973
1974 if (!IS_LETTER(*cur) && (*cur != '_') &&
1975 (*cur != ':')) {
1976 return(0);
1977 }
1978
1979 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1980 (*cur == '.') || (*cur == '-') ||
1981 (*cur == '_') || (*cur == ':') ||
1982 (IS_COMBINING(*cur)) ||
1983 (IS_EXTENDER(*cur)))
1984 cur++;
1985
1986 if (*cur != 0) return(0);
1987
1988 return(1);
1989}
1990
1991/**
1992 * xmlValidateNamesValue:
1993 * @value: an Names value
1994 *
1995 * Validate that the given value match Names production
1996 *
1997 * returns 1 if valid or 0 otherwise
1998 */
1999
2000int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002001xmlValidateNamesValue(const xmlChar *value) {
2002 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002003
2004 if (value == NULL) return(0);
2005 cur = value;
2006
2007 if (!IS_LETTER(*cur) && (*cur != '_') &&
2008 (*cur != ':')) {
2009 return(0);
2010 }
2011
2012 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2013 (*cur == '.') || (*cur == '-') ||
2014 (*cur == '_') || (*cur == ':') ||
2015 (IS_COMBINING(*cur)) ||
2016 (IS_EXTENDER(*cur)))
2017 cur++;
2018
2019 while (IS_BLANK(*cur)) {
2020 while (IS_BLANK(*cur)) cur++;
2021
2022 if (!IS_LETTER(*cur) && (*cur != '_') &&
2023 (*cur != ':')) {
2024 return(0);
2025 }
2026
2027 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2028 (*cur == '.') || (*cur == '-') ||
2029 (*cur == '_') || (*cur == ':') ||
2030 (IS_COMBINING(*cur)) ||
2031 (IS_EXTENDER(*cur)))
2032 cur++;
2033 }
2034
2035 if (*cur != 0) return(0);
2036
2037 return(1);
2038}
2039
2040/**
2041 * xmlValidateNmtokenValue:
2042 * @value: an Mntoken value
2043 *
2044 * Validate that the given value match Nmtoken production
2045 *
2046 * [ VC: Name Token ]
2047 *
2048 * returns 1 if valid or 0 otherwise
2049 */
2050
2051int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002052xmlValidateNmtokenValue(const xmlChar *value) {
2053 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002054
2055 if (value == NULL) return(0);
2056 cur = value;
2057
2058 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2059 (*cur != '.') && (*cur != '-') &&
2060 (*cur != '_') && (*cur != ':') &&
2061 (!IS_COMBINING(*cur)) &&
2062 (!IS_EXTENDER(*cur)))
2063 return(0);
2064
2065 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2066 (*cur == '.') || (*cur == '-') ||
2067 (*cur == '_') || (*cur == ':') ||
2068 (IS_COMBINING(*cur)) ||
2069 (IS_EXTENDER(*cur)))
2070 cur++;
2071
2072 if (*cur != 0) return(0);
2073
2074 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002075}
2076
2077/**
2078 * xmlValidateNmtokensValue:
2079 * @value: an Mntokens value
2080 *
2081 * Validate that the given value match Nmtokens production
2082 *
2083 * [ VC: Name Token ]
2084 *
2085 * returns 1 if valid or 0 otherwise
2086 */
2087
2088int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002089xmlValidateNmtokensValue(const xmlChar *value) {
2090 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002091
2092 if (value == NULL) return(0);
2093 cur = value;
2094
2095 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2096 (*cur != '.') && (*cur != '-') &&
2097 (*cur != '_') && (*cur != ':') &&
2098 (!IS_COMBINING(*cur)) &&
2099 (!IS_EXTENDER(*cur)))
2100 return(0);
2101
2102 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2103 (*cur == '.') || (*cur == '-') ||
2104 (*cur == '_') || (*cur == ':') ||
2105 (IS_COMBINING(*cur)) ||
2106 (IS_EXTENDER(*cur)))
2107 cur++;
2108
2109 while (IS_BLANK(*cur)) {
2110 while (IS_BLANK(*cur)) cur++;
2111
2112 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2113 (*cur != '.') && (*cur != '-') &&
2114 (*cur != '_') && (*cur != ':') &&
2115 (!IS_COMBINING(*cur)) &&
2116 (!IS_EXTENDER(*cur)))
2117 return(0);
2118
2119 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2120 (*cur == '.') || (*cur == '-') ||
2121 (*cur == '_') || (*cur == ':') ||
2122 (IS_COMBINING(*cur)) ||
2123 (IS_EXTENDER(*cur)))
2124 cur++;
2125 }
2126
2127 if (*cur != 0) return(0);
2128
2129 return(1);
2130}
2131
2132/**
2133 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002134 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002135 * @doc: a document instance
2136 * @nota: a notation definition
2137 *
2138 * Try to validate a single notation definition
2139 * basically it does the following checks as described by the
2140 * XML-1.0 recommendation:
2141 * - it seems that no validity constraing exist on notation declarations
2142 * But this function get called anyway ...
2143 *
2144 * returns 1 if valid or 0 otherwise
2145 */
2146
2147int
2148xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2149 xmlNotationPtr nota) {
2150 int ret = 1;
2151
2152 return(ret);
2153}
2154
2155/**
2156 * xmlValidateAttributeValue:
2157 * @type: an attribute type
2158 * @value: an attribute value
2159 *
2160 * Validate that the given attribute value match the proper production
2161 *
2162 * [ VC: ID ]
2163 * Values of type ID must match the Name production....
2164 *
2165 * [ VC: IDREF ]
2166 * Values of type IDREF must match the Name production, and values
2167 * of type IDREFS must match Names ...
2168 *
2169 * [ VC: Entity Name ]
2170 * Values of type ENTITY must match the Name production, values
2171 * of type ENTITIES must match Names ...
2172 *
2173 * [ VC: Name Token ]
2174 * Values of type NMTOKEN must match the Nmtoken production; values
2175 * of type NMTOKENS must match Nmtokens.
2176 *
2177 * returns 1 if valid or 0 otherwise
2178 */
2179
2180int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002181xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002182 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002183 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002184 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002185 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002186 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002187 case XML_ATTRIBUTE_IDREF:
2188 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002189 case XML_ATTRIBUTE_NOTATION:
2190 return(xmlValidateNameValue(value));
2191 case XML_ATTRIBUTE_NMTOKENS:
2192 case XML_ATTRIBUTE_ENUMERATION:
2193 return(xmlValidateNmtokensValue(value));
2194 case XML_ATTRIBUTE_NMTOKEN:
2195 return(xmlValidateNmtokenValue(value));
2196 case XML_ATTRIBUTE_CDATA:
2197 break;
2198 }
2199 return(1);
2200}
2201
2202/**
2203 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002204 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002205 * @doc: a document instance
2206 * @attr: an attribute definition
2207 *
2208 * Try to validate a single attribute definition
2209 * basically it does the following checks as described by the
2210 * XML-1.0 recommendation:
2211 * - [ VC: Attribute Default Legal ]
2212 * - [ VC: Enumeration ]
2213 * - [ VC: ID Attribute Default ]
2214 *
2215 * The ID/IDREF uniqueness and matching are done separately
2216 *
2217 * returns 1 if valid or 0 otherwise
2218 */
2219
2220int
2221xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2222 xmlAttributePtr attr) {
2223 int ret = 1;
2224 int val;
2225 CHECK_DTD;
2226 if(attr == NULL) return(1);
2227
2228 /* Attribute Default Legal */
2229 /* Enumeration */
2230 if (attr->defaultValue != NULL) {
2231 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2232 if (val == 0) {
2233 VERROR(ctxt->userData,
2234 "Syntax of default value for attribute %s on %s is not valid\n",
2235 attr->name, attr->elem);
2236 }
2237 ret &= val;
2238 }
2239
2240 /* ID Attribute Default */
2241 if ((attr->type == XML_ATTRIBUTE_ID)&&
2242 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2243 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2244 VERROR(ctxt->userData,
2245 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2246 attr->name, attr->elem);
2247 ret = 0;
2248 }
2249
Daniel Veillardb96e6431999-08-29 21:02:19 +00002250 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002251 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2252 int nbId = 0;
2253
2254 /* the trick is taht we parse DtD as their own internal subset */
2255 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2256 attr->elem);
2257 if (elem != NULL) {
2258 nbId = xmlScanIDAttributeDecl(NULL, elem);
2259 }
2260 if (nbId >= 1)
2261 VERROR(ctxt->userData,
2262 "Element %s has ID attribute defined in the external subset : %s\n",
2263 attr->elem, attr->name);
2264 }
2265
2266 return(ret);
2267}
2268
2269/**
2270 * xmlValidateElementDecl:
2271 * @ctxt: the validation context
2272 * @doc: a document instance
2273 * @elem: an element definition
2274 *
2275 * Try to validate a single element definition
2276 * basically it does the following checks as described by the
2277 * XML-1.0 recommendation:
2278 * - [ VC: One ID per Element Type ]
2279 * - [ VC: No Duplicate Types ]
2280 * - [ VC: Unique Element Type Declaration ]
2281 *
2282 * returns 1 if valid or 0 otherwise
2283 */
2284
2285int
2286xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2287 xmlElementPtr elem) {
2288 int ret = 1;
2289 xmlElementPtr tst;
2290
2291 CHECK_DTD;
2292
2293 if (elem == NULL) return(1);
2294
2295 /* No Duplicate Types */
2296 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2297 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002298 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002299
2300 cur = elem->content;
2301 while (cur != NULL) {
2302 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2303 if (cur->c1 == NULL) break;
2304 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2305 name = cur->c1->name;
2306 next = cur->c2;
2307 while (next != NULL) {
2308 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2309 if (!xmlStrcmp(next->name, name)) {
2310 VERROR(ctxt->userData,
2311 "Definition of %s has duplicate references of %s\n",
2312 elem->name, name);
2313 ret = 0;
2314 }
2315 break;
2316 }
2317 if (next->c1 == NULL) break;
2318 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2319 if (!xmlStrcmp(next->c1->name, name)) {
2320 VERROR(ctxt->userData,
2321 "Definition of %s has duplicate references of %s\n",
2322 elem->name, name);
2323 ret = 0;
2324 }
2325 next = next->c2;
2326 }
2327 }
2328 cur = cur->c2;
2329 }
2330 }
2331
2332 /* VC: Unique Element Type Declaration */
2333 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2334 if ((tst != NULL ) && (tst != elem)) {
2335 VERROR(ctxt->userData, "Redefinition of element %s\n",
2336 elem->name);
2337 ret = 0;
2338 }
2339 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2340 if ((tst != NULL ) && (tst != elem)) {
2341 VERROR(ctxt->userData, "Redefinition of element %s\n",
2342 elem->name);
2343 ret = 0;
2344 }
2345
2346 /* One ID per Element Type */
2347 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2348 ret = 0;
2349 }
2350 return(ret);
2351}
2352
2353/**
2354 * xmlValidateOneAttribute:
2355 * @ctxt: the validation context
2356 * @doc: a document instance
2357 * @elem: an element instance
2358 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00002359 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002360 *
2361 * Try to validate a single attribute for an element
2362 * basically it * does the following checks as described by the
2363 * XML-1.0 recommendation:
2364 * - [ VC: Attribute Value Type ]
2365 * - [ VC: Fixed Attribute Default ]
2366 * - [ VC: Entity Name ]
2367 * - [ VC: Name Token ]
2368 * - [ VC: ID ]
2369 * - [ VC: IDREF ]
2370 * - [ VC: Entity Name ]
2371 * - [ VC: Notation Attributes ]
2372 *
2373 * The ID/IDREF uniqueness and matching are done separately
2374 *
2375 * returns 1 if valid or 0 otherwise
2376 */
2377
2378int
2379xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002380 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002381 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002382 xmlAttributePtr attrDecl;
2383 int val;
2384 int ret = 1;
2385
2386 CHECK_DTD;
2387 if ((elem == NULL) || (elem->name == NULL)) return(0);
2388 if ((attr == NULL) || (attr->name == NULL)) return(0);
2389
2390 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2391 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2392 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2393
2394
2395 /* Validity Constraint: Attribute Value Type */
2396 if (attrDecl == NULL) {
2397 VERROR(ctxt->userData,
2398 "No declaration for attribute %s on element %s\n",
2399 attr->name, elem->name);
2400 return(0);
2401 }
2402 val = xmlValidateAttributeValue(attrDecl->type, value);
2403 if (val == 0) {
2404 VERROR(ctxt->userData,
2405 "Syntax of value for attribute %s on %s is not valid\n",
2406 attr->name, elem->name);
2407 ret = 0;
2408 }
2409
Daniel Veillardb96e6431999-08-29 21:02:19 +00002410 /* Validity Constraint: ID uniqueness */
2411 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2412 xmlAddID(ctxt, doc, value, attr);
2413 }
2414
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002415 if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2416 xmlAddRef(ctxt, doc, value, attr);
2417 }
2418
Daniel Veillardb05deb71999-08-10 19:04:08 +00002419 /* Validity Constraint: Notation Attributes */
2420 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2421 xmlEnumerationPtr tree = attrDecl->tree;
2422 xmlNotationPtr nota;
2423
2424 /* First check that the given NOTATION was declared */
2425 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2426 if (nota == NULL)
2427 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2428
2429 if (nota == NULL) {
2430 VERROR(ctxt->userData,
2431 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2432 value, attr->name, elem->name);
2433 ret = 0;
2434 }
2435
2436 /* Second, verify that it's among the list */
2437 while (tree != NULL) {
2438 if (!xmlStrcmp(tree->name, value)) break;
2439 tree = tree->next;
2440 }
2441 if (tree == NULL) {
2442 VERROR(ctxt->userData,
2443 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2444 value, attr->name, elem->name);
2445 ret = 0;
2446 }
2447 }
2448
2449 /* Validity Constraint: Enumeration */
2450 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2451 xmlEnumerationPtr tree = attrDecl->tree;
2452 while (tree != NULL) {
2453 if (!xmlStrcmp(tree->name, value)) break;
2454 tree = tree->next;
2455 }
2456 if (tree == NULL) {
2457 VERROR(ctxt->userData,
2458 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2459 value, attr->name, elem->name);
2460 ret = 0;
2461 }
2462 }
2463
2464 /* Fixed Attribute Default */
2465 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2466 (xmlStrcmp(attrDecl->defaultValue, value))) {
2467 VERROR(ctxt->userData,
2468 "Value for attribute %s on %s must be \"%s\"\n",
2469 attr->name, elem->name, attrDecl->defaultValue);
2470 ret = 0;
2471 }
2472
Daniel Veillardb96e6431999-08-29 21:02:19 +00002473 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002474 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2475 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2476 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2477 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002478 return(0);
2479 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002480 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002481 return(ret);
2482}
2483
2484int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2485 xmlElementContentPtr cont);
2486
2487/**
2488 * xmlValidateElementTypeExpr:
2489 * @ctxt: the validation context
2490 * @child: pointer to the child list
2491 * @cont: pointer to the content declaration
2492 *
2493 * Try to validate the content of an element of type element
2494 * but don't handle the occurence factor
2495 *
2496 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2497 * also update child value in-situ.
2498 */
2499
2500int
2501xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2502 xmlElementContentPtr cont) {
2503 xmlNodePtr cur;
2504 int ret = 1;
2505
2506 if (cont == NULL) return(-1);
2507 while (*child != NULL) {
2508 if ((*child)->type == XML_PI_NODE) {
2509 *child = (*child)->next;
2510 continue;
2511 }
2512 if ((*child)->type == XML_COMMENT_NODE) {
2513 *child = (*child)->next;
2514 continue;
2515 }
2516 else if ((*child)->type != XML_ELEMENT_NODE) {
2517 return(-1);
2518 }
2519 break;
2520 }
2521 switch (cont->type) {
2522 case XML_ELEMENT_CONTENT_PCDATA:
2523 /* Internal error !!! */
2524 fprintf(stderr, "Internal: MIXED struct bad\n");
2525 return(-1);
2526 case XML_ELEMENT_CONTENT_ELEMENT:
2527 if (*child == NULL) return(0);
2528 ret = (!xmlStrcmp((*child)->name, cont->name));
2529 if (ret == 1)
2530 *child = (*child)->next;
2531 return(ret);
2532 case XML_ELEMENT_CONTENT_OR:
2533 cur = *child;
2534 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2535 if (ret == -1) return(-1);
2536 if (ret == 1) {
2537 return(1);
2538 }
2539 /* rollback and retry the other path */
2540 *child = cur;
2541 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2542 if (ret == -1) return(-1);
2543 if (ret == 0) {
2544 *child = cur;
2545 return(0);
2546 }
2547 return(1);
2548 case XML_ELEMENT_CONTENT_SEQ:
2549 cur = *child;
2550 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2551 if (ret == -1) return(-1);
2552 if (ret == 0) {
2553 *child = cur;
2554 return(0);
2555 }
2556 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2557 if (ret == -1) return(-1);
2558 if (ret == 0) {
2559 *child = cur;
2560 return(0);
2561 }
2562 return(1);
2563 }
2564 return(ret);
2565}
2566
2567/**
2568 * xmlValidateElementTypeElement:
2569 * @ctxt: the validation context
2570 * @child: pointer to the child list
2571 * @cont: pointer to the content declaration
2572 *
2573 * Try to validate the content of an element of type element
2574 * yeah, Yet Another Regexp Implementation, and recursive
2575 *
2576 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2577 * also update child and content values in-situ.
2578 */
2579
2580int
2581xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2582 xmlElementContentPtr cont) {
2583 xmlNodePtr cur;
2584 int ret = 1;
2585
2586 if (cont == NULL) return(-1);
2587 while (*child != NULL) {
2588 if ((*child)->type == XML_PI_NODE) {
2589 *child = (*child)->next;
2590 continue;
2591 }
2592 if ((*child)->type == XML_COMMENT_NODE) {
2593 *child = (*child)->next;
2594 continue;
2595 }
2596 else if ((*child)->type != XML_ELEMENT_NODE) {
2597 return(-1);
2598 }
2599 break;
2600 }
2601 cur = *child;
2602 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2603 if (ret == -1) return(-1);
2604 switch (cont->ocur) {
2605 case XML_ELEMENT_CONTENT_ONCE:
2606 if (ret == 1) {
2607 return(1);
2608 }
2609 *child = cur;
2610 return(0);
2611 case XML_ELEMENT_CONTENT_OPT:
2612 if (ret == 0) {
2613 *child = cur;
2614 return(1);
2615 }
2616 break;
2617 case XML_ELEMENT_CONTENT_MULT:
2618 if (ret == 0) {
2619 *child = cur;
2620 break;
2621 }
2622 /* no break on purpose */
2623 case XML_ELEMENT_CONTENT_PLUS:
2624 if (ret == 0) {
2625 *child = cur;
2626 return(0);
2627 }
2628 do {
2629 cur = *child;
2630 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2631 } while (ret == 1);
2632 if (ret == -1) return(-1);
2633 *child = cur;
2634 break;
2635 }
2636 while (*child != NULL) {
2637 if ((*child)->type == XML_PI_NODE) {
2638 *child = (*child)->next;
2639 continue;
2640 }
2641 if ((*child)->type == XML_COMMENT_NODE) {
2642 *child = (*child)->next;
2643 continue;
2644 }
2645 else if ((*child)->type != XML_ELEMENT_NODE) {
2646 return(-1);
2647 }
2648 break;
2649 }
2650 return(1);
2651}
2652
2653/**
2654 * xmlSprintfElementChilds:
2655 * @buf: an output buffer
2656 * @content: An element
2657 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2658 *
2659 * This will dump the list of childs to the buffer
2660 * Intended just for the debug routine
2661 */
2662void
2663xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2664 xmlNodePtr cur;
2665
2666 if (node == NULL) return;
2667 if (glob) strcat(buf, "(");
2668 cur = node->childs;
2669 while (cur != NULL) {
2670 switch (cur->type) {
2671 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002672 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002673 if (cur->next != NULL)
2674 strcat(buf, " ");
2675 break;
2676 case XML_TEXT_NODE:
2677 case XML_CDATA_SECTION_NODE:
2678 case XML_ENTITY_REF_NODE:
2679 strcat(buf, "CDATA");
2680 if (cur->next != NULL)
2681 strcat(buf, " ");
2682 break;
2683 case XML_ATTRIBUTE_NODE:
2684 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002685 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002686 case XML_DOCUMENT_TYPE_NODE:
2687 case XML_DOCUMENT_FRAG_NODE:
2688 case XML_NOTATION_NODE:
2689 strcat(buf, "???");
2690 if (cur->next != NULL)
2691 strcat(buf, " ");
2692 break;
2693 case XML_ENTITY_NODE:
2694 case XML_PI_NODE:
2695 case XML_COMMENT_NODE:
2696 break;
2697 }
2698 cur = cur->next;
2699 }
2700 if (glob) strcat(buf, ")");
2701}
2702
2703
2704/**
2705 * xmlValidateOneElement:
2706 * @ctxt: the validation context
2707 * @doc: a document instance
2708 * @elem: an element instance
2709 *
2710 * Try to validate a single element and it's attributes,
2711 * basically it does the following checks as described by the
2712 * XML-1.0 recommendation:
2713 * - [ VC: Element Valid ]
2714 * - [ VC: Required Attribute ]
2715 * Then call xmlValidateOneAttribute() for each attribute present.
2716 *
2717 * The ID/IDREF checkings are done separately
2718 *
2719 * returns 1 if valid or 0 otherwise
2720 */
2721
2722int
2723xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2724 xmlNodePtr elem) {
2725 xmlElementPtr elemDecl;
2726 xmlElementContentPtr cont;
2727 xmlNodePtr child;
2728 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002729 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002730
2731 CHECK_DTD;
2732
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002733 if (elem == NULL) return(0);
2734 if (elem->type == XML_TEXT_NODE) {
2735 }
2736 switch (elem->type) {
2737 case XML_ATTRIBUTE_NODE:
2738 VERROR(ctxt->userData,
2739 "Attribute element not expected here\n");
2740 return(0);
2741 case XML_TEXT_NODE:
2742 if (elem->childs != NULL) {
2743 VERROR(ctxt->userData, "Text element has childs !\n");
2744 return(0);
2745 }
2746 if (elem->properties != NULL) {
2747 VERROR(ctxt->userData, "Text element has attributes !\n");
2748 return(0);
2749 }
2750 if (elem->ns != NULL) {
2751 VERROR(ctxt->userData, "Text element has namespace !\n");
2752 return(0);
2753 }
2754 if (elem->ns != NULL) {
2755 VERROR(ctxt->userData,
2756 "Text element carries namespace definitions !\n");
2757 return(0);
2758 }
2759 if (elem->content == NULL) {
2760 VERROR(ctxt->userData,
2761 "Text element has no content !\n");
2762 return(0);
2763 }
2764 return(1);
2765 case XML_CDATA_SECTION_NODE:
2766 case XML_ENTITY_REF_NODE:
2767 case XML_PI_NODE:
2768 case XML_COMMENT_NODE:
2769 return(1);
2770 case XML_ENTITY_NODE:
2771 VERROR(ctxt->userData,
2772 "Entity element not expected here\n");
2773 return(0);
2774 case XML_NOTATION_NODE:
2775 VERROR(ctxt->userData,
2776 "Notation element not expected here\n");
2777 return(0);
2778 case XML_DOCUMENT_NODE:
2779 case XML_DOCUMENT_TYPE_NODE:
2780 case XML_DOCUMENT_FRAG_NODE:
2781 VERROR(ctxt->userData,
2782 "Document element not expected here\n");
2783 return(0);
2784 case XML_HTML_DOCUMENT_NODE:
2785 VERROR(ctxt->userData,
2786 "\n");
2787 return(0);
2788 case XML_ELEMENT_NODE:
2789 break;
2790 default:
2791 VERROR(ctxt->userData,
2792 "unknown element type %d\n", elem->type);
2793 return(0);
2794 }
2795 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002796
2797 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2798 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2799 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2800 if (elemDecl == NULL) {
2801 VERROR(ctxt->userData, "No declaration for element %s\n",
2802 elem->name);
2803 return(0);
2804 }
2805
2806 /* Check taht the element content matches the definition */
2807 switch (elemDecl->type) {
2808 case XML_ELEMENT_TYPE_EMPTY:
2809 if (elem->childs != NULL) {
2810 VERROR(ctxt->userData,
2811 "Element %s was declared EMPTY this one has content\n",
2812 elem->name);
2813 ret = 0;
2814 }
2815 break;
2816 case XML_ELEMENT_TYPE_ANY:
2817 /* I don't think anything is required then */
2818 break;
2819 case XML_ELEMENT_TYPE_MIXED:
2820 /* Hum, this start to get messy */
2821 child = elem->childs;
2822 while (child != NULL) {
2823 if (child->type == XML_ELEMENT_NODE) {
2824 name = child->name;
2825 cont = elemDecl->content;
2826 while (cont != NULL) {
2827 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2828 if (!xmlStrcmp(cont->name, name)) break;
2829 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2830 (cont->c1 != NULL) &&
2831 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2832 if (!xmlStrcmp(cont->c1->name, name)) break;
2833 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2834 (cont->c1 == NULL) ||
2835 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2836 /* Internal error !!! */
2837 fprintf(stderr, "Internal: MIXED struct bad\n");
2838 break;
2839 }
2840 cont = cont->c2;
2841 }
2842 if (cont == NULL) {
2843 VERROR(ctxt->userData,
2844 "Element %s is not declared in %s list of possible childs\n",
2845 name, elem->name);
2846 ret = 0;
2847 }
2848 }
2849 child = child->next;
2850 }
2851 break;
2852 case XML_ELEMENT_TYPE_ELEMENT:
2853 child = elem->childs;
2854 cont = elemDecl->content;
2855 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2856 if ((ret == 0) || (child != NULL)) {
2857 char expr[1000];
2858 char list[2000];
2859
2860 expr[0] = 0;
2861 xmlSprintfElementContent(expr, cont, 1);
2862 list[0] = 0;
2863 xmlSprintfElementChilds(list, elem, 1);
2864
2865 VERROR(ctxt->userData,
2866 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2867 elem->name, expr, list);
2868 ret = 0;
2869 }
2870 break;
2871 }
2872
Daniel Veillardb96e6431999-08-29 21:02:19 +00002873 /* TODO - [ VC: Required Attribute ] */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002874 return(ret);
2875}
2876
2877/**
2878 * xmlValidateRoot:
2879 * @ctxt: the validation context
2880 * @doc: a document instance
2881 *
2882 * Try to validate a the root element
2883 * basically it does the following check as described by the
2884 * XML-1.0 recommendation:
2885 * - [ VC: Root Element Type ]
2886 * it doesn't try to recurse or apply other check to the element
2887 *
2888 * returns 1 if valid or 0 otherwise
2889 */
2890
2891int
2892xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002893 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002894 if (doc == NULL) return(0);
2895
2896 if ((doc->intSubset == NULL) ||
2897 (doc->intSubset->name == NULL)) {
2898 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2899 return(0);
2900 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002901 root = xmlDocGetRootElement(doc);
2902 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002903 VERROR(ctxt->userData, "Not valid: no root element\n");
2904 return(0);
2905 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002906 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002907 VERROR(ctxt->userData,
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002908 "Not valid: root and DtD name do not match '%s' and '%s'\n",
2909 root->name, doc->intSubset->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002910 return(0);
2911 }
2912 return(1);
2913}
2914
2915
2916/**
2917 * xmlValidateElement:
2918 * @ctxt: the validation context
2919 * @doc: a document instance
2920 * @elem: an element instance
2921 *
2922 * Try to validate the subtree under an element
2923 *
2924 * returns 1 if valid or 0 otherwise
2925 */
2926
2927int
2928xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002929 xmlNodePtr child;
2930 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002931 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002932 int ret = 1;
2933
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002934 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002935 CHECK_DTD;
2936
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002937 ret &= xmlValidateOneElement(ctxt, doc, elem);
2938 attr = elem->properties;
2939 while(attr != NULL) {
2940 value = xmlNodeListGetString(doc, attr->val, 0);
2941 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
2942 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002943 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002944 attr= attr->next;
2945 }
2946 child = elem->childs;
2947 while (child != NULL) {
2948 ret &= xmlValidateElement(ctxt, doc, child);
2949 child = child->next;
2950 }
2951
2952 return(ret);
2953}
2954
2955/**
2956 * xmlValidateDocumentFinal:
2957 * @ctxt: the validation context
2958 * @doc: a document instance
2959 *
2960 * Does the final step for the document validation once all the
2961 * incremental validation steps have been completed
2962 *
2963 * basically it does the following checks described by the XML Rec
2964 *
2965 *
2966 * returns 1 if valid or 0 otherwise
2967 */
2968
2969int
2970xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2971 int ret = 1, i;
2972 xmlRefTablePtr table;
2973 xmlAttrPtr id;
2974
2975 if (doc == NULL) {
2976 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
2977 return(0);
2978 }
2979
2980 /*
2981 * Get the refs table
2982 */
2983 table = doc->refs;
2984 if (table != NULL) {
2985 for (i = 0; i < table->nb_refs; i++) {
2986 id = xmlGetID(doc, table->table[i]->value);
2987 if (id == NULL) {
2988 VERROR(ctxt->userData,
2989 "IDREF attribute %s reference an unknown ID '%s'\n",
2990 table->table[i]->attr->name, table->table[i]->value);
2991 ret = 0;
2992 }
2993 }
2994 }
2995 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002996}
2997
2998/**
2999 * xmlValidateDtd:
3000 * @ctxt: the validation context
3001 * @doc: a document instance
3002 * @dtd: a dtd instance
3003 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003004 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003005 *
3006 * basically it does check all the definitions in the DtD.
3007 *
3008 * returns 1 if valid or 0 otherwise
3009 */
3010
3011int
3012xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003013 int ret;
3014 xmlDtdPtr oldExt;
3015 xmlNodePtr root;
3016
3017 if (dtd == NULL) return(0);
3018 if (doc == NULL) return(0);
3019 oldExt = doc->extSubset;
3020 doc->extSubset = dtd;
3021 ret = xmlValidateRoot(ctxt, doc);
3022 if (ret == 0) {
3023 doc->extSubset = oldExt;
3024 return(ret);
3025 }
3026 root = xmlDocGetRootElement(doc);
3027 ret = xmlValidateElement(ctxt, doc, root);
3028 ret &= xmlValidateDocumentFinal(ctxt, doc);
3029 doc->extSubset = oldExt;
3030 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003031}
3032
3033/**
3034 * xmlValidateDocument:
3035 * @ctxt: the validation context
3036 * @doc: a document instance
3037 *
3038 * Try to validate the document instance
3039 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003040 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00003041 * i.e. validates the internal and external subset (if present)
3042 * and validate the document tree.
3043 *
3044 * returns 1 if valid or 0 otherwise
3045 */
3046
3047int
3048xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003049 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003050 xmlNodePtr root;
3051
3052 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3053 return(0);
3054 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
3055 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
3056 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
3057 doc->intSubset->SystemID);
3058 if (doc->extSubset == NULL) {
3059 if (doc->intSubset->SystemID != NULL) {
3060 VERROR(ctxt->userData,
3061 "Could not load the external subset '%s'\n",
3062 doc->intSubset->SystemID);
3063 } else {
3064 VERROR(ctxt->userData,
3065 "Could not load the external subset '%s'\n",
3066 doc->intSubset->ExternalID);
3067 }
3068 return(0);
3069 }
3070 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003071
Daniel Veillardb05deb71999-08-10 19:04:08 +00003072 if (!xmlValidateRoot(ctxt, doc)) return(0);
3073
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003074 root = xmlDocGetRootElement(doc);
3075 ret = xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003076 ret &= xmlValidateDocumentFinal(ctxt, doc);
3077 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003078}
3079
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003080
3081/************************************************************************
3082 * *
3083 * Routines for dynamic validation editing *
3084 * *
3085 ************************************************************************/
3086
3087/**
3088 * xmlValidGetPotentialChildren:
3089 * @ctree: an element content tree
3090 * @list: an array to store the list of child names
3091 * @len: a pointer to the number of element in the list
3092 * @max: the size of the array
3093 *
3094 * Build/extend a list of potential children allowed by the content tree
3095 *
3096 * returns the number of element in the list, or -1 in case of error.
3097 */
3098
3099int
3100xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
3101 int *len, int max) {
3102 int i;
3103
3104 if ((ctree == NULL) || (list == NULL) || (len == NULL))
3105 return(-1);
3106 if (*len >= max) return(*len);
3107
3108 switch (ctree->type) {
3109 case XML_ELEMENT_CONTENT_PCDATA:
3110 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00003111 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
3112 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003113 break;
3114 case XML_ELEMENT_CONTENT_ELEMENT:
3115 for (i = 0; i < *len;i++)
3116 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
3117 list[(*len)++] = ctree->name;
3118 break;
3119 case XML_ELEMENT_CONTENT_SEQ:
3120 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3121 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3122 break;
3123 case XML_ELEMENT_CONTENT_OR:
3124 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3125 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3126 break;
3127 }
3128
3129 return(*len);
3130}
3131
3132/**
3133 * xmlValidGetValidElements:
3134 * @prev: an element to insert after
3135 * @next: an element to insert next
3136 * @list: an array to store the list of child names
3137 * @max: the size of the array
3138 *
3139 * This function returns the list of authorized children to insert
3140 * within an existing tree while respecting the validity constraints
3141 * forced by the Dtd. The insertion point is defined using @prev and
3142 * @next in the following ways:
3143 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3144 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3145 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3146 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3147 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
3148 *
3149 * pointers to the element names are inserted at the beginning of the array
3150 * and do not need to be freed.
3151 *
3152 * returns the number of element in the list, or -1 in case of error. If
3153 * the function returns the value @max the caller is invited to grow the
3154 * receiving array and retry.
3155 */
3156
3157int
3158xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3159 int max) {
3160 int nb_valid_elements = 0;
3161 const xmlChar *elements[256];
3162 int nb_elements = 0, i;
3163
3164 xmlNode *ref_node;
3165 xmlNode *parent;
3166 xmlNode *test_node;
3167
3168 xmlNode *prev_next;
3169 xmlNode *next_prev;
3170 xmlNode *parent_childs;
3171 xmlNode *parent_last;
3172
3173 xmlElement *element_desc;
3174
3175 if (prev == NULL && next == NULL)
3176 return(-1);
3177
3178 if (list == NULL) return(-1);
3179 if (max <= 0) return(-1);
3180
3181 nb_valid_elements = 0;
3182 ref_node = prev ? prev : next;
3183 parent = ref_node->parent;
3184
3185 /*
3186 * Retrieves the parent element declaration
3187 */
3188 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3189 parent->name);
3190 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3191 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3192 parent->name);
3193 if (element_desc == NULL) return(-1);
3194
3195 /*
3196 * Do a backup of the current tree structure
3197 */
3198 prev_next = prev ? prev->next : NULL;
3199 next_prev = next ? next->prev : NULL;
3200 parent_childs = parent->childs;
3201 parent_last = parent->last;
3202
3203 /*
3204 * Creates a dummy node and insert it into the tree
3205 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003206 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003207 test_node->doc = ref_node->doc;
3208 test_node->parent = parent;
3209 test_node->prev = prev;
3210 test_node->next = next;
3211
3212 if (prev) prev->next = test_node;
3213 else parent->childs = test_node;
3214
3215 if (next) next->prev = test_node;
3216 else parent->last = test_node;
3217
3218 /*
3219 * Insert each potential child node and check if the parent is
3220 * still valid
3221 */
3222 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
3223 elements, &nb_elements, 256);
3224
3225 for (i = 0;i < nb_elements;i++) {
3226 test_node->name = elements[i];
3227 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
3228 int j;
3229
3230 for (j = 0; j < nb_valid_elements;j++)
3231 if (!xmlStrcmp(elements[i], list[j])) break;
3232 list[nb_valid_elements++] = elements[i];
3233 if (nb_valid_elements >= max) break;
3234 }
3235 }
3236
3237 /*
3238 * Restore the tree structure
3239 */
3240 if (prev) prev->next = prev_next;
3241 if (next) next->prev = next_prev;
3242 parent->childs = parent_childs;
3243 parent->last = parent_last;
3244
3245 return(nb_valid_elements);
3246}