blob: f592c182c98f9d78b73c9548c953c30144b4c6f8 [file] [log] [blame]
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001/*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel.Veillard@w3.org
8 */
9
Daniel Veillard7f7d1111999-09-22 09:46:25 +000010#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000011#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000012#else
13#include "config.h"
14#endif
15
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000016#include <stdio.h>
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000017#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018
19#ifdef HAVE_STDLIB_H
20#include <stdlib.h>
21#endif
22
Daniel Veillard6454aec1999-09-02 22:04:43 +000023#include "xmlmemory.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000024#include "valid.h"
25#include "parser.h"
Daniel Veillardb05deb71999-08-10 19:04:08 +000026#include "parserInternals.h"
27
Daniel Veillarddbfd6411999-12-28 16:35:14 +000028/* TODO: use hash table for accesses to elem and attribute dedinitions */
29
Daniel Veillardb05deb71999-08-10 19:04:08 +000030#define VERROR \
31 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
32
33#define VWARNING \
34 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
35
36#define CHECK_DTD \
37 if (doc == NULL) return(0); \
38 else if (doc->intSubset == NULL) return(0)
39
Daniel Veillarddd6b3671999-09-23 22:19:22 +000040xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
41xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000042
43/****************************************************************
44 * *
45 * Util functions for data allocation/deallocation *
46 * *
47 ****************************************************************/
48
49/**
50 * xmlNewElementContent:
51 * @name: the subelement name or NULL
52 * @type: the type of element content decl
53 *
54 * Allocate an element content structure.
55 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000056 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000057 */
58xmlElementContentPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +000059xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000060 xmlElementContentPtr ret;
61
62 switch(type) {
63 case XML_ELEMENT_CONTENT_ELEMENT:
64 if (name == NULL) {
65 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
66 }
67 break;
68 case XML_ELEMENT_CONTENT_PCDATA:
69 case XML_ELEMENT_CONTENT_SEQ:
70 case XML_ELEMENT_CONTENT_OR:
71 if (name != NULL) {
72 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
73 }
74 break;
75 default:
76 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
77 exit(1);
78 }
Daniel Veillard6454aec1999-09-02 22:04:43 +000079 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000080 if (ret == NULL) {
81 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
82 return(NULL);
83 }
84 ret->type = type;
85 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +000086 if (name != NULL)
87 ret->name = xmlStrdup(name);
88 else
89 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +000090 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000091 return(ret);
92}
93
94/**
Daniel Veillard3b9def11999-01-31 22:15:06 +000095 * xmlCopyElementContent:
96 * @content: An element content pointer.
97 *
98 * Build a copy of an element content description.
99 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000100 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000101 */
102xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000103xmlCopyElementContent(xmlElementContentPtr cur) {
104 xmlElementContentPtr ret;
105
106 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000107 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +0000108 if (ret == NULL) {
109 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
110 return(NULL);
111 }
112 ret->ocur = cur->ocur;
113 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
114 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000115 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000116}
117
118/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000119 * xmlFreeElementContent:
120 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000121 *
122 * Free an element content structure. This is a recursive call !
123 */
124void
125xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000126 if (cur == NULL) return;
127 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
128 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000129 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000130 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000131 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000132}
133
Daniel Veillard1899e851999-02-01 12:18:54 +0000134/**
135 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000136 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000137 * @content: An element table
138 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
139 *
140 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000141 */
142void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000143xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000144 if (content == NULL) return;
145
Daniel Veillard5099ae81999-04-21 20:12:07 +0000146 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000147 switch (content->type) {
148 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000149 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000150 break;
151 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000152 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000153 break;
154 case XML_ELEMENT_CONTENT_SEQ:
155 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
156 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000157 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000158 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000159 xmlDumpElementContent(buf, content->c1, 0);
160 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000161 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000162 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000163 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000164 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000165 break;
166 case XML_ELEMENT_CONTENT_OR:
167 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
168 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000169 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000170 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000171 xmlDumpElementContent(buf, content->c1, 0);
172 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000173 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000174 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000175 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000176 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000177 break;
178 default:
179 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
180 content->type);
181 }
182 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000183 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000184 switch (content->ocur) {
185 case XML_ELEMENT_CONTENT_ONCE:
186 break;
187 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000188 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000189 break;
190 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000191 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000192 break;
193 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000194 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000195 break;
196 }
197}
198
Daniel Veillardb05deb71999-08-10 19:04:08 +0000199/**
200 * xmlSprintfElementContent:
201 * @buf: an output buffer
202 * @content: An element table
203 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
204 *
205 * This will dump the content of the element content definition
206 * Intended just for the debug routine
207 */
208void
209xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
210 if (content == NULL) return;
211 if (glob) strcat(buf, "(");
212 switch (content->type) {
213 case XML_ELEMENT_CONTENT_PCDATA:
214 strcat(buf, "#PCDATA");
215 break;
216 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000217 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000218 break;
219 case XML_ELEMENT_CONTENT_SEQ:
220 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
221 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
222 xmlSprintfElementContent(buf, content->c1, 1);
223 else
224 xmlSprintfElementContent(buf, content->c1, 0);
225 strcat(buf, " , ");
226 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
227 xmlSprintfElementContent(buf, content->c2, 1);
228 else
229 xmlSprintfElementContent(buf, content->c2, 0);
230 break;
231 case XML_ELEMENT_CONTENT_OR:
232 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
233 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
234 xmlSprintfElementContent(buf, content->c1, 1);
235 else
236 xmlSprintfElementContent(buf, content->c1, 0);
237 strcat(buf, " | ");
238 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
239 xmlSprintfElementContent(buf, content->c2, 1);
240 else
241 xmlSprintfElementContent(buf, content->c2, 0);
242 break;
243 }
244 if (glob)
245 strcat(buf, ")");
246 switch (content->ocur) {
247 case XML_ELEMENT_CONTENT_ONCE:
248 break;
249 case XML_ELEMENT_CONTENT_OPT:
250 strcat(buf, "?");
251 break;
252 case XML_ELEMENT_CONTENT_MULT:
253 strcat(buf, "*");
254 break;
255 case XML_ELEMENT_CONTENT_PLUS:
256 strcat(buf, "+");
257 break;
258 }
259}
260
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000261/****************************************************************
262 * *
263 * Registration of DTD declarations *
264 * *
265 ****************************************************************/
266
Daniel Veillard3b9def11999-01-31 22:15:06 +0000267/**
268 * xmlCreateElementTable:
269 *
270 * create and initialize an empty element hash table.
271 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000272 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000273 */
274xmlElementTablePtr
275xmlCreateElementTable(void) {
276 xmlElementTablePtr ret;
277
278 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000279 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000280 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000281 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000282 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000283 return(NULL);
284 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000285 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000286 ret->nb_elements = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000287 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000288 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000289 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000290 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000291 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000292 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000293 return(NULL);
294 }
295 return(ret);
296}
297
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000298
299/**
300 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000301 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000302 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000303 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000304 * @type: the element type
305 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000306 *
307 * Register a new element declaration
308 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000309 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000310 */
311xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000312xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillard51e3b151999-11-12 17:02:31 +0000313 xmlElementTypeVal type, xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000314 xmlElementPtr ret, cur;
315 xmlElementTablePtr table;
316 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000317
318 if (dtd == NULL) {
319 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
320 return(NULL);
321 }
322 if (name == NULL) {
323 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
324 return(NULL);
325 }
326 switch (type) {
327 case XML_ELEMENT_TYPE_EMPTY:
328 if (content != NULL) {
329 fprintf(stderr,
330 "xmlAddElementDecl: content != NULL for EMPTY\n");
331 return(NULL);
332 }
333 break;
334 case XML_ELEMENT_TYPE_ANY:
335 if (content != NULL) {
336 fprintf(stderr,
337 "xmlAddElementDecl: content != NULL for ANY\n");
338 return(NULL);
339 }
340 break;
341 case XML_ELEMENT_TYPE_MIXED:
342 if (content == NULL) {
343 fprintf(stderr,
344 "xmlAddElementDecl: content == NULL for MIXED\n");
345 return(NULL);
346 }
347 break;
348 case XML_ELEMENT_TYPE_ELEMENT:
349 if (content == NULL) {
350 fprintf(stderr,
351 "xmlAddElementDecl: content == NULL for ELEMENT\n");
352 return(NULL);
353 }
354 break;
355 default:
356 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
357 return(NULL);
358 }
359
360 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000361 * Create the Element table if needed.
362 */
363 table = dtd->elements;
364 if (table == NULL)
365 table = dtd->elements = xmlCreateElementTable();
366 if (table == NULL) {
367 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
368 return(NULL);
369 }
370
371 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000372 * Validity Check:
373 * Search the DTD for previous declarations of the ELEMENT
374 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000375 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000376 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000377 if (!xmlStrcmp(cur->name, name)) {
378 /*
379 * The element is already defined in this Dtd.
380 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000381 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000382 return(NULL);
383 }
384 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000385
386 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000387 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000388 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000389 if (table->nb_elements >= table->max_elements) {
390 /*
391 * need more elements.
392 */
393 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000394 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000395 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000396 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000397 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
398 return(NULL);
399 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000400 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000401 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000402 if (ret == NULL) {
403 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
404 return(NULL);
405 }
406 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000407
408 /*
409 * fill the structure.
410 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000411 ret->type = type;
412 ret->name = xmlStrdup(name);
Daniel Veillard14fff061999-06-22 21:49:07 +0000413 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000414 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000415 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000416
417 return(ret);
418}
419
Daniel Veillard3b9def11999-01-31 22:15:06 +0000420/**
421 * xmlFreeElement:
422 * @elem: An element
423 *
424 * Deallocate the memory used by an element definition
425 */
426void
427xmlFreeElement(xmlElementPtr elem) {
428 if (elem == NULL) return;
429 xmlFreeElementContent(elem->content);
430 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000431 xmlFree((xmlChar *) elem->name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000432 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000433 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000434}
435
436/**
437 * xmlFreeElementTable:
438 * @table: An element table
439 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000440 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000441 */
442void
443xmlFreeElementTable(xmlElementTablePtr table) {
444 int i;
445
446 if (table == NULL) return;
447
448 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000449 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000450 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000451 xmlFree(table->table);
452 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000453}
454
455/**
456 * xmlCopyElementTable:
457 * @table: An element table
458 *
459 * Build a copy of an element table.
460 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000461 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000462 */
463xmlElementTablePtr
464xmlCopyElementTable(xmlElementTablePtr table) {
465 xmlElementTablePtr ret;
466 xmlElementPtr cur, ent;
467 int i;
468
Daniel Veillard6454aec1999-09-02 22:04:43 +0000469 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000470 if (ret == NULL) {
471 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
472 return(NULL);
473 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000474 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000475 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000476 if (ret->table == NULL) {
477 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000478 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000479 return(NULL);
480 }
481 ret->max_elements = table->max_elements;
482 ret->nb_elements = table->nb_elements;
483 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000484 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000485 if (cur == NULL) {
486 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000487 xmlFree(ret);
488 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000489 return(NULL);
490 }
491 ret->table[i] = cur;
492 ent = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000493 cur->type = ent->type;
494 if (ent->name != NULL)
495 cur->name = xmlStrdup(ent->name);
496 else
497 cur->name = NULL;
498 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000499 /* TODO : rebuild the attribute list on the copy */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000500 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000501 }
502 return(ret);
503}
504
505/**
506 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000507 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000508 * @table: An element table
509 *
510 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000511 */
512void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000513xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000514 int i;
515 xmlElementPtr cur;
516
517 if (table == NULL) return;
518
519 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000520 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000521 switch (cur->type) {
522 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000523 xmlBufferWriteChar(buf, "<!ELEMENT ");
524 xmlBufferWriteCHAR(buf, cur->name);
525 xmlBufferWriteChar(buf, " EMPTY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000526 break;
527 case XML_ELEMENT_TYPE_ANY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000528 xmlBufferWriteChar(buf, "<!ELEMENT ");
529 xmlBufferWriteCHAR(buf, cur->name);
530 xmlBufferWriteChar(buf, " ANY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000531 break;
532 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000533 xmlBufferWriteChar(buf, "<!ELEMENT ");
534 xmlBufferWriteCHAR(buf, cur->name);
535 xmlBufferWriteChar(buf, " ");
536 xmlDumpElementContent(buf, cur->content, 1);
537 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000538 break;
539 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000540 xmlBufferWriteChar(buf, "<!ELEMENT ");
541 xmlBufferWriteCHAR(buf, cur->name);
542 xmlBufferWriteChar(buf, " ");
543 xmlDumpElementContent(buf, cur->content, 1);
544 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000545 break;
546 default:
547 fprintf(stderr,
548 "xmlDumpElementTable: internal: unknown type %d\n",
549 cur->type);
550 }
551 }
552}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000553
554/**
555 * xmlCreateEnumeration:
556 * @name: the enumeration name or NULL
557 *
558 * create and initialize an enumeration attribute node.
559 *
560 * Returns the xmlEnumerationPtr just created or NULL in case
561 * of error.
562 */
563xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000564xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000565 xmlEnumerationPtr ret;
566
Daniel Veillard6454aec1999-09-02 22:04:43 +0000567 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000568 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000569 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000570 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000571 return(NULL);
572 }
573
574 if (name != NULL)
575 ret->name = xmlStrdup(name);
576 else
577 ret->name = NULL;
578 ret->next = NULL;
579 return(ret);
580}
581
582/**
583 * xmlFreeEnumeration:
584 * @cur: the tree to free.
585 *
586 * free an enumeration attribute node (recursive).
587 */
588void
589xmlFreeEnumeration(xmlEnumerationPtr cur) {
590 if (cur == NULL) return;
591
592 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
593
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000594 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000595 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000596 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000597}
598
599/**
600 * xmlCopyEnumeration:
601 * @cur: the tree to copy.
602 *
603 * Copy an enumeration attribute node (recursive).
604 *
605 * Returns the xmlEnumerationPtr just created or NULL in case
606 * of error.
607 */
608xmlEnumerationPtr
609xmlCopyEnumeration(xmlEnumerationPtr cur) {
610 xmlEnumerationPtr ret;
611
612 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000613 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000614
615 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
616 else ret->next = NULL;
617
618 return(ret);
619}
620
621/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000622 * xmlDumpEnumeration:
623 * @buf: the XML buffer output
624 * @enum: An enumeration
625 *
626 * This will dump the content of the enumeration
627 */
628void
629xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
630 if (cur == NULL) return;
631
632 xmlBufferWriteCHAR(buf, cur->name);
633 if (cur->next == NULL)
634 xmlBufferWriteChar(buf, ")");
635 else {
636 xmlBufferWriteChar(buf, " | ");
637 xmlDumpEnumeration(buf, cur->next);
638 }
639}
640
641/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000642 * xmlCreateAttributeTable:
643 *
644 * create and initialize an empty attribute hash table.
645 *
646 * Returns the xmlAttributeTablePtr just created or NULL in case
647 * of error.
648 */
649xmlAttributeTablePtr
650xmlCreateAttributeTable(void) {
651 xmlAttributeTablePtr ret;
652
653 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000654 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000655 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000656 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000657 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000658 return(NULL);
659 }
660 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
661 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000662 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000663 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000664 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000665 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000666 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000667 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000668 return(NULL);
669 }
670 return(ret);
671}
672
Daniel Veillardb05deb71999-08-10 19:04:08 +0000673/**
674 * xmlScanAttributeDecl:
675 * @dtd: pointer to the DTD
676 * @elem: the element name
677 *
678 * When inserting a new element scan the DtD for existing attributes
679 * for taht element and initialize the Attribute chain
680 *
681 * Returns the pointer to the first attribute decl in the chain,
682 * possibly NULL.
683 */
684xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000685xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000686 xmlAttributePtr ret = NULL;
687 xmlAttributeTablePtr table;
688 int i;
689
690 if (dtd == NULL) {
691 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
692 return(NULL);
693 }
694 if (elem == NULL) {
695 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
696 return(NULL);
697 }
698 table = dtd->attributes;
699 if (table == NULL)
700 return(NULL);
701
702 for (i = 0;i < table->nb_attributes;i++) {
703 if (!xmlStrcmp(table->table[i]->elem, elem)) {
704 table->table[i]->next = ret;
705 ret = table->table[i];
706 }
707 }
708 return(ret);
709}
710
711/**
712 * xmlScanIDAttributeDecl:
713 * @ctxt: the validation context
714 * @elem: the element name
715 *
716 * Veryfy that the element don't have too many ID attributes
717 * declared.
718 *
719 * Returns the number of ID attributes found.
720 */
721int
722xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
723 xmlAttributePtr cur;
724 int ret = 0;
725
726 if (elem == NULL) return(0);
727 cur = elem->attributes;
728 while (cur != NULL) {
729 if (cur->type == XML_ATTRIBUTE_ID) {
730 ret ++;
731 if (ret > 1)
732 VERROR(ctxt->userData,
733 "Element %s has too may ID attributes defined : %s\n",
734 elem->name, cur->name);
735 }
736 cur = cur->next;
737 }
738 return(ret);
739}
740
Daniel Veillard1e346af1999-02-22 10:33:01 +0000741
742/**
743 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000744 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000745 * @dtd: pointer to the DTD
746 * @elem: the element name
747 * @name: the attribute name
748 * @type: the attribute type
749 * @def: the attribute default type
750 * @defaultValue: the attribute default value
751 * @tree: if it's an enumeration, the associated list
752 *
753 * Register a new attribute declaration
754 *
755 * Returns NULL if not, othervise the entity
756 */
757xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000758xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
759 const xmlChar *name, xmlAttributeType type,
760 xmlAttributeDefault def, const xmlChar *defaultValue,
Daniel Veillardc26087b1999-08-30 11:23:51 +0000761 xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000762 xmlAttributePtr ret, cur;
763 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000764 xmlElementPtr elemDef;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000765 xmlChar *rname;
766 xmlChar *ns;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000767 int i;
768
769 if (dtd == NULL) {
770 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
771 return(NULL);
772 }
773 if (name == NULL) {
774 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
775 return(NULL);
776 }
777 if (elem == NULL) {
778 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
779 return(NULL);
780 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000781 /*
782 * Check the type and possibly the default value.
783 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000784 switch (type) {
785 case XML_ATTRIBUTE_CDATA:
786 break;
787 case XML_ATTRIBUTE_ID:
788 break;
789 case XML_ATTRIBUTE_IDREF:
790 break;
791 case XML_ATTRIBUTE_IDREFS:
792 break;
793 case XML_ATTRIBUTE_ENTITY:
794 break;
795 case XML_ATTRIBUTE_ENTITIES:
796 break;
797 case XML_ATTRIBUTE_NMTOKEN:
798 break;
799 case XML_ATTRIBUTE_NMTOKENS:
800 break;
801 case XML_ATTRIBUTE_ENUMERATION:
802 break;
803 case XML_ATTRIBUTE_NOTATION:
804 break;
805 default:
806 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
807 return(NULL);
808 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000809 if ((defaultValue != NULL) &&
810 (!xmlValidateAttributeValue(type, defaultValue))) {
811 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
812 elem, name, defaultValue);
813 defaultValue = NULL;
814 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000815
816 /*
817 * Create the Attribute table if needed.
818 */
819 table = dtd->attributes;
820 if (table == NULL)
821 table = dtd->attributes = xmlCreateAttributeTable();
822 if (table == NULL) {
823 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
824 return(NULL);
825 }
826
827 /*
Daniel Veillard10a2c651999-12-12 13:03:50 +0000828 * Split the full name into a namespace prefix and the tag name
829 */
830 rname = xmlSplitQName(name, &ns);
831
832 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +0000833 * Validity Check:
834 * Search the DTD for previous declarations of the ATTLIST
835 */
836 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000837 cur = table->table[i];
Daniel Veillard10a2c651999-12-12 13:03:50 +0000838 if ((ns != NULL) && (cur->prefix == NULL)) continue;
839 if ((ns == NULL) && (cur->prefix != NULL)) continue;
840 if ((!xmlStrcmp(cur->name, rname)) && (!xmlStrcmp(cur->elem, elem)) &&
841 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000842 /*
843 * The attribute is already defined in this Dtd.
844 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000845 VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
846 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000847 }
848 }
849
850 /*
851 * Grow the table, if needed.
852 */
853 if (table->nb_attributes >= table->max_attributes) {
854 /*
855 * need more attributes.
856 */
857 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000858 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000859 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000860 sizeof(xmlAttributePtr));
861 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000862 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
863 return(NULL);
864 }
865 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000866 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000867 if (ret == NULL) {
868 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
869 return(NULL);
870 }
871 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000872
873 /*
874 * fill the structure.
875 */
876 ret->type = type;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000877 ret->name = rname;
878 ret->prefix = ns;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000879 ret->elem = xmlStrdup(elem);
880 ret->def = def;
881 ret->tree = tree;
882 if (defaultValue != NULL)
883 ret->defaultValue = xmlStrdup(defaultValue);
884 else
885 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000886 elemDef = xmlGetDtdElementDesc(dtd, elem);
887 if (elemDef != NULL) {
888 if ((type == XML_ATTRIBUTE_ID) &&
889 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
890 VERROR(ctxt->userData,
891 "Element %s has too may ID attributes defined : %s\n",
892 elem, name);
893 ret->next = elemDef->attributes;
894 elemDef->attributes = ret;
895 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000896 table->nb_attributes++;
897
898 return(ret);
899}
900
901/**
902 * xmlFreeAttribute:
903 * @elem: An attribute
904 *
905 * Deallocate the memory used by an attribute definition
906 */
907void
908xmlFreeAttribute(xmlAttributePtr attr) {
909 if (attr == NULL) return;
910 if (attr->tree != NULL)
911 xmlFreeEnumeration(attr->tree);
912 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000913 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000914 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000915 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000916 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000917 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +0000918 if (attr->prefix != NULL)
919 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000920 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000921 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000922}
923
924/**
925 * xmlFreeAttributeTable:
926 * @table: An attribute table
927 *
928 * Deallocate the memory used by an entities hash table.
929 */
930void
931xmlFreeAttributeTable(xmlAttributeTablePtr table) {
932 int i;
933
934 if (table == NULL) return;
935
936 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000937 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000938 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000939 xmlFree(table->table);
940 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000941}
942
943/**
944 * xmlCopyAttributeTable:
945 * @table: An attribute table
946 *
947 * Build a copy of an attribute table.
948 *
949 * Returns the new xmlAttributeTablePtr or NULL in case of error.
950 */
951xmlAttributeTablePtr
952xmlCopyAttributeTable(xmlAttributeTablePtr table) {
953 xmlAttributeTablePtr ret;
954 xmlAttributePtr cur, attr;
955 int i;
956
Daniel Veillard6454aec1999-09-02 22:04:43 +0000957 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000958 if (ret == NULL) {
959 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
960 return(NULL);
961 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000962 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000963 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000964 if (ret->table == NULL) {
965 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000966 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000967 return(NULL);
968 }
969 ret->max_attributes = table->max_attributes;
970 ret->nb_attributes = table->nb_attributes;
971 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000972 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +0000973 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000974 if (cur == NULL) {
975 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000976 xmlFree(ret);
977 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000978 return(NULL);
979 }
980 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000981 cur->type = attr->type;
982 cur->def = attr->def;
983 cur->tree = xmlCopyEnumeration(attr->tree);
984 if (attr->elem != NULL)
985 cur->elem = xmlStrdup(attr->elem);
986 else
987 cur->elem = NULL;
988 if (attr->name != NULL)
989 cur->name = xmlStrdup(attr->name);
990 else
991 cur->name = NULL;
992 if (attr->defaultValue != NULL)
993 cur->defaultValue = xmlStrdup(attr->defaultValue);
994 else
995 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000996 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000997 }
998 return(ret);
999}
1000
1001/**
1002 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001003 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001004 * @table: An attribute table
1005 *
1006 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001007 */
1008void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001009xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001010 int i;
1011 xmlAttributePtr cur;
1012
1013 if (table == NULL) return;
1014
1015 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001016 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001017 xmlBufferWriteChar(buf, "<!ATTLIST ");
1018 xmlBufferWriteCHAR(buf, cur->elem);
1019 xmlBufferWriteChar(buf, " ");
1020 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001021 switch (cur->type) {
1022 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001023 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001024 break;
1025 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001026 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001027 break;
1028 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001029 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001030 break;
1031 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001032 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001033 break;
1034 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001035 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001036 break;
1037 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001038 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001039 break;
1040 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001041 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001042 break;
1043 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001044 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001045 break;
1046 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001047 xmlBufferWriteChar(buf, " (");
1048 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001049 break;
1050 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001051 xmlBufferWriteChar(buf, " NOTATION (");
1052 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001053 break;
1054 default:
1055 fprintf(stderr,
1056 "xmlDumpAttributeTable: internal: unknown type %d\n",
1057 cur->type);
1058 }
1059 switch (cur->def) {
1060 case XML_ATTRIBUTE_NONE:
1061 break;
1062 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001063 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001064 break;
1065 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001066 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001067 break;
1068 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001069 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001070 break;
1071 default:
1072 fprintf(stderr,
1073 "xmlDumpAttributeTable: internal: unknown default %d\n",
1074 cur->def);
1075 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001076 if (cur->defaultValue != NULL) {
1077 xmlBufferWriteChar(buf, " ");
1078 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1079 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001080 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001081 }
1082}
1083
1084/************************************************************************
1085 * *
1086 * NOTATIONs *
1087 * *
1088 ************************************************************************/
1089/**
1090 * xmlCreateNotationTable:
1091 *
1092 * create and initialize an empty notation hash table.
1093 *
1094 * Returns the xmlNotationTablePtr just created or NULL in case
1095 * of error.
1096 */
1097xmlNotationTablePtr
1098xmlCreateNotationTable(void) {
1099 xmlNotationTablePtr ret;
1100
1101 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001102 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001103 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001104 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001105 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001106 return(NULL);
1107 }
1108 ret->max_notations = XML_MIN_NOTATION_TABLE;
1109 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001110 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001111 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001112 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001113 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001114 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001115 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001116 return(NULL);
1117 }
1118 return(ret);
1119}
1120
1121
1122/**
1123 * xmlAddNotationDecl:
1124 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001125 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001126 * @name: the entity name
1127 * @PublicID: the public identifier or NULL
1128 * @SystemID: the system identifier or NULL
1129 *
1130 * Register a new notation declaration
1131 *
1132 * Returns NULL if not, othervise the entity
1133 */
1134xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001135xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1136 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001137 xmlNotationPtr ret, cur;
1138 xmlNotationTablePtr table;
1139 int i;
1140
1141 if (dtd == NULL) {
1142 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1143 return(NULL);
1144 }
1145 if (name == NULL) {
1146 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1147 return(NULL);
1148 }
1149 if ((PublicID == NULL) && (SystemID == NULL)) {
1150 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1151 }
1152
1153 /*
1154 * Create the Notation table if needed.
1155 */
1156 table = dtd->notations;
1157 if (table == NULL)
1158 table = dtd->notations = xmlCreateNotationTable();
1159 if (table == NULL) {
1160 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1161 return(NULL);
1162 }
1163
1164 /*
1165 * Validity Check:
1166 * Search the DTD for previous declarations of the ATTLIST
1167 */
1168 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001169 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001170 if (!xmlStrcmp(cur->name, name)) {
1171 /*
1172 * The notation is already defined in this Dtd.
1173 */
1174 fprintf(stderr,
1175 "xmlAddNotationDecl: %s already defined\n", name);
1176 }
1177 }
1178
1179 /*
1180 * Grow the table, if needed.
1181 */
1182 if (table->nb_notations >= table->max_notations) {
1183 /*
1184 * need more notations.
1185 */
1186 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001187 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001188 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001189 sizeof(xmlNotationPtr));
1190 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001191 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1192 return(NULL);
1193 }
1194 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001195 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001196 if (ret == NULL) {
1197 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1198 return(NULL);
1199 }
1200 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001201
1202 /*
1203 * fill the structure.
1204 */
1205 ret->name = xmlStrdup(name);
1206 if (SystemID != NULL)
1207 ret->SystemID = xmlStrdup(SystemID);
1208 else
1209 ret->SystemID = NULL;
1210 if (PublicID != NULL)
1211 ret->PublicID = xmlStrdup(PublicID);
1212 else
1213 ret->PublicID = NULL;
1214 table->nb_notations++;
1215
1216 return(ret);
1217}
1218
1219/**
1220 * xmlFreeNotation:
1221 * @not: A notation
1222 *
1223 * Deallocate the memory used by an notation definition
1224 */
1225void
1226xmlFreeNotation(xmlNotationPtr nota) {
1227 if (nota == NULL) return;
1228 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001229 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001230 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001231 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001232 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001233 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001234 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001235 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001236}
1237
1238/**
1239 * xmlFreeNotationTable:
1240 * @table: An notation table
1241 *
1242 * Deallocate the memory used by an entities hash table.
1243 */
1244void
1245xmlFreeNotationTable(xmlNotationTablePtr table) {
1246 int i;
1247
1248 if (table == NULL) return;
1249
1250 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001251 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001252 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001253 xmlFree(table->table);
1254 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001255}
1256
1257/**
1258 * xmlCopyNotationTable:
1259 * @table: A notation table
1260 *
1261 * Build a copy of a notation table.
1262 *
1263 * Returns the new xmlNotationTablePtr or NULL in case of error.
1264 */
1265xmlNotationTablePtr
1266xmlCopyNotationTable(xmlNotationTablePtr table) {
1267 xmlNotationTablePtr ret;
1268 xmlNotationPtr cur, nota;
1269 int i;
1270
Daniel Veillard6454aec1999-09-02 22:04:43 +00001271 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001272 if (ret == NULL) {
1273 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1274 return(NULL);
1275 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001276 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001277 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001278 if (ret->table == NULL) {
1279 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001280 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001281 return(NULL);
1282 }
1283 ret->max_notations = table->max_notations;
1284 ret->nb_notations = table->nb_notations;
1285 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001286 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001287 if (cur == NULL) {
1288 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001289 xmlFree(ret);
1290 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001291 return(NULL);
1292 }
1293 ret->table[i] = cur;
1294 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001295 if (nota->name != NULL)
1296 cur->name = xmlStrdup(nota->name);
1297 else
1298 cur->name = NULL;
1299 if (nota->PublicID != NULL)
1300 cur->PublicID = xmlStrdup(nota->PublicID);
1301 else
1302 cur->PublicID = NULL;
1303 if (nota->SystemID != NULL)
1304 cur->SystemID = xmlStrdup(nota->SystemID);
1305 else
1306 cur->SystemID = NULL;
1307 }
1308 return(ret);
1309}
1310
1311/**
1312 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001313 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001314 * @table: A notation table
1315 *
1316 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001317 */
1318void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001319xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001320 int i;
1321 xmlNotationPtr cur;
1322
1323 if (table == NULL) return;
1324
1325 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001326 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001327 xmlBufferWriteChar(buf, "<!NOTATION ");
1328 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001329 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001330 xmlBufferWriteChar(buf, " PUBLIC ");
1331 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001332 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001333 xmlBufferWriteChar(buf, " ");
1334 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001335 }
1336 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001337 xmlBufferWriteChar(buf, " SYSTEM ");
1338 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001339 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001340 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001341 }
1342}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001343
1344/************************************************************************
1345 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001346 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001347 * *
1348 ************************************************************************/
1349/**
1350 * xmlCreateIDTable:
1351 *
1352 * create and initialize an empty id hash table.
1353 *
1354 * Returns the xmlIDTablePtr just created or NULL in case
1355 * of error.
1356 */
1357xmlIDTablePtr
1358xmlCreateIDTable(void) {
1359 xmlIDTablePtr ret;
1360
1361 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001362 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001363 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001364 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001365 (long)sizeof(xmlIDTable));
1366 return(NULL);
1367 }
1368 ret->max_ids = XML_MIN_NOTATION_TABLE;
1369 ret->nb_ids = 0;
1370 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001371 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001372 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001373 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001374 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001375 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001376 return(NULL);
1377 }
1378 return(ret);
1379}
1380
1381
1382/**
1383 * xmlAddID:
1384 * @ctxt: the validation context
1385 * @doc: pointer to the document
1386 * @value: the value name
1387 * @attr: the attribute holding the ID
1388 *
1389 * Register a new id declaration
1390 *
1391 * Returns NULL if not, othervise the new xmlIDPtr
1392 */
1393xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001394xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001395 xmlAttrPtr attr) {
1396 xmlIDPtr ret, cur;
1397 xmlIDTablePtr table;
1398 int i;
1399
1400 if (doc == NULL) {
1401 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1402 return(NULL);
1403 }
1404 if (value == NULL) {
1405 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1406 return(NULL);
1407 }
1408 if (attr == NULL) {
1409 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1410 return(NULL);
1411 }
1412
1413 /*
1414 * Create the ID table if needed.
1415 */
1416 table = doc->ids;
1417 if (table == NULL)
1418 table = doc->ids = xmlCreateIDTable();
1419 if (table == NULL) {
1420 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1421 return(NULL);
1422 }
1423
1424 /*
1425 * Validity Check:
1426 * Search the DTD for previous declarations of the ATTLIST
1427 */
1428 for (i = 0;i < table->nb_ids;i++) {
1429 cur = table->table[i];
1430 if (!xmlStrcmp(cur->value, value)) {
1431 /*
1432 * The id is already defined in this Dtd.
1433 */
1434 VERROR(ctxt->userData, "ID %s already defined\n", value);
1435 return(NULL);
1436 }
1437 }
1438
1439 /*
1440 * Grow the table, if needed.
1441 */
1442 if (table->nb_ids >= table->max_ids) {
1443 /*
1444 * need more ids.
1445 */
1446 table->max_ids *= 2;
1447 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001448 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001449 sizeof(xmlIDPtr));
1450 if (table->table == NULL) {
1451 fprintf(stderr, "xmlAddID: out of memory\n");
1452 return(NULL);
1453 }
1454 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001455 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001456 if (ret == NULL) {
1457 fprintf(stderr, "xmlAddID: out of memory\n");
1458 return(NULL);
1459 }
1460 table->table[table->nb_ids] = ret;
1461
1462 /*
1463 * fill the structure.
1464 */
1465 ret->value = xmlStrdup(value);
1466 ret->attr = attr;
1467 table->nb_ids++;
1468
1469 return(ret);
1470}
1471
1472/**
1473 * xmlFreeID:
1474 * @not: A id
1475 *
1476 * Deallocate the memory used by an id definition
1477 */
1478void
1479xmlFreeID(xmlIDPtr id) {
1480 if (id == NULL) return;
1481 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001482 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001483 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001484 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001485}
1486
1487/**
1488 * xmlFreeIDTable:
1489 * @table: An id table
1490 *
1491 * Deallocate the memory used by an ID hash table.
1492 */
1493void
1494xmlFreeIDTable(xmlIDTablePtr table) {
1495 int i;
1496
1497 if (table == NULL) return;
1498
1499 for (i = 0;i < table->nb_ids;i++) {
1500 xmlFreeID(table->table[i]);
1501 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001502 xmlFree(table->table);
1503 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001504}
1505
1506/**
1507 * xmlIsID
1508 * @doc: the document
1509 * @elem: the element carrying the attribute
1510 * @attr: the attribute
1511 *
1512 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1513 * then this is simple, otherwise we use an heuristic: name ID (upper
1514 * or lowercase).
1515 *
1516 * Returns 0 or 1 depending on the lookup result
1517 */
1518int
1519xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1520 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1521 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1522 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1523 (attr->name[2] == 0)) return(1);
1524 } else {
1525 xmlAttributePtr attrDecl;
1526
1527 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1528 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1529 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1530 attr->name);
1531
Daniel Veillardb96e6431999-08-29 21:02:19 +00001532 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001533 return(1);
1534 }
1535 return(0);
1536}
1537
Daniel Veillardb96e6431999-08-29 21:02:19 +00001538/**
1539 * xmlGetID:
1540 * @doc: pointer to the document
1541 * @ID: the ID value
1542 *
1543 * Search the attribute declaring the given ID
1544 *
1545 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1546 */
1547xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001548xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001549 xmlIDPtr cur;
1550 xmlIDTablePtr table;
1551 int i;
1552
1553 if (doc == NULL) {
1554 fprintf(stderr, "xmlGetID: doc == NULL\n");
1555 return(NULL);
1556 }
1557
1558 if (ID == NULL) {
1559 fprintf(stderr, "xmlGetID: ID == NULL\n");
1560 return(NULL);
1561 }
1562
1563 table = doc->ids;
1564 if (table == NULL)
1565 return(NULL);
1566
1567 /*
1568 * Search the ID list.
1569 */
1570 for (i = 0;i < table->nb_ids;i++) {
1571 cur = table->table[i];
1572 if (!xmlStrcmp(cur->value, ID)) {
1573 return(cur->attr);
1574 }
1575 }
1576 return(NULL);
1577}
1578
Daniel Veillard991e63d1999-08-15 23:32:28 +00001579/************************************************************************
1580 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001581 * Refs *
1582 * *
1583 ************************************************************************/
1584/**
1585 * xmlCreateRefTable:
1586 *
1587 * create and initialize an empty ref hash table.
1588 *
1589 * Returns the xmlRefTablePtr just created or NULL in case
1590 * of error.
1591 */
1592xmlRefTablePtr
1593xmlCreateRefTable(void) {
1594 xmlRefTablePtr ret;
1595
1596 ret = (xmlRefTablePtr)
1597 xmlMalloc(sizeof(xmlRefTable));
1598 if (ret == NULL) {
1599 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1600 (long)sizeof(xmlRefTable));
1601 return(NULL);
1602 }
1603 ret->max_refs = XML_MIN_NOTATION_TABLE;
1604 ret->nb_refs = 0;
1605 ret->table = (xmlRefPtr *)
1606 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1607 if (ret == NULL) {
1608 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1609 ret->max_refs * (long)sizeof(xmlRef));
1610 xmlFree(ret);
1611 return(NULL);
1612 }
1613 return(ret);
1614}
1615
1616
1617/**
1618 * xmlAddRef:
1619 * @ctxt: the validation context
1620 * @doc: pointer to the document
1621 * @value: the value name
1622 * @attr: the attribute holding the Ref
1623 *
1624 * Register a new ref declaration
1625 *
1626 * Returns NULL if not, othervise the new xmlRefPtr
1627 */
1628xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001629xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001630 xmlAttrPtr attr) {
1631 xmlRefPtr ret;
1632 xmlRefTablePtr table;
1633
1634 if (doc == NULL) {
1635 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1636 return(NULL);
1637 }
1638 if (value == NULL) {
1639 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1640 return(NULL);
1641 }
1642 if (attr == NULL) {
1643 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1644 return(NULL);
1645 }
1646
1647 /*
1648 * Create the Ref table if needed.
1649 */
1650 table = doc->refs;
1651 if (table == NULL)
1652 table = doc->refs = xmlCreateRefTable();
1653 if (table == NULL) {
1654 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1655 return(NULL);
1656 }
1657
1658 /*
1659 * Grow the table, if needed.
1660 */
1661 if (table->nb_refs >= table->max_refs) {
1662 /*
1663 * need more refs.
1664 */
1665 table->max_refs *= 2;
1666 table->table = (xmlRefPtr *)
1667 xmlRealloc(table->table, table->max_refs *
1668 sizeof(xmlRefPtr));
1669 if (table->table == NULL) {
1670 fprintf(stderr, "xmlAddRef: out of memory\n");
1671 return(NULL);
1672 }
1673 }
1674 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1675 if (ret == NULL) {
1676 fprintf(stderr, "xmlAddRef: out of memory\n");
1677 return(NULL);
1678 }
1679 table->table[table->nb_refs] = ret;
1680
1681 /*
1682 * fill the structure.
1683 */
1684 ret->value = xmlStrdup(value);
1685 ret->attr = attr;
1686 table->nb_refs++;
1687
1688 return(ret);
1689}
1690
1691/**
1692 * xmlFreeRef:
1693 * @not: A ref
1694 *
1695 * Deallocate the memory used by an ref definition
1696 */
1697void
1698xmlFreeRef(xmlRefPtr ref) {
1699 if (ref == NULL) return;
1700 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001701 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001702 memset(ref, -1, sizeof(xmlRef));
1703 xmlFree(ref);
1704}
1705
1706/**
1707 * xmlFreeRefTable:
1708 * @table: An ref table
1709 *
1710 * Deallocate the memory used by an Ref hash table.
1711 */
1712void
1713xmlFreeRefTable(xmlRefTablePtr table) {
1714 int i;
1715
1716 if (table == NULL) return;
1717
1718 for (i = 0;i < table->nb_refs;i++) {
1719 xmlFreeRef(table->table[i]);
1720 }
1721 xmlFree(table->table);
1722 xmlFree(table);
1723}
1724
1725/**
1726 * xmlIsRef
1727 * @doc: the document
1728 * @elem: the element carrying the attribute
1729 * @attr: the attribute
1730 *
1731 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1732 * then this is simple, otherwise we use an heuristic: name Ref (upper
1733 * or lowercase).
1734 *
1735 * Returns 0 or 1 depending on the lookup result
1736 */
1737int
1738xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1739 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1740 return(0);
1741 /*******************
1742 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1743 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1744 (attr->name[2] == 0)) return(1);
1745 *******************/
1746 } else {
1747 xmlAttributePtr attrDecl;
1748
1749 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1750 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1751 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1752 attr->name);
1753
1754 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1755 return(1);
1756 }
1757 return(0);
1758}
1759
1760/**
1761 * xmlGetRef:
1762 * @doc: pointer to the document
1763 * @Ref: the Ref value
1764 *
1765 * Search the attribute declaring the given Ref
1766 *
1767 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1768 */
1769xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001770xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001771 xmlRefPtr cur;
1772 xmlRefTablePtr table;
1773 int i;
1774
1775 if (doc == NULL) {
1776 fprintf(stderr, "xmlGetRef: doc == NULL\n");
1777 return(NULL);
1778 }
1779
1780 if (Ref == NULL) {
1781 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1782 return(NULL);
1783 }
1784
1785 table = doc->refs;
1786 if (table == NULL)
1787 return(NULL);
1788
1789 /*
1790 * Search the Ref list.
1791 */
1792 for (i = 0;i < table->nb_refs;i++) {
1793 cur = table->table[i];
1794 if (!xmlStrcmp(cur->value, Ref)) {
1795 return(cur->attr);
1796 }
1797 }
1798 return(NULL);
1799}
1800
1801/************************************************************************
1802 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001803 * Routines for validity checking *
1804 * *
1805 ************************************************************************/
1806
1807/**
1808 * xmlGetDtdElementDesc:
1809 * @dtd: a pointer to the DtD to search
1810 * @name: the element name
1811 *
1812 * Search the Dtd for the description of this element
1813 *
1814 * returns the xmlElementPtr if found or NULL
1815 */
1816
1817xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001818xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001819 xmlElementTablePtr table;
1820 xmlElementPtr cur;
1821 int i;
1822
1823 if (dtd == NULL) return(NULL);
1824 if (dtd->elements == NULL) return(NULL);
1825 table = dtd->elements;
1826
1827 for (i = 0;i < table->nb_elements;i++) {
1828 cur = table->table[i];
1829 if (!xmlStrcmp(cur->name, name))
1830 return(cur);
1831 }
1832 return(NULL);
1833}
1834
1835/**
1836 * xmlGetDtdAttrDesc:
1837 * @dtd: a pointer to the DtD to search
1838 * @elem: the element name
1839 * @name: the attribute name
1840 *
1841 * Search the Dtd for the description of this attribute on
1842 * this element.
1843 *
1844 * returns the xmlAttributePtr if found or NULL
1845 */
1846
1847xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001848xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001849 xmlAttributeTablePtr table;
1850 xmlAttributePtr cur;
1851 int i;
1852
1853 if (dtd == NULL) return(NULL);
1854 if (dtd->attributes == NULL) return(NULL);
1855 table = dtd->attributes;
1856
1857 for (i = 0;i < table->nb_attributes;i++) {
1858 cur = table->table[i];
1859 if ((!xmlStrcmp(cur->name, name)) &&
1860 (!xmlStrcmp(cur->elem, elem)))
1861 return(cur);
1862 }
1863 return(NULL);
1864}
1865
1866/**
1867 * xmlGetDtdNotationDesc:
1868 * @dtd: a pointer to the DtD to search
1869 * @name: the notation name
1870 *
1871 * Search the Dtd for the description of this notation
1872 *
1873 * returns the xmlNotationPtr if found or NULL
1874 */
1875
1876xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001877xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001878 xmlNotationTablePtr table;
1879 xmlNotationPtr cur;
1880 int i;
1881
1882 if (dtd == NULL) return(NULL);
1883 if (dtd->notations == NULL) return(NULL);
1884 table = dtd->notations;
1885
1886 for (i = 0;i < table->nb_notations;i++) {
1887 cur = table->table[i];
1888 if (!xmlStrcmp(cur->name, name))
1889 return(cur);
1890 }
1891 return(NULL);
1892}
1893
1894/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001895 * xmlValidateNotationUse:
1896 * @ctxt: the validation context
1897 * @doc: the document
1898 * @notationName: the notation name to check
1899 *
1900 * Validate that the given mame match a notation declaration.
1901 * - [ VC: Notation Declared ]
1902 *
1903 * returns 1 if valid or 0 otherwise
1904 */
1905
1906int
1907xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001908 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001909 xmlNotationPtr notaDecl;
1910 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1911
1912 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1913 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1914 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1915
1916 if (notaDecl == NULL) {
1917 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1918 notationName);
1919 return(0);
1920 }
1921 return(1);
1922}
1923
1924/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00001925 * xmlIsMixedElement
1926 * @doc: the document
1927 * @name: the element name
1928 *
1929 * Search in the DtDs whether an element accept Mixed content (or ANY)
1930 * basically if it is supposed to accept text childs
1931 *
1932 * returns 0 if no, 1 if yes, and -1 if no element description is available
1933 */
1934
1935int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001936xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001937 xmlElementPtr elemDecl;
1938
1939 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1940
1941 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1942 if ((elemDecl == NULL) && (doc->extSubset != NULL))
1943 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1944 if (elemDecl == NULL) return(-1);
1945 switch (elemDecl->type) {
1946 case XML_ELEMENT_TYPE_ELEMENT:
1947 return(0);
1948 case XML_ELEMENT_TYPE_EMPTY:
1949 /*
1950 * return 1 for EMPTY since we want VC error to pop up
1951 * on <empty> </empty> for example
1952 */
1953 case XML_ELEMENT_TYPE_ANY:
1954 case XML_ELEMENT_TYPE_MIXED:
1955 return(1);
1956 }
1957 return(1);
1958}
1959
1960/**
1961 * xmlValidateNameValue:
1962 * @value: an Name value
1963 *
1964 * Validate that the given value match Name production
1965 *
1966 * returns 1 if valid or 0 otherwise
1967 */
1968
1969int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001970xmlValidateNameValue(const xmlChar *value) {
1971 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001972
1973 if (value == NULL) return(0);
1974 cur = value;
1975
1976 if (!IS_LETTER(*cur) && (*cur != '_') &&
1977 (*cur != ':')) {
1978 return(0);
1979 }
1980
1981 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1982 (*cur == '.') || (*cur == '-') ||
1983 (*cur == '_') || (*cur == ':') ||
1984 (IS_COMBINING(*cur)) ||
1985 (IS_EXTENDER(*cur)))
1986 cur++;
1987
1988 if (*cur != 0) return(0);
1989
1990 return(1);
1991}
1992
1993/**
1994 * xmlValidateNamesValue:
1995 * @value: an Names value
1996 *
1997 * Validate that the given value match Names production
1998 *
1999 * returns 1 if valid or 0 otherwise
2000 */
2001
2002int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002003xmlValidateNamesValue(const xmlChar *value) {
2004 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002005
2006 if (value == NULL) return(0);
2007 cur = value;
2008
2009 if (!IS_LETTER(*cur) && (*cur != '_') &&
2010 (*cur != ':')) {
2011 return(0);
2012 }
2013
2014 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2015 (*cur == '.') || (*cur == '-') ||
2016 (*cur == '_') || (*cur == ':') ||
2017 (IS_COMBINING(*cur)) ||
2018 (IS_EXTENDER(*cur)))
2019 cur++;
2020
2021 while (IS_BLANK(*cur)) {
2022 while (IS_BLANK(*cur)) cur++;
2023
2024 if (!IS_LETTER(*cur) && (*cur != '_') &&
2025 (*cur != ':')) {
2026 return(0);
2027 }
2028
2029 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2030 (*cur == '.') || (*cur == '-') ||
2031 (*cur == '_') || (*cur == ':') ||
2032 (IS_COMBINING(*cur)) ||
2033 (IS_EXTENDER(*cur)))
2034 cur++;
2035 }
2036
2037 if (*cur != 0) return(0);
2038
2039 return(1);
2040}
2041
2042/**
2043 * xmlValidateNmtokenValue:
2044 * @value: an Mntoken value
2045 *
2046 * Validate that the given value match Nmtoken production
2047 *
2048 * [ VC: Name Token ]
2049 *
2050 * returns 1 if valid or 0 otherwise
2051 */
2052
2053int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002054xmlValidateNmtokenValue(const xmlChar *value) {
2055 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002056
2057 if (value == NULL) return(0);
2058 cur = value;
2059
2060 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2061 (*cur != '.') && (*cur != '-') &&
2062 (*cur != '_') && (*cur != ':') &&
2063 (!IS_COMBINING(*cur)) &&
2064 (!IS_EXTENDER(*cur)))
2065 return(0);
2066
2067 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2068 (*cur == '.') || (*cur == '-') ||
2069 (*cur == '_') || (*cur == ':') ||
2070 (IS_COMBINING(*cur)) ||
2071 (IS_EXTENDER(*cur)))
2072 cur++;
2073
2074 if (*cur != 0) return(0);
2075
2076 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002077}
2078
2079/**
2080 * xmlValidateNmtokensValue:
2081 * @value: an Mntokens value
2082 *
2083 * Validate that the given value match Nmtokens production
2084 *
2085 * [ VC: Name Token ]
2086 *
2087 * returns 1 if valid or 0 otherwise
2088 */
2089
2090int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002091xmlValidateNmtokensValue(const xmlChar *value) {
2092 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002093
2094 if (value == NULL) return(0);
2095 cur = value;
2096
2097 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2098 (*cur != '.') && (*cur != '-') &&
2099 (*cur != '_') && (*cur != ':') &&
2100 (!IS_COMBINING(*cur)) &&
2101 (!IS_EXTENDER(*cur)))
2102 return(0);
2103
2104 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2105 (*cur == '.') || (*cur == '-') ||
2106 (*cur == '_') || (*cur == ':') ||
2107 (IS_COMBINING(*cur)) ||
2108 (IS_EXTENDER(*cur)))
2109 cur++;
2110
2111 while (IS_BLANK(*cur)) {
2112 while (IS_BLANK(*cur)) cur++;
2113
2114 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2115 (*cur != '.') && (*cur != '-') &&
2116 (*cur != '_') && (*cur != ':') &&
2117 (!IS_COMBINING(*cur)) &&
2118 (!IS_EXTENDER(*cur)))
2119 return(0);
2120
2121 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2122 (*cur == '.') || (*cur == '-') ||
2123 (*cur == '_') || (*cur == ':') ||
2124 (IS_COMBINING(*cur)) ||
2125 (IS_EXTENDER(*cur)))
2126 cur++;
2127 }
2128
2129 if (*cur != 0) return(0);
2130
2131 return(1);
2132}
2133
2134/**
2135 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002136 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002137 * @doc: a document instance
2138 * @nota: a notation definition
2139 *
2140 * Try to validate a single notation definition
2141 * basically it does the following checks as described by the
2142 * XML-1.0 recommendation:
2143 * - it seems that no validity constraing exist on notation declarations
2144 * But this function get called anyway ...
2145 *
2146 * returns 1 if valid or 0 otherwise
2147 */
2148
2149int
2150xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2151 xmlNotationPtr nota) {
2152 int ret = 1;
2153
2154 return(ret);
2155}
2156
2157/**
2158 * xmlValidateAttributeValue:
2159 * @type: an attribute type
2160 * @value: an attribute value
2161 *
2162 * Validate that the given attribute value match the proper production
2163 *
2164 * [ VC: ID ]
2165 * Values of type ID must match the Name production....
2166 *
2167 * [ VC: IDREF ]
2168 * Values of type IDREF must match the Name production, and values
2169 * of type IDREFS must match Names ...
2170 *
2171 * [ VC: Entity Name ]
2172 * Values of type ENTITY must match the Name production, values
2173 * of type ENTITIES must match Names ...
2174 *
2175 * [ VC: Name Token ]
2176 * Values of type NMTOKEN must match the Nmtoken production; values
2177 * of type NMTOKENS must match Nmtokens.
2178 *
2179 * returns 1 if valid or 0 otherwise
2180 */
2181
2182int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002183xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002184 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002185 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002186 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002187 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002188 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002189 case XML_ATTRIBUTE_IDREF:
2190 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002191 case XML_ATTRIBUTE_NOTATION:
2192 return(xmlValidateNameValue(value));
2193 case XML_ATTRIBUTE_NMTOKENS:
2194 case XML_ATTRIBUTE_ENUMERATION:
2195 return(xmlValidateNmtokensValue(value));
2196 case XML_ATTRIBUTE_NMTOKEN:
2197 return(xmlValidateNmtokenValue(value));
2198 case XML_ATTRIBUTE_CDATA:
2199 break;
2200 }
2201 return(1);
2202}
2203
2204/**
2205 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002206 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002207 * @doc: a document instance
2208 * @attr: an attribute definition
2209 *
2210 * Try to validate a single attribute definition
2211 * basically it does the following checks as described by the
2212 * XML-1.0 recommendation:
2213 * - [ VC: Attribute Default Legal ]
2214 * - [ VC: Enumeration ]
2215 * - [ VC: ID Attribute Default ]
2216 *
2217 * The ID/IDREF uniqueness and matching are done separately
2218 *
2219 * returns 1 if valid or 0 otherwise
2220 */
2221
2222int
2223xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2224 xmlAttributePtr attr) {
2225 int ret = 1;
2226 int val;
2227 CHECK_DTD;
2228 if(attr == NULL) return(1);
2229
2230 /* Attribute Default Legal */
2231 /* Enumeration */
2232 if (attr->defaultValue != NULL) {
2233 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2234 if (val == 0) {
2235 VERROR(ctxt->userData,
2236 "Syntax of default value for attribute %s on %s is not valid\n",
2237 attr->name, attr->elem);
2238 }
2239 ret &= val;
2240 }
2241
2242 /* ID Attribute Default */
2243 if ((attr->type == XML_ATTRIBUTE_ID)&&
2244 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2245 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2246 VERROR(ctxt->userData,
2247 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2248 attr->name, attr->elem);
2249 ret = 0;
2250 }
2251
Daniel Veillardb96e6431999-08-29 21:02:19 +00002252 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002253 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2254 int nbId = 0;
2255
2256 /* the trick is taht we parse DtD as their own internal subset */
2257 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2258 attr->elem);
2259 if (elem != NULL) {
2260 nbId = xmlScanIDAttributeDecl(NULL, elem);
2261 }
2262 if (nbId >= 1)
2263 VERROR(ctxt->userData,
2264 "Element %s has ID attribute defined in the external subset : %s\n",
2265 attr->elem, attr->name);
2266 }
2267
2268 return(ret);
2269}
2270
2271/**
2272 * xmlValidateElementDecl:
2273 * @ctxt: the validation context
2274 * @doc: a document instance
2275 * @elem: an element definition
2276 *
2277 * Try to validate a single element definition
2278 * basically it does the following checks as described by the
2279 * XML-1.0 recommendation:
2280 * - [ VC: One ID per Element Type ]
2281 * - [ VC: No Duplicate Types ]
2282 * - [ VC: Unique Element Type Declaration ]
2283 *
2284 * returns 1 if valid or 0 otherwise
2285 */
2286
2287int
2288xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2289 xmlElementPtr elem) {
2290 int ret = 1;
2291 xmlElementPtr tst;
2292
2293 CHECK_DTD;
2294
2295 if (elem == NULL) return(1);
2296
2297 /* No Duplicate Types */
2298 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2299 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002300 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002301
2302 cur = elem->content;
2303 while (cur != NULL) {
2304 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2305 if (cur->c1 == NULL) break;
2306 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2307 name = cur->c1->name;
2308 next = cur->c2;
2309 while (next != NULL) {
2310 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2311 if (!xmlStrcmp(next->name, name)) {
2312 VERROR(ctxt->userData,
2313 "Definition of %s has duplicate references of %s\n",
2314 elem->name, name);
2315 ret = 0;
2316 }
2317 break;
2318 }
2319 if (next->c1 == NULL) break;
2320 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2321 if (!xmlStrcmp(next->c1->name, name)) {
2322 VERROR(ctxt->userData,
2323 "Definition of %s has duplicate references of %s\n",
2324 elem->name, name);
2325 ret = 0;
2326 }
2327 next = next->c2;
2328 }
2329 }
2330 cur = cur->c2;
2331 }
2332 }
2333
2334 /* VC: Unique Element Type Declaration */
2335 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2336 if ((tst != NULL ) && (tst != elem)) {
2337 VERROR(ctxt->userData, "Redefinition of element %s\n",
2338 elem->name);
2339 ret = 0;
2340 }
2341 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2342 if ((tst != NULL ) && (tst != elem)) {
2343 VERROR(ctxt->userData, "Redefinition of element %s\n",
2344 elem->name);
2345 ret = 0;
2346 }
2347
2348 /* One ID per Element Type */
2349 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2350 ret = 0;
2351 }
2352 return(ret);
2353}
2354
2355/**
2356 * xmlValidateOneAttribute:
2357 * @ctxt: the validation context
2358 * @doc: a document instance
2359 * @elem: an element instance
2360 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00002361 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002362 *
2363 * Try to validate a single attribute for an element
2364 * basically it * does the following checks as described by the
2365 * XML-1.0 recommendation:
2366 * - [ VC: Attribute Value Type ]
2367 * - [ VC: Fixed Attribute Default ]
2368 * - [ VC: Entity Name ]
2369 * - [ VC: Name Token ]
2370 * - [ VC: ID ]
2371 * - [ VC: IDREF ]
2372 * - [ VC: Entity Name ]
2373 * - [ VC: Notation Attributes ]
2374 *
2375 * The ID/IDREF uniqueness and matching are done separately
2376 *
2377 * returns 1 if valid or 0 otherwise
2378 */
2379
2380int
2381xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002382 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002383 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002384 xmlAttributePtr attrDecl;
2385 int val;
2386 int ret = 1;
2387
2388 CHECK_DTD;
2389 if ((elem == NULL) || (elem->name == NULL)) return(0);
2390 if ((attr == NULL) || (attr->name == NULL)) return(0);
2391
2392 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2393 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2394 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2395
2396
2397 /* Validity Constraint: Attribute Value Type */
2398 if (attrDecl == NULL) {
2399 VERROR(ctxt->userData,
2400 "No declaration for attribute %s on element %s\n",
2401 attr->name, elem->name);
2402 return(0);
2403 }
2404 val = xmlValidateAttributeValue(attrDecl->type, value);
2405 if (val == 0) {
2406 VERROR(ctxt->userData,
2407 "Syntax of value for attribute %s on %s is not valid\n",
2408 attr->name, elem->name);
2409 ret = 0;
2410 }
2411
Daniel Veillardb96e6431999-08-29 21:02:19 +00002412 /* Validity Constraint: ID uniqueness */
2413 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2414 xmlAddID(ctxt, doc, value, attr);
2415 }
2416
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002417 if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2418 xmlAddRef(ctxt, doc, value, attr);
2419 }
2420
Daniel Veillardb05deb71999-08-10 19:04:08 +00002421 /* Validity Constraint: Notation Attributes */
2422 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2423 xmlEnumerationPtr tree = attrDecl->tree;
2424 xmlNotationPtr nota;
2425
2426 /* First check that the given NOTATION was declared */
2427 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2428 if (nota == NULL)
2429 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2430
2431 if (nota == NULL) {
2432 VERROR(ctxt->userData,
2433 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2434 value, attr->name, elem->name);
2435 ret = 0;
2436 }
2437
2438 /* Second, verify that it's among the list */
2439 while (tree != NULL) {
2440 if (!xmlStrcmp(tree->name, value)) break;
2441 tree = tree->next;
2442 }
2443 if (tree == NULL) {
2444 VERROR(ctxt->userData,
2445 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2446 value, attr->name, elem->name);
2447 ret = 0;
2448 }
2449 }
2450
2451 /* Validity Constraint: Enumeration */
2452 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2453 xmlEnumerationPtr tree = attrDecl->tree;
2454 while (tree != NULL) {
2455 if (!xmlStrcmp(tree->name, value)) break;
2456 tree = tree->next;
2457 }
2458 if (tree == NULL) {
2459 VERROR(ctxt->userData,
2460 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2461 value, attr->name, elem->name);
2462 ret = 0;
2463 }
2464 }
2465
2466 /* Fixed Attribute Default */
2467 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2468 (xmlStrcmp(attrDecl->defaultValue, value))) {
2469 VERROR(ctxt->userData,
2470 "Value for attribute %s on %s must be \"%s\"\n",
2471 attr->name, elem->name, attrDecl->defaultValue);
2472 ret = 0;
2473 }
2474
Daniel Veillardb96e6431999-08-29 21:02:19 +00002475 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002476 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2477 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2478 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2479 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002480 return(0);
2481 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002482 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002483 return(ret);
2484}
2485
2486int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2487 xmlElementContentPtr cont);
2488
2489/**
2490 * xmlValidateElementTypeExpr:
2491 * @ctxt: the validation context
2492 * @child: pointer to the child list
2493 * @cont: pointer to the content declaration
2494 *
2495 * Try to validate the content of an element of type element
2496 * but don't handle the occurence factor
2497 *
2498 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2499 * also update child value in-situ.
2500 */
2501
2502int
2503xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2504 xmlElementContentPtr cont) {
2505 xmlNodePtr cur;
2506 int ret = 1;
2507
2508 if (cont == NULL) return(-1);
2509 while (*child != NULL) {
2510 if ((*child)->type == XML_PI_NODE) {
2511 *child = (*child)->next;
2512 continue;
2513 }
2514 if ((*child)->type == XML_COMMENT_NODE) {
2515 *child = (*child)->next;
2516 continue;
2517 }
2518 else if ((*child)->type != XML_ELEMENT_NODE) {
2519 return(-1);
2520 }
2521 break;
2522 }
2523 switch (cont->type) {
2524 case XML_ELEMENT_CONTENT_PCDATA:
2525 /* Internal error !!! */
2526 fprintf(stderr, "Internal: MIXED struct bad\n");
2527 return(-1);
2528 case XML_ELEMENT_CONTENT_ELEMENT:
2529 if (*child == NULL) return(0);
2530 ret = (!xmlStrcmp((*child)->name, cont->name));
2531 if (ret == 1)
2532 *child = (*child)->next;
2533 return(ret);
2534 case XML_ELEMENT_CONTENT_OR:
2535 cur = *child;
2536 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2537 if (ret == -1) return(-1);
2538 if (ret == 1) {
2539 return(1);
2540 }
2541 /* rollback and retry the other path */
2542 *child = cur;
2543 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2544 if (ret == -1) return(-1);
2545 if (ret == 0) {
2546 *child = cur;
2547 return(0);
2548 }
2549 return(1);
2550 case XML_ELEMENT_CONTENT_SEQ:
2551 cur = *child;
2552 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2553 if (ret == -1) return(-1);
2554 if (ret == 0) {
2555 *child = cur;
2556 return(0);
2557 }
2558 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2559 if (ret == -1) return(-1);
2560 if (ret == 0) {
2561 *child = cur;
2562 return(0);
2563 }
2564 return(1);
2565 }
2566 return(ret);
2567}
2568
2569/**
2570 * xmlValidateElementTypeElement:
2571 * @ctxt: the validation context
2572 * @child: pointer to the child list
2573 * @cont: pointer to the content declaration
2574 *
2575 * Try to validate the content of an element of type element
2576 * yeah, Yet Another Regexp Implementation, and recursive
2577 *
2578 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2579 * also update child and content values in-situ.
2580 */
2581
2582int
2583xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2584 xmlElementContentPtr cont) {
2585 xmlNodePtr cur;
2586 int ret = 1;
2587
2588 if (cont == NULL) return(-1);
2589 while (*child != NULL) {
2590 if ((*child)->type == XML_PI_NODE) {
2591 *child = (*child)->next;
2592 continue;
2593 }
2594 if ((*child)->type == XML_COMMENT_NODE) {
2595 *child = (*child)->next;
2596 continue;
2597 }
2598 else if ((*child)->type != XML_ELEMENT_NODE) {
2599 return(-1);
2600 }
2601 break;
2602 }
2603 cur = *child;
2604 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2605 if (ret == -1) return(-1);
2606 switch (cont->ocur) {
2607 case XML_ELEMENT_CONTENT_ONCE:
2608 if (ret == 1) {
2609 return(1);
2610 }
2611 *child = cur;
2612 return(0);
2613 case XML_ELEMENT_CONTENT_OPT:
2614 if (ret == 0) {
2615 *child = cur;
2616 return(1);
2617 }
2618 break;
2619 case XML_ELEMENT_CONTENT_MULT:
2620 if (ret == 0) {
2621 *child = cur;
2622 break;
2623 }
2624 /* no break on purpose */
2625 case XML_ELEMENT_CONTENT_PLUS:
2626 if (ret == 0) {
2627 *child = cur;
2628 return(0);
2629 }
2630 do {
2631 cur = *child;
2632 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2633 } while (ret == 1);
2634 if (ret == -1) return(-1);
2635 *child = cur;
2636 break;
2637 }
2638 while (*child != NULL) {
2639 if ((*child)->type == XML_PI_NODE) {
2640 *child = (*child)->next;
2641 continue;
2642 }
2643 if ((*child)->type == XML_COMMENT_NODE) {
2644 *child = (*child)->next;
2645 continue;
2646 }
2647 else if ((*child)->type != XML_ELEMENT_NODE) {
2648 return(-1);
2649 }
2650 break;
2651 }
2652 return(1);
2653}
2654
2655/**
2656 * xmlSprintfElementChilds:
2657 * @buf: an output buffer
2658 * @content: An element
2659 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2660 *
2661 * This will dump the list of childs to the buffer
2662 * Intended just for the debug routine
2663 */
2664void
2665xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2666 xmlNodePtr cur;
2667
2668 if (node == NULL) return;
2669 if (glob) strcat(buf, "(");
2670 cur = node->childs;
2671 while (cur != NULL) {
2672 switch (cur->type) {
2673 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002674 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002675 if (cur->next != NULL)
2676 strcat(buf, " ");
2677 break;
2678 case XML_TEXT_NODE:
2679 case XML_CDATA_SECTION_NODE:
2680 case XML_ENTITY_REF_NODE:
2681 strcat(buf, "CDATA");
2682 if (cur->next != NULL)
2683 strcat(buf, " ");
2684 break;
2685 case XML_ATTRIBUTE_NODE:
2686 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002687 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002688 case XML_DOCUMENT_TYPE_NODE:
2689 case XML_DOCUMENT_FRAG_NODE:
2690 case XML_NOTATION_NODE:
2691 strcat(buf, "???");
2692 if (cur->next != NULL)
2693 strcat(buf, " ");
2694 break;
2695 case XML_ENTITY_NODE:
2696 case XML_PI_NODE:
2697 case XML_COMMENT_NODE:
2698 break;
2699 }
2700 cur = cur->next;
2701 }
2702 if (glob) strcat(buf, ")");
2703}
2704
2705
2706/**
2707 * xmlValidateOneElement:
2708 * @ctxt: the validation context
2709 * @doc: a document instance
2710 * @elem: an element instance
2711 *
2712 * Try to validate a single element and it's attributes,
2713 * basically it does the following checks as described by the
2714 * XML-1.0 recommendation:
2715 * - [ VC: Element Valid ]
2716 * - [ VC: Required Attribute ]
2717 * Then call xmlValidateOneAttribute() for each attribute present.
2718 *
2719 * The ID/IDREF checkings are done separately
2720 *
2721 * returns 1 if valid or 0 otherwise
2722 */
2723
2724int
2725xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2726 xmlNodePtr elem) {
2727 xmlElementPtr elemDecl;
2728 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002729 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002730 xmlNodePtr child;
2731 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002732 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002733
2734 CHECK_DTD;
2735
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002736 if (elem == NULL) return(0);
2737 if (elem->type == XML_TEXT_NODE) {
2738 }
2739 switch (elem->type) {
2740 case XML_ATTRIBUTE_NODE:
2741 VERROR(ctxt->userData,
2742 "Attribute element not expected here\n");
2743 return(0);
2744 case XML_TEXT_NODE:
2745 if (elem->childs != NULL) {
2746 VERROR(ctxt->userData, "Text element has childs !\n");
2747 return(0);
2748 }
2749 if (elem->properties != NULL) {
2750 VERROR(ctxt->userData, "Text element has attributes !\n");
2751 return(0);
2752 }
2753 if (elem->ns != NULL) {
2754 VERROR(ctxt->userData, "Text element has namespace !\n");
2755 return(0);
2756 }
2757 if (elem->ns != NULL) {
2758 VERROR(ctxt->userData,
2759 "Text element carries namespace definitions !\n");
2760 return(0);
2761 }
2762 if (elem->content == NULL) {
2763 VERROR(ctxt->userData,
2764 "Text element has no content !\n");
2765 return(0);
2766 }
2767 return(1);
2768 case XML_CDATA_SECTION_NODE:
2769 case XML_ENTITY_REF_NODE:
2770 case XML_PI_NODE:
2771 case XML_COMMENT_NODE:
2772 return(1);
2773 case XML_ENTITY_NODE:
2774 VERROR(ctxt->userData,
2775 "Entity element not expected here\n");
2776 return(0);
2777 case XML_NOTATION_NODE:
2778 VERROR(ctxt->userData,
2779 "Notation element not expected here\n");
2780 return(0);
2781 case XML_DOCUMENT_NODE:
2782 case XML_DOCUMENT_TYPE_NODE:
2783 case XML_DOCUMENT_FRAG_NODE:
2784 VERROR(ctxt->userData,
2785 "Document element not expected here\n");
2786 return(0);
2787 case XML_HTML_DOCUMENT_NODE:
2788 VERROR(ctxt->userData,
2789 "\n");
2790 return(0);
2791 case XML_ELEMENT_NODE:
2792 break;
2793 default:
2794 VERROR(ctxt->userData,
2795 "unknown element type %d\n", elem->type);
2796 return(0);
2797 }
2798 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002799
2800 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2801 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2802 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2803 if (elemDecl == NULL) {
2804 VERROR(ctxt->userData, "No declaration for element %s\n",
2805 elem->name);
2806 return(0);
2807 }
2808
2809 /* Check taht the element content matches the definition */
2810 switch (elemDecl->type) {
2811 case XML_ELEMENT_TYPE_EMPTY:
2812 if (elem->childs != NULL) {
2813 VERROR(ctxt->userData,
2814 "Element %s was declared EMPTY this one has content\n",
2815 elem->name);
2816 ret = 0;
2817 }
2818 break;
2819 case XML_ELEMENT_TYPE_ANY:
2820 /* I don't think anything is required then */
2821 break;
2822 case XML_ELEMENT_TYPE_MIXED:
2823 /* Hum, this start to get messy */
2824 child = elem->childs;
2825 while (child != NULL) {
2826 if (child->type == XML_ELEMENT_NODE) {
2827 name = child->name;
2828 cont = elemDecl->content;
2829 while (cont != NULL) {
2830 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2831 if (!xmlStrcmp(cont->name, name)) break;
2832 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2833 (cont->c1 != NULL) &&
2834 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2835 if (!xmlStrcmp(cont->c1->name, name)) break;
2836 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2837 (cont->c1 == NULL) ||
2838 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2839 /* Internal error !!! */
2840 fprintf(stderr, "Internal: MIXED struct bad\n");
2841 break;
2842 }
2843 cont = cont->c2;
2844 }
2845 if (cont == NULL) {
2846 VERROR(ctxt->userData,
2847 "Element %s is not declared in %s list of possible childs\n",
2848 name, elem->name);
2849 ret = 0;
2850 }
2851 }
2852 child = child->next;
2853 }
2854 break;
2855 case XML_ELEMENT_TYPE_ELEMENT:
2856 child = elem->childs;
2857 cont = elemDecl->content;
2858 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2859 if ((ret == 0) || (child != NULL)) {
2860 char expr[1000];
2861 char list[2000];
2862
2863 expr[0] = 0;
2864 xmlSprintfElementContent(expr, cont, 1);
2865 list[0] = 0;
2866 xmlSprintfElementChilds(list, elem, 1);
2867
2868 VERROR(ctxt->userData,
2869 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2870 elem->name, expr, list);
2871 ret = 0;
2872 }
2873 break;
2874 }
2875
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002876 /* [ VC: Required Attribute ] */
2877 attr = elemDecl->attributes;
2878 while (attr != NULL) {
2879 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
2880 xmlAttrPtr attrib;
2881 int qualified = -1;
2882
2883 attrib = elem->properties;
2884 while (attrib != NULL) {
2885 if (!xmlStrcmp(attrib->name, attr->name)) {
2886 if (attr->prefix != NULL) {
2887 xmlNsPtr nameSpace = attrib->ns;
2888
2889 if (nameSpace == NULL)
2890 nameSpace = elem->ns;
2891 /*
2892 * qualified names handling is problematic, having a
2893 * different prefix should be possible but DTDs don't
2894 * allow to define the URI instead of the prefix :-(
2895 */
2896 if (nameSpace == NULL) {
2897 if (qualified < 0)
2898 qualified = 0;
2899 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
2900 if (qualified < 1)
2901 qualified = 1;
2902 } else
2903 goto found;
2904 } else {
2905 /*
2906 * We should allow applications to define namespaces
2907 * for their application even if the DTD doesn't
2908 * carry one, otherwise, basically we would always
2909 * break.
2910 */
2911 goto found;
2912 }
2913 }
2914 attrib = attrib->next;
2915 }
2916 if (qualified == -1) {
2917 if (attr->prefix == NULL) {
2918 VERROR(ctxt->userData,
2919 "Element %s doesn't carry attribute %s\n",
2920 elem->name, attr->name);
2921 } else {
2922 VERROR(ctxt->userData,
2923 "Element %s doesn't carry attribute %s:%s\n",
2924 elem->name, attr->prefix,attr->name);
2925 }
2926 } else if (qualified == 0) {
2927 VWARNING(ctxt->userData,
2928 "Element %s required attribute %s:%s has no prefix\n",
2929 elem->name, attr->prefix,attr->name);
2930 } else if (qualified == 1) {
2931 VWARNING(ctxt->userData,
2932 "Element %s required attribute %s:%s has different prefix\n",
2933 elem->name, attr->prefix,attr->name);
2934 }
2935 }
2936found:
2937 attr = attr->next;
2938 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002939 return(ret);
2940}
2941
2942/**
2943 * xmlValidateRoot:
2944 * @ctxt: the validation context
2945 * @doc: a document instance
2946 *
2947 * Try to validate a the root element
2948 * basically it does the following check as described by the
2949 * XML-1.0 recommendation:
2950 * - [ VC: Root Element Type ]
2951 * it doesn't try to recurse or apply other check to the element
2952 *
2953 * returns 1 if valid or 0 otherwise
2954 */
2955
2956int
2957xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002958 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002959 if (doc == NULL) return(0);
2960
2961 if ((doc->intSubset == NULL) ||
2962 (doc->intSubset->name == NULL)) {
2963 VERROR(ctxt->userData, "Not valid: no DtD found\n");
2964 return(0);
2965 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002966 root = xmlDocGetRootElement(doc);
2967 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002968 VERROR(ctxt->userData, "Not valid: no root element\n");
2969 return(0);
2970 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002971 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002972 VERROR(ctxt->userData,
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002973 "Not valid: root and DtD name do not match '%s' and '%s'\n",
2974 root->name, doc->intSubset->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002975 return(0);
2976 }
2977 return(1);
2978}
2979
2980
2981/**
2982 * xmlValidateElement:
2983 * @ctxt: the validation context
2984 * @doc: a document instance
2985 * @elem: an element instance
2986 *
2987 * Try to validate the subtree under an element
2988 *
2989 * returns 1 if valid or 0 otherwise
2990 */
2991
2992int
2993xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002994 xmlNodePtr child;
2995 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002996 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002997 int ret = 1;
2998
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002999 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003000 CHECK_DTD;
3001
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003002 ret &= xmlValidateOneElement(ctxt, doc, elem);
3003 attr = elem->properties;
3004 while(attr != NULL) {
3005 value = xmlNodeListGetString(doc, attr->val, 0);
3006 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3007 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003008 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003009 attr= attr->next;
3010 }
3011 child = elem->childs;
3012 while (child != NULL) {
3013 ret &= xmlValidateElement(ctxt, doc, child);
3014 child = child->next;
3015 }
3016
3017 return(ret);
3018}
3019
3020/**
3021 * xmlValidateDocumentFinal:
3022 * @ctxt: the validation context
3023 * @doc: a document instance
3024 *
3025 * Does the final step for the document validation once all the
3026 * incremental validation steps have been completed
3027 *
3028 * basically it does the following checks described by the XML Rec
3029 *
3030 *
3031 * returns 1 if valid or 0 otherwise
3032 */
3033
3034int
3035xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3036 int ret = 1, i;
3037 xmlRefTablePtr table;
3038 xmlAttrPtr id;
3039
3040 if (doc == NULL) {
3041 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3042 return(0);
3043 }
3044
3045 /*
3046 * Get the refs table
3047 */
3048 table = doc->refs;
3049 if (table != NULL) {
3050 for (i = 0; i < table->nb_refs; i++) {
3051 id = xmlGetID(doc, table->table[i]->value);
3052 if (id == NULL) {
3053 VERROR(ctxt->userData,
3054 "IDREF attribute %s reference an unknown ID '%s'\n",
3055 table->table[i]->attr->name, table->table[i]->value);
3056 ret = 0;
3057 }
3058 }
3059 }
3060 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003061}
3062
3063/**
3064 * xmlValidateDtd:
3065 * @ctxt: the validation context
3066 * @doc: a document instance
3067 * @dtd: a dtd instance
3068 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003069 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003070 *
3071 * basically it does check all the definitions in the DtD.
3072 *
3073 * returns 1 if valid or 0 otherwise
3074 */
3075
3076int
3077xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003078 int ret;
3079 xmlDtdPtr oldExt;
3080 xmlNodePtr root;
3081
3082 if (dtd == NULL) return(0);
3083 if (doc == NULL) return(0);
3084 oldExt = doc->extSubset;
3085 doc->extSubset = dtd;
3086 ret = xmlValidateRoot(ctxt, doc);
3087 if (ret == 0) {
3088 doc->extSubset = oldExt;
3089 return(ret);
3090 }
3091 root = xmlDocGetRootElement(doc);
3092 ret = xmlValidateElement(ctxt, doc, root);
3093 ret &= xmlValidateDocumentFinal(ctxt, doc);
3094 doc->extSubset = oldExt;
3095 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003096}
3097
3098/**
3099 * xmlValidateDocument:
3100 * @ctxt: the validation context
3101 * @doc: a document instance
3102 *
3103 * Try to validate the document instance
3104 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003105 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00003106 * i.e. validates the internal and external subset (if present)
3107 * and validate the document tree.
3108 *
3109 * returns 1 if valid or 0 otherwise
3110 */
3111
3112int
3113xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003114 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003115 xmlNodePtr root;
3116
3117 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3118 return(0);
3119 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
3120 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
3121 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
3122 doc->intSubset->SystemID);
3123 if (doc->extSubset == NULL) {
3124 if (doc->intSubset->SystemID != NULL) {
3125 VERROR(ctxt->userData,
3126 "Could not load the external subset '%s'\n",
3127 doc->intSubset->SystemID);
3128 } else {
3129 VERROR(ctxt->userData,
3130 "Could not load the external subset '%s'\n",
3131 doc->intSubset->ExternalID);
3132 }
3133 return(0);
3134 }
3135 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003136
Daniel Veillardb05deb71999-08-10 19:04:08 +00003137 if (!xmlValidateRoot(ctxt, doc)) return(0);
3138
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003139 root = xmlDocGetRootElement(doc);
3140 ret = xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003141 ret &= xmlValidateDocumentFinal(ctxt, doc);
3142 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003143}
3144
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003145
3146/************************************************************************
3147 * *
3148 * Routines for dynamic validation editing *
3149 * *
3150 ************************************************************************/
3151
3152/**
3153 * xmlValidGetPotentialChildren:
3154 * @ctree: an element content tree
3155 * @list: an array to store the list of child names
3156 * @len: a pointer to the number of element in the list
3157 * @max: the size of the array
3158 *
3159 * Build/extend a list of potential children allowed by the content tree
3160 *
3161 * returns the number of element in the list, or -1 in case of error.
3162 */
3163
3164int
3165xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
3166 int *len, int max) {
3167 int i;
3168
3169 if ((ctree == NULL) || (list == NULL) || (len == NULL))
3170 return(-1);
3171 if (*len >= max) return(*len);
3172
3173 switch (ctree->type) {
3174 case XML_ELEMENT_CONTENT_PCDATA:
3175 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00003176 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
3177 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003178 break;
3179 case XML_ELEMENT_CONTENT_ELEMENT:
3180 for (i = 0; i < *len;i++)
3181 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
3182 list[(*len)++] = ctree->name;
3183 break;
3184 case XML_ELEMENT_CONTENT_SEQ:
3185 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3186 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3187 break;
3188 case XML_ELEMENT_CONTENT_OR:
3189 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3190 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3191 break;
3192 }
3193
3194 return(*len);
3195}
3196
3197/**
3198 * xmlValidGetValidElements:
3199 * @prev: an element to insert after
3200 * @next: an element to insert next
3201 * @list: an array to store the list of child names
3202 * @max: the size of the array
3203 *
3204 * This function returns the list of authorized children to insert
3205 * within an existing tree while respecting the validity constraints
3206 * forced by the Dtd. The insertion point is defined using @prev and
3207 * @next in the following ways:
3208 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3209 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3210 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3211 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3212 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
3213 *
3214 * pointers to the element names are inserted at the beginning of the array
3215 * and do not need to be freed.
3216 *
3217 * returns the number of element in the list, or -1 in case of error. If
3218 * the function returns the value @max the caller is invited to grow the
3219 * receiving array and retry.
3220 */
3221
3222int
3223xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3224 int max) {
3225 int nb_valid_elements = 0;
3226 const xmlChar *elements[256];
3227 int nb_elements = 0, i;
3228
3229 xmlNode *ref_node;
3230 xmlNode *parent;
3231 xmlNode *test_node;
3232
3233 xmlNode *prev_next;
3234 xmlNode *next_prev;
3235 xmlNode *parent_childs;
3236 xmlNode *parent_last;
3237
3238 xmlElement *element_desc;
3239
3240 if (prev == NULL && next == NULL)
3241 return(-1);
3242
3243 if (list == NULL) return(-1);
3244 if (max <= 0) return(-1);
3245
3246 nb_valid_elements = 0;
3247 ref_node = prev ? prev : next;
3248 parent = ref_node->parent;
3249
3250 /*
3251 * Retrieves the parent element declaration
3252 */
3253 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3254 parent->name);
3255 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3256 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3257 parent->name);
3258 if (element_desc == NULL) return(-1);
3259
3260 /*
3261 * Do a backup of the current tree structure
3262 */
3263 prev_next = prev ? prev->next : NULL;
3264 next_prev = next ? next->prev : NULL;
3265 parent_childs = parent->childs;
3266 parent_last = parent->last;
3267
3268 /*
3269 * Creates a dummy node and insert it into the tree
3270 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003271 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003272 test_node->doc = ref_node->doc;
3273 test_node->parent = parent;
3274 test_node->prev = prev;
3275 test_node->next = next;
3276
3277 if (prev) prev->next = test_node;
3278 else parent->childs = test_node;
3279
3280 if (next) next->prev = test_node;
3281 else parent->last = test_node;
3282
3283 /*
3284 * Insert each potential child node and check if the parent is
3285 * still valid
3286 */
3287 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
3288 elements, &nb_elements, 256);
3289
3290 for (i = 0;i < nb_elements;i++) {
3291 test_node->name = elements[i];
3292 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
3293 int j;
3294
3295 for (j = 0; j < nb_valid_elements;j++)
3296 if (!xmlStrcmp(elements[i], list[j])) break;
3297 list[nb_valid_elements++] = elements[i];
3298 if (nb_valid_elements >= max) break;
3299 }
3300 }
3301
3302 /*
3303 * Restore the tree structure
3304 */
3305 if (prev) prev->next = prev_next;
3306 if (next) next->prev = next_prev;
3307 parent->childs = parent_childs;
3308 parent->last = parent_last;
3309
3310 return(nb_valid_elements);
3311}