blob: 28d6c9d9481424b7dd7543ebfc96d6b32ee99b82 [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 Veillard361d8452000-04-03 19:48:13 +000023#include <libxml/xmlmemory.h>
24#include <libxml/valid.h>
25#include <libxml/parser.h>
26#include <libxml/parserInternals.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000027
Daniel Veillardcf461992000-03-14 18:30:20 +000028/*
29 * Generic function for accessing stacks in the Validity Context
30 */
31
32#define PUSH_AND_POP(scope, type, name) \
33scope int name##VPush(xmlValidCtxtPtr ctxt, type value) { \
34 if (ctxt->name##Nr >= ctxt->name##Max) { \
35 ctxt->name##Max *= 2; \
Daniel Veillard32bc74e2000-07-14 14:49:25 +000036 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillardcf461992000-03-14 18:30:20 +000037 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
38 if (ctxt->name##Tab == NULL) { \
39 fprintf(stderr, "realloc failed !\n"); \
40 return(0); \
41 } \
42 } \
43 ctxt->name##Tab[ctxt->name##Nr] = value; \
44 ctxt->name = value; \
45 return(ctxt->name##Nr++); \
46} \
47scope type name##VPop(xmlValidCtxtPtr ctxt) { \
48 type ret; \
49 if (ctxt->name##Nr <= 0) return(0); \
50 ctxt->name##Nr--; \
51 if (ctxt->name##Nr > 0) \
52 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
53 else \
54 ctxt->name = NULL; \
55 ret = ctxt->name##Tab[ctxt->name##Nr]; \
56 ctxt->name##Tab[ctxt->name##Nr] = 0; \
57 return(ret); \
58} \
59
60PUSH_AND_POP(static, xmlNodePtr, node)
61
62/* #define DEBUG_VALID_ALGO */
63
64#ifdef DEBUG_VALID_ALGO
65void xmlValidPrintNodeList(xmlNodePtr cur) {
66 if (cur == NULL)
67 fprintf(stderr, "null ");
68 while (cur != NULL) {
69 switch (cur->type) {
70 case XML_ELEMENT_NODE:
71 fprintf(stderr, "%s ", cur->name);
72 break;
73 case XML_TEXT_NODE:
74 fprintf(stderr, "text ");
75 break;
76 case XML_CDATA_SECTION_NODE:
77 fprintf(stderr, "cdata ");
78 break;
79 case XML_ENTITY_REF_NODE:
80 fprintf(stderr, "&%s; ", cur->name);
81 break;
82 case XML_PI_NODE:
83 fprintf(stderr, "pi(%s) ", cur->name);
84 break;
85 case XML_COMMENT_NODE:
86 fprintf(stderr, "comment ");
87 break;
88 case XML_ATTRIBUTE_NODE:
89 fprintf(stderr, "?attr? ");
90 break;
91 case XML_ENTITY_NODE:
92 fprintf(stderr, "?ent? ");
93 break;
94 case XML_DOCUMENT_NODE:
95 fprintf(stderr, "?doc? ");
96 break;
97 case XML_DOCUMENT_TYPE_NODE:
98 fprintf(stderr, "?doctype? ");
99 break;
100 case XML_DOCUMENT_FRAG_NODE:
101 fprintf(stderr, "?frag? ");
102 break;
103 case XML_NOTATION_NODE:
104 fprintf(stderr, "?nota? ");
105 break;
106 case XML_HTML_DOCUMENT_NODE:
107 fprintf(stderr, "?html? ");
108 break;
109 case XML_DTD_NODE:
110 fprintf(stderr, "?dtd? ");
111 break;
112 case XML_ELEMENT_DECL:
113 fprintf(stderr, "?edecl? ");
114 break;
115 case XML_ATTRIBUTE_DECL:
116 fprintf(stderr, "?adecl? ");
117 break;
118 case XML_ENTITY_DECL:
119 fprintf(stderr, "?entdecl? ");
120 break;
121 }
122 cur = cur->next;
123 }
124}
125
126void xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
127 char expr[1000];
128
129 expr[0] = 0;
130 fprintf(stderr, "valid: ");
131 xmlValidPrintNodeList(cur);
132 fprintf(stderr, "against ");
133 xmlSprintfElementContent(expr, cont, 0);
134 fprintf(stderr, "%s\n", expr);
135}
136
137#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
138#else
139#define DEBUG_VALID_STATE(n,c)
140#endif
141
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000142/* TODO: use hash table for accesses to elem and attribute dedinitions */
143
Daniel Veillardb05deb71999-08-10 19:04:08 +0000144#define VERROR \
145 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
146
147#define VWARNING \
148 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
149
150#define CHECK_DTD \
151 if (doc == NULL) return(0); \
Daniel Veillardcd429612000-10-11 15:57:05 +0000152 else if ((doc->intSubset == NULL) && \
153 (doc->extSubset == NULL)) return(0)
Daniel Veillardb05deb71999-08-10 19:04:08 +0000154
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000155xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
156xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000157
Daniel Veillardbe803962000-06-28 23:40:59 +0000158/************************************************************************
159 * *
160 * QName handling helper *
161 * *
162 ************************************************************************/
163
164/**
165 * xmlSplitQName2:
166 * @name: an XML parser context
167 * @prefix: a xmlChar **
168 *
169 * parse an XML qualified name string
170 *
171 * [NS 5] QName ::= (Prefix ':')? LocalPart
172 *
173 * [NS 6] Prefix ::= NCName
174 *
175 * [NS 7] LocalPart ::= NCName
176 *
177 * Returns NULL if not a QName, otherwise the local part, and prefix
178 * is updated to get the Prefix if any.
179 */
180
181xmlChar *
182xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
183 int len = 0;
184 xmlChar *ret = NULL;
185
186 *prefix = NULL;
187
188 /* xml: prefix is not really a namespace */
189 if ((name[0] == 'x') && (name[1] == 'm') &&
190 (name[2] == 'l') && (name[3] == ':'))
191 return(NULL);
192
193 /* nasty but valid */
194 if (name[0] == ':')
195 return(NULL);
196
197 /*
198 * we are not trying to validate but just to cut, and yes it will
199 * work even if this is as set of UTF-8 encoded chars
200 */
201 while ((name[len] != 0) && (name[len] != ':'))
202 len++;
203
204 if (name[len] == 0)
205 return(NULL);
206
207 *prefix = xmlStrndup(name, len);
208 ret = xmlStrdup(&name[len + 1]);
209
210 return(ret);
211}
212
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000213/****************************************************************
214 * *
215 * Util functions for data allocation/deallocation *
216 * *
217 ****************************************************************/
218
219/**
220 * xmlNewElementContent:
221 * @name: the subelement name or NULL
222 * @type: the type of element content decl
223 *
224 * Allocate an element content structure.
225 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000226 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000227 */
228xmlElementContentPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000229xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000230 xmlElementContentPtr ret;
231
232 switch(type) {
233 case XML_ELEMENT_CONTENT_ELEMENT:
234 if (name == NULL) {
235 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
236 }
237 break;
238 case XML_ELEMENT_CONTENT_PCDATA:
239 case XML_ELEMENT_CONTENT_SEQ:
240 case XML_ELEMENT_CONTENT_OR:
241 if (name != NULL) {
242 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
243 }
244 break;
245 default:
246 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
Daniel Veillard0142b842000-01-14 14:45:24 +0000247 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000248 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000249 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000250 if (ret == NULL) {
251 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
252 return(NULL);
253 }
254 ret->type = type;
255 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000256 if (name != NULL)
257 ret->name = xmlStrdup(name);
258 else
259 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000260 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000261 return(ret);
262}
263
264/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000265 * xmlCopyElementContent:
266 * @content: An element content pointer.
267 *
268 * Build a copy of an element content description.
269 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000270 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000271 */
272xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000273xmlCopyElementContent(xmlElementContentPtr cur) {
274 xmlElementContentPtr ret;
275
276 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000277 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +0000278 if (ret == NULL) {
279 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
280 return(NULL);
281 }
282 ret->ocur = cur->ocur;
283 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
284 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000285 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000286}
287
288/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000289 * xmlFreeElementContent:
290 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000291 *
292 * Free an element content structure. This is a recursive call !
293 */
294void
295xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000296 if (cur == NULL) return;
Daniel Veillard87b95392000-08-12 21:12:04 +0000297 switch (cur->type) {
298 case XML_ELEMENT_CONTENT_PCDATA:
299 case XML_ELEMENT_CONTENT_ELEMENT:
300 case XML_ELEMENT_CONTENT_SEQ:
301 case XML_ELEMENT_CONTENT_OR:
302 break;
303 default:
304 fprintf(stderr, "xmlFreeElementContent : type %d\n", cur->type);
305 return;
306 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000307 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
308 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000309 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000310 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000311 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000312}
313
Daniel Veillard1899e851999-02-01 12:18:54 +0000314/**
315 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000316 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000317 * @content: An element table
318 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
319 *
320 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000321 */
322void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000323xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000324 if (content == NULL) return;
325
Daniel Veillard5099ae81999-04-21 20:12:07 +0000326 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000327 switch (content->type) {
328 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000329 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000330 break;
331 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000332 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000333 break;
334 case XML_ELEMENT_CONTENT_SEQ:
335 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
336 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000337 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000338 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000339 xmlDumpElementContent(buf, content->c1, 0);
340 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000341 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000342 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000343 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000344 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000345 break;
346 case XML_ELEMENT_CONTENT_OR:
347 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
348 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000349 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000350 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000351 xmlDumpElementContent(buf, content->c1, 0);
352 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000353 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000354 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000355 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000356 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000357 break;
358 default:
359 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
360 content->type);
361 }
362 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000363 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000364 switch (content->ocur) {
365 case XML_ELEMENT_CONTENT_ONCE:
366 break;
367 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000368 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000369 break;
370 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000371 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000372 break;
373 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000374 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000375 break;
376 }
377}
378
Daniel Veillardb05deb71999-08-10 19:04:08 +0000379/**
380 * xmlSprintfElementContent:
381 * @buf: an output buffer
382 * @content: An element table
383 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
384 *
385 * This will dump the content of the element content definition
386 * Intended just for the debug routine
387 */
388void
389xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
390 if (content == NULL) return;
391 if (glob) strcat(buf, "(");
392 switch (content->type) {
393 case XML_ELEMENT_CONTENT_PCDATA:
394 strcat(buf, "#PCDATA");
395 break;
396 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000397 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000398 break;
399 case XML_ELEMENT_CONTENT_SEQ:
400 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
401 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
402 xmlSprintfElementContent(buf, content->c1, 1);
403 else
404 xmlSprintfElementContent(buf, content->c1, 0);
405 strcat(buf, " , ");
406 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
407 xmlSprintfElementContent(buf, content->c2, 1);
408 else
409 xmlSprintfElementContent(buf, content->c2, 0);
410 break;
411 case XML_ELEMENT_CONTENT_OR:
412 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
413 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
414 xmlSprintfElementContent(buf, content->c1, 1);
415 else
416 xmlSprintfElementContent(buf, content->c1, 0);
417 strcat(buf, " | ");
418 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
419 xmlSprintfElementContent(buf, content->c2, 1);
420 else
421 xmlSprintfElementContent(buf, content->c2, 0);
422 break;
423 }
424 if (glob)
425 strcat(buf, ")");
426 switch (content->ocur) {
427 case XML_ELEMENT_CONTENT_ONCE:
428 break;
429 case XML_ELEMENT_CONTENT_OPT:
430 strcat(buf, "?");
431 break;
432 case XML_ELEMENT_CONTENT_MULT:
433 strcat(buf, "*");
434 break;
435 case XML_ELEMENT_CONTENT_PLUS:
436 strcat(buf, "+");
437 break;
438 }
439}
440
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000441/****************************************************************
442 * *
443 * Registration of DTD declarations *
444 * *
445 ****************************************************************/
446
Daniel Veillard3b9def11999-01-31 22:15:06 +0000447/**
448 * xmlCreateElementTable:
449 *
450 * create and initialize an empty element hash table.
451 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000452 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000453 */
454xmlElementTablePtr
455xmlCreateElementTable(void) {
456 xmlElementTablePtr ret;
457
458 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000459 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000460 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000461 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000462 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000463 return(NULL);
464 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000465 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000466 ret->nb_elements = 0;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000467 ret->last = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000468 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000469 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +0000470 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000471 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000472 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000473 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000474 return(NULL);
475 }
476 return(ret);
477}
478
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000479
480/**
481 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000482 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000483 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000484 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000485 * @type: the element type
486 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000487 *
488 * Register a new element declaration
489 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000490 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000491 */
492xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000493xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillardcf461992000-03-14 18:30:20 +0000494 xmlElementTypeVal type,
495 xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000496 xmlElementPtr ret, cur;
497 xmlElementTablePtr table;
Daniel Veillardbe803962000-06-28 23:40:59 +0000498 xmlChar *ns, *uqname;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000499 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000500
501 if (dtd == NULL) {
502 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
503 return(NULL);
504 }
505 if (name == NULL) {
506 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
507 return(NULL);
508 }
509 switch (type) {
510 case XML_ELEMENT_TYPE_EMPTY:
511 if (content != NULL) {
512 fprintf(stderr,
513 "xmlAddElementDecl: content != NULL for EMPTY\n");
514 return(NULL);
515 }
516 break;
517 case XML_ELEMENT_TYPE_ANY:
518 if (content != NULL) {
519 fprintf(stderr,
520 "xmlAddElementDecl: content != NULL for ANY\n");
521 return(NULL);
522 }
523 break;
524 case XML_ELEMENT_TYPE_MIXED:
525 if (content == NULL) {
526 fprintf(stderr,
527 "xmlAddElementDecl: content == NULL for MIXED\n");
528 return(NULL);
529 }
530 break;
531 case XML_ELEMENT_TYPE_ELEMENT:
532 if (content == NULL) {
533 fprintf(stderr,
534 "xmlAddElementDecl: content == NULL for ELEMENT\n");
535 return(NULL);
536 }
537 break;
538 default:
539 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
540 return(NULL);
541 }
542
543 /*
Daniel Veillardbe803962000-06-28 23:40:59 +0000544 * check if name is a QName
545 */
546 uqname = xmlSplitQName2(name, &ns);
547 if (uqname != NULL)
548 name = uqname;
549
550 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000551 * Create the Element table if needed.
552 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000553 table = (xmlElementTablePtr) dtd->elements;
554 if (table == NULL) {
555 table = xmlCreateElementTable();
556 dtd->elements = (void *) table;
557 }
Daniel Veillard3b9def11999-01-31 22:15:06 +0000558 if (table == NULL) {
559 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
560 return(NULL);
561 }
562
563 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000564 * Validity Check:
565 * Search the DTD for previous declarations of the ELEMENT
566 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000567 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000568 cur = table->table[i];
Daniel Veillardbe803962000-06-28 23:40:59 +0000569 if ((ns != NULL) && (cur->prefix == NULL)) continue;
570 if ((ns == NULL) && (cur->prefix != NULL)) continue;
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000571 if ((xmlStrEqual(cur->name, name)) &&
572 ((ns == NULL) || (xmlStrEqual(cur->prefix, ns)))) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000573 /*
574 * The element is already defined in this Dtd.
575 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000576 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000577 return(NULL);
578 }
579 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000580
581 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000582 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000583 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000584 if (table->nb_elements >= table->max_elements) {
585 /*
586 * need more elements.
587 */
588 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000589 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000590 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000591 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000592 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
593 return(NULL);
594 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000595 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000596 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000597 if (ret == NULL) {
598 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
599 return(NULL);
600 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000601 memset(ret, 0, sizeof(xmlElement));
602 ret->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000603 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000604
605 /*
606 * fill the structure.
607 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000608 ret->etype = type;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000609 ret->name = xmlStrdup(name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000610 ret->prefix = ns;
Daniel Veillard14fff061999-06-22 21:49:07 +0000611 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000612 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000613 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000614
Daniel Veillardcf461992000-03-14 18:30:20 +0000615 /*
616 * Link it to the Dtd
617 */
618 ret->parent = dtd;
619 ret->doc = dtd->doc;
620 if (dtd->last == NULL) {
621 dtd->children = dtd->last = (xmlNodePtr) ret;
622 } else {
623 dtd->last->next = (xmlNodePtr) ret;
624 ret->prev = dtd->last;
625 dtd->last = (xmlNodePtr) ret;
626 }
Daniel Veillardbe803962000-06-28 23:40:59 +0000627 if (uqname != NULL)
628 xmlFree(uqname);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000629 return(ret);
630}
631
Daniel Veillard3b9def11999-01-31 22:15:06 +0000632/**
633 * xmlFreeElement:
634 * @elem: An element
635 *
636 * Deallocate the memory used by an element definition
637 */
638void
639xmlFreeElement(xmlElementPtr elem) {
640 if (elem == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +0000641 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000642 xmlFreeElementContent(elem->content);
643 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000644 xmlFree((xmlChar *) elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000645 if (elem->prefix != NULL)
646 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000647 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000648 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000649}
650
651/**
652 * xmlFreeElementTable:
653 * @table: An element table
654 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000655 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000656 */
657void
658xmlFreeElementTable(xmlElementTablePtr table) {
659 int i;
660
661 if (table == NULL) return;
662
663 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000664 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000665 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000666 xmlFree(table->table);
667 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000668}
669
670/**
671 * xmlCopyElementTable:
672 * @table: An element table
673 *
674 * Build a copy of an element table.
675 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000676 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000677 */
678xmlElementTablePtr
679xmlCopyElementTable(xmlElementTablePtr table) {
680 xmlElementTablePtr ret;
681 xmlElementPtr cur, ent;
682 int i;
683
Daniel Veillard6454aec1999-09-02 22:04:43 +0000684 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000685 if (ret == NULL) {
686 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
687 return(NULL);
688 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000689 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000690 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000691 if (ret->table == NULL) {
692 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000693 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000694 return(NULL);
695 }
696 ret->max_elements = table->max_elements;
697 ret->nb_elements = table->nb_elements;
698 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000699 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000700 if (cur == NULL) {
701 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000702 xmlFree(ret);
703 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000704 return(NULL);
705 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000706 memset(cur, 0, sizeof(xmlElement));
707 cur->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000708 ret->table[i] = cur;
709 ent = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000710 cur->etype = ent->etype;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000711 if (ent->name != NULL)
712 cur->name = xmlStrdup(ent->name);
713 else
714 cur->name = NULL;
715 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000716 /* TODO : rebuild the attribute list on the copy */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000717 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000718 }
719 return(ret);
720}
721
722/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000723 * xmlDumpElementDecl:
724 * @buf: the XML buffer output
725 * @elem: An element table
726 *
727 * This will dump the content of the element declaration as an XML
728 * DTD definition
729 */
730void
731xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
732 switch (elem->etype) {
733 case XML_ELEMENT_TYPE_EMPTY:
734 xmlBufferWriteChar(buf, "<!ELEMENT ");
735 xmlBufferWriteCHAR(buf, elem->name);
736 xmlBufferWriteChar(buf, " EMPTY>\n");
737 break;
738 case XML_ELEMENT_TYPE_ANY:
739 xmlBufferWriteChar(buf, "<!ELEMENT ");
740 xmlBufferWriteCHAR(buf, elem->name);
741 xmlBufferWriteChar(buf, " ANY>\n");
742 break;
743 case XML_ELEMENT_TYPE_MIXED:
744 xmlBufferWriteChar(buf, "<!ELEMENT ");
745 xmlBufferWriteCHAR(buf, elem->name);
746 xmlBufferWriteChar(buf, " ");
747 xmlDumpElementContent(buf, elem->content, 1);
748 xmlBufferWriteChar(buf, ">\n");
749 break;
750 case XML_ELEMENT_TYPE_ELEMENT:
751 xmlBufferWriteChar(buf, "<!ELEMENT ");
752 xmlBufferWriteCHAR(buf, elem->name);
753 xmlBufferWriteChar(buf, " ");
754 xmlDumpElementContent(buf, elem->content, 1);
755 xmlBufferWriteChar(buf, ">\n");
756 break;
757 default:
758 fprintf(stderr,
759 "xmlDumpElementDecl: internal: unknown type %d\n",
760 elem->etype);
761 }
762}
763
764/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000765 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000766 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000767 * @table: An element table
768 *
769 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000770 */
771void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000772xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000773 int i;
774 xmlElementPtr cur;
775
776 if (table == NULL) return;
777
778 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000779 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000780 xmlDumpElementDecl(buf, cur);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000781 }
782}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000783
784/**
785 * xmlCreateEnumeration:
786 * @name: the enumeration name or NULL
787 *
788 * create and initialize an enumeration attribute node.
789 *
790 * Returns the xmlEnumerationPtr just created or NULL in case
791 * of error.
792 */
793xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000794xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000795 xmlEnumerationPtr ret;
796
Daniel Veillard6454aec1999-09-02 22:04:43 +0000797 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000798 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000799 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000800 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000801 return(NULL);
802 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000803 memset(ret, 0, sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000804
805 if (name != NULL)
806 ret->name = xmlStrdup(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000807 return(ret);
808}
809
810/**
811 * xmlFreeEnumeration:
812 * @cur: the tree to free.
813 *
814 * free an enumeration attribute node (recursive).
815 */
816void
817xmlFreeEnumeration(xmlEnumerationPtr cur) {
818 if (cur == NULL) return;
819
820 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
821
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000822 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000823 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000824 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000825}
826
827/**
828 * xmlCopyEnumeration:
829 * @cur: the tree to copy.
830 *
831 * Copy an enumeration attribute node (recursive).
832 *
833 * Returns the xmlEnumerationPtr just created or NULL in case
834 * of error.
835 */
836xmlEnumerationPtr
837xmlCopyEnumeration(xmlEnumerationPtr cur) {
838 xmlEnumerationPtr ret;
839
840 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000841 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000842
843 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
844 else ret->next = NULL;
845
846 return(ret);
847}
848
849/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000850 * xmlDumpEnumeration:
851 * @buf: the XML buffer output
852 * @enum: An enumeration
853 *
854 * This will dump the content of the enumeration
855 */
856void
857xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
858 if (cur == NULL) return;
859
860 xmlBufferWriteCHAR(buf, cur->name);
861 if (cur->next == NULL)
862 xmlBufferWriteChar(buf, ")");
863 else {
864 xmlBufferWriteChar(buf, " | ");
865 xmlDumpEnumeration(buf, cur->next);
866 }
867}
868
869/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000870 * xmlCreateAttributeTable:
871 *
872 * create and initialize an empty attribute hash table.
873 *
874 * Returns the xmlAttributeTablePtr just created or NULL in case
875 * of error.
876 */
877xmlAttributeTablePtr
878xmlCreateAttributeTable(void) {
879 xmlAttributeTablePtr ret;
880
881 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000882 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000883 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000884 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000885 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000886 return(NULL);
887 }
888 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
889 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000890 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000891 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard87b95392000-08-12 21:12:04 +0000892 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000893 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000894 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000895 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000896 return(NULL);
897 }
898 return(ret);
899}
900
Daniel Veillardb05deb71999-08-10 19:04:08 +0000901/**
902 * xmlScanAttributeDecl:
903 * @dtd: pointer to the DTD
904 * @elem: the element name
905 *
906 * When inserting a new element scan the DtD for existing attributes
907 * for taht element and initialize the Attribute chain
908 *
909 * Returns the pointer to the first attribute decl in the chain,
910 * possibly NULL.
911 */
912xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000913xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000914 xmlAttributePtr ret = NULL;
915 xmlAttributeTablePtr table;
916 int i;
917
918 if (dtd == NULL) {
919 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
920 return(NULL);
921 }
922 if (elem == NULL) {
923 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
924 return(NULL);
925 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000926 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000927 if (table == NULL)
928 return(NULL);
929
930 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000931 if (xmlStrEqual(table->table[i]->elem, elem)) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000932 table->table[i]->nexth = ret;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000933 ret = table->table[i];
934 }
935 }
936 return(ret);
937}
938
939/**
940 * xmlScanIDAttributeDecl:
941 * @ctxt: the validation context
942 * @elem: the element name
943 *
Daniel Veillard71b656e2000-01-05 14:46:17 +0000944 * Verify that the element don't have too many ID attributes
Daniel Veillardb05deb71999-08-10 19:04:08 +0000945 * declared.
946 *
947 * Returns the number of ID attributes found.
948 */
949int
950xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
951 xmlAttributePtr cur;
952 int ret = 0;
953
954 if (elem == NULL) return(0);
955 cur = elem->attributes;
956 while (cur != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000957 if (cur->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000958 ret ++;
959 if (ret > 1)
960 VERROR(ctxt->userData,
961 "Element %s has too may ID attributes defined : %s\n",
962 elem->name, cur->name);
963 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000964 cur = cur->nexth;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000965 }
966 return(ret);
967}
968
Daniel Veillard1e346af1999-02-22 10:33:01 +0000969
970/**
971 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000972 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000973 * @dtd: pointer to the DTD
974 * @elem: the element name
975 * @name: the attribute name
Daniel Veillardcf461992000-03-14 18:30:20 +0000976 * @ns: the attribute namespace prefix
Daniel Veillard1e346af1999-02-22 10:33:01 +0000977 * @type: the attribute type
978 * @def: the attribute default type
979 * @defaultValue: the attribute default value
980 * @tree: if it's an enumeration, the associated list
981 *
982 * Register a new attribute declaration
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000983 * Note that @tree becomes the ownership of the DTD
Daniel Veillard1e346af1999-02-22 10:33:01 +0000984 *
Daniel Veillardbe803962000-06-28 23:40:59 +0000985 * Returns NULL if not new, othervise the attribute decl
Daniel Veillard1e346af1999-02-22 10:33:01 +0000986 */
987xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000988xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
Daniel Veillardcf461992000-03-14 18:30:20 +0000989 const xmlChar *name, const xmlChar *ns,
990 xmlAttributeType type, xmlAttributeDefault def,
991 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000992 xmlAttributePtr ret, cur;
993 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000994 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000995 int i;
996
997 if (dtd == NULL) {
998 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000999 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001000 return(NULL);
1001 }
1002 if (name == NULL) {
1003 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001004 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001005 return(NULL);
1006 }
1007 if (elem == NULL) {
1008 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001009 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001010 return(NULL);
1011 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001012 /*
1013 * Check the type and possibly the default value.
1014 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001015 switch (type) {
1016 case XML_ATTRIBUTE_CDATA:
1017 break;
1018 case XML_ATTRIBUTE_ID:
1019 break;
1020 case XML_ATTRIBUTE_IDREF:
1021 break;
1022 case XML_ATTRIBUTE_IDREFS:
1023 break;
1024 case XML_ATTRIBUTE_ENTITY:
1025 break;
1026 case XML_ATTRIBUTE_ENTITIES:
1027 break;
1028 case XML_ATTRIBUTE_NMTOKEN:
1029 break;
1030 case XML_ATTRIBUTE_NMTOKENS:
1031 break;
1032 case XML_ATTRIBUTE_ENUMERATION:
1033 break;
1034 case XML_ATTRIBUTE_NOTATION:
1035 break;
1036 default:
1037 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001038 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001039 return(NULL);
1040 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001041 if ((defaultValue != NULL) &&
1042 (!xmlValidateAttributeValue(type, defaultValue))) {
1043 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
1044 elem, name, defaultValue);
1045 defaultValue = NULL;
1046 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001047
1048 /*
1049 * Create the Attribute table if needed.
1050 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001051 table = (xmlAttributeTablePtr) dtd->attributes;
1052 if (table == NULL) {
1053 table = xmlCreateAttributeTable();
1054 dtd->attributes = (void *) table;
1055 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001056 if (table == NULL) {
1057 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
1058 return(NULL);
1059 }
1060
1061 /*
1062 * Validity Check:
1063 * Search the DTD for previous declarations of the ATTLIST
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001064 * The initial code used to walk the attribute table comparing
1065 * all pairs of element/attribute names, and was far too slow
1066 * for large DtDs, we now walk the attribute list associated to
1067 * the element declaration instead if this declaration is found.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001068 */
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001069 elemDef = xmlGetDtdElementDesc(dtd, elem);
1070 if (elemDef != NULL) {
1071 /*
1072 * follow the attribute list.
1073 */
1074 cur = elemDef->attributes;
1075 while (cur != NULL) {
1076 if ((ns != NULL) && (cur->prefix == NULL)) {
1077 cur = cur->nexth;
1078 continue;
1079 }
1080 if ((ns == NULL) && (cur->prefix != NULL)) {
1081 cur = cur->nexth;
1082 continue;
1083 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001084 if ((xmlStrEqual(cur->name, name)) &&
1085 ((ns == NULL) || (xmlStrEqual(cur->prefix, ns)))) {
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001086 /*
1087 * The attribute is already defined in this Dtd.
1088 */
1089 VWARNING(ctxt->userData,
1090 "Attribute %s on %s: already defined\n",
1091 name, elem);
1092 xmlFreeEnumeration(tree);
1093 return(NULL);
1094 }
1095 cur = cur->nexth;
1096 }
1097 } else {
1098 /*
1099 * Walk down the attribute table.
1100 */
1101 for (i = 0;i < table->nb_attributes;i++) {
1102 cur = table->table[i];
1103 if ((ns != NULL) && (cur->prefix == NULL)) continue;
1104 if ((ns == NULL) && (cur->prefix != NULL)) continue;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001105 if ((xmlStrEqual(cur->name, name)) &&
1106 (xmlStrEqual(cur->elem, elem)) &&
1107 ((ns == NULL) || (xmlStrEqual(cur->prefix, ns)))) {
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001108 /*
1109 * The attribute is already defined in this Dtd.
1110 */
1111 VWARNING(ctxt->userData,
1112 "Attribute %s on %s: already defined\n",
1113 elem, name);
1114 xmlFreeEnumeration(tree);
1115 return(NULL);
1116 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001117 }
1118 }
1119
1120 /*
1121 * Grow the table, if needed.
1122 */
1123 if (table->nb_attributes >= table->max_attributes) {
1124 /*
1125 * need more attributes.
1126 */
1127 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001128 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001129 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001130 sizeof(xmlAttributePtr));
1131 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001132 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1133 return(NULL);
1134 }
1135 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001136 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001137 if (ret == NULL) {
1138 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1139 return(NULL);
1140 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001141 memset(ret, 0, sizeof(xmlAttribute));
1142 ret->type = XML_ATTRIBUTE_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001143 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001144
1145 /*
1146 * fill the structure.
1147 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001148 ret->atype = type;
1149 ret->name = xmlStrdup(name);
1150 ret->prefix = xmlStrdup(ns);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001151 ret->elem = xmlStrdup(elem);
1152 ret->def = def;
1153 ret->tree = tree;
1154 if (defaultValue != NULL)
1155 ret->defaultValue = xmlStrdup(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001156 if (elemDef != NULL) {
1157 if ((type == XML_ATTRIBUTE_ID) &&
1158 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
1159 VERROR(ctxt->userData,
1160 "Element %s has too may ID attributes defined : %s\n",
1161 elem, name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001162 ret->nexth = elemDef->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001163 elemDef->attributes = ret;
1164 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001165 table->nb_attributes++;
1166
Daniel Veillardcf461992000-03-14 18:30:20 +00001167 /*
1168 * Link it to the Dtd
1169 */
1170 ret->parent = dtd;
1171 ret->doc = dtd->doc;
1172 if (dtd->last == NULL) {
1173 dtd->children = dtd->last = (xmlNodePtr) ret;
1174 } else {
1175 dtd->last->next = (xmlNodePtr) ret;
1176 ret->prev = dtd->last;
1177 dtd->last = (xmlNodePtr) ret;
1178 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001179 return(ret);
1180}
1181
1182/**
1183 * xmlFreeAttribute:
1184 * @elem: An attribute
1185 *
1186 * Deallocate the memory used by an attribute definition
1187 */
1188void
1189xmlFreeAttribute(xmlAttributePtr attr) {
1190 if (attr == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +00001191 xmlUnlinkNode((xmlNodePtr) attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001192 if (attr->tree != NULL)
1193 xmlFreeEnumeration(attr->tree);
1194 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001195 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001196 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001197 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001198 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001199 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +00001200 if (attr->prefix != NULL)
1201 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001202 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001203 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001204}
1205
1206/**
1207 * xmlFreeAttributeTable:
1208 * @table: An attribute table
1209 *
1210 * Deallocate the memory used by an entities hash table.
1211 */
1212void
1213xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1214 int i;
1215
1216 if (table == NULL) return;
1217
1218 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001219 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001220 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001221 xmlFree(table->table);
1222 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001223}
1224
1225/**
1226 * xmlCopyAttributeTable:
1227 * @table: An attribute table
1228 *
1229 * Build a copy of an attribute table.
1230 *
1231 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1232 */
1233xmlAttributeTablePtr
1234xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1235 xmlAttributeTablePtr ret;
1236 xmlAttributePtr cur, attr;
1237 int i;
1238
Daniel Veillard6454aec1999-09-02 22:04:43 +00001239 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001240 if (ret == NULL) {
1241 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1242 return(NULL);
1243 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001244 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001245 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001246 if (ret->table == NULL) {
1247 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001248 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001249 return(NULL);
1250 }
1251 ret->max_attributes = table->max_attributes;
1252 ret->nb_attributes = table->nb_attributes;
1253 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001254 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001255 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001256 if (cur == NULL) {
1257 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001258 xmlFree(ret);
1259 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001260 return(NULL);
1261 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001262 memset(cur, 0, sizeof(xmlAttribute));
1263 /* !!! cur->type = XML_ATTRIBUTE_DECL; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001264 ret->table[i] = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001265 cur->atype = attr->atype;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001266 cur->def = attr->def;
1267 cur->tree = xmlCopyEnumeration(attr->tree);
1268 if (attr->elem != NULL)
1269 cur->elem = xmlStrdup(attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001270 if (attr->name != NULL)
1271 cur->name = xmlStrdup(attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001272 if (attr->defaultValue != NULL)
1273 cur->defaultValue = xmlStrdup(attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001274 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001275 }
1276 return(ret);
1277}
1278
1279/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001280 * xmlDumpAttributeDecl:
1281 * @buf: the XML buffer output
1282 * @attr: An attribute declaration
1283 *
1284 * This will dump the content of the attribute declaration as an XML
1285 * DTD definition
1286 */
1287void
1288xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1289 xmlBufferWriteChar(buf, "<!ATTLIST ");
1290 xmlBufferWriteCHAR(buf, attr->elem);
1291 xmlBufferWriteChar(buf, " ");
Daniel Veillardbe803962000-06-28 23:40:59 +00001292 if (attr->prefix != NULL) {
1293 xmlBufferWriteCHAR(buf, attr->prefix);
1294 xmlBufferWriteChar(buf, ":");
1295 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001296 xmlBufferWriteCHAR(buf, attr->name);
1297 switch (attr->atype) {
1298 case XML_ATTRIBUTE_CDATA:
1299 xmlBufferWriteChar(buf, " CDATA");
1300 break;
1301 case XML_ATTRIBUTE_ID:
1302 xmlBufferWriteChar(buf, " ID");
1303 break;
1304 case XML_ATTRIBUTE_IDREF:
1305 xmlBufferWriteChar(buf, " IDREF");
1306 break;
1307 case XML_ATTRIBUTE_IDREFS:
1308 xmlBufferWriteChar(buf, " IDREFS");
1309 break;
1310 case XML_ATTRIBUTE_ENTITY:
1311 xmlBufferWriteChar(buf, " ENTITY");
1312 break;
1313 case XML_ATTRIBUTE_ENTITIES:
1314 xmlBufferWriteChar(buf, " ENTITIES");
1315 break;
1316 case XML_ATTRIBUTE_NMTOKEN:
1317 xmlBufferWriteChar(buf, " NMTOKEN");
1318 break;
1319 case XML_ATTRIBUTE_NMTOKENS:
1320 xmlBufferWriteChar(buf, " NMTOKENS");
1321 break;
1322 case XML_ATTRIBUTE_ENUMERATION:
1323 xmlBufferWriteChar(buf, " (");
1324 xmlDumpEnumeration(buf, attr->tree);
1325 break;
1326 case XML_ATTRIBUTE_NOTATION:
1327 xmlBufferWriteChar(buf, " NOTATION (");
1328 xmlDumpEnumeration(buf, attr->tree);
1329 break;
1330 default:
1331 fprintf(stderr,
1332 "xmlDumpAttributeTable: internal: unknown type %d\n",
1333 attr->atype);
1334 }
1335 switch (attr->def) {
1336 case XML_ATTRIBUTE_NONE:
1337 break;
1338 case XML_ATTRIBUTE_REQUIRED:
1339 xmlBufferWriteChar(buf, " #REQUIRED");
1340 break;
1341 case XML_ATTRIBUTE_IMPLIED:
1342 xmlBufferWriteChar(buf, " #IMPLIED");
1343 break;
1344 case XML_ATTRIBUTE_FIXED:
1345 xmlBufferWriteChar(buf, " #FIXED");
1346 break;
1347 default:
1348 fprintf(stderr,
1349 "xmlDumpAttributeTable: internal: unknown default %d\n",
1350 attr->def);
1351 }
1352 if (attr->defaultValue != NULL) {
1353 xmlBufferWriteChar(buf, " ");
1354 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1355 }
1356 xmlBufferWriteChar(buf, ">\n");
1357}
1358
1359/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001360 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001361 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001362 * @table: An attribute table
1363 *
1364 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001365 */
1366void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001367xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001368 int i;
1369 xmlAttributePtr cur;
1370
1371 if (table == NULL) return;
1372
1373 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001374 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001375 xmlDumpAttributeDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001376 }
1377}
1378
1379/************************************************************************
1380 * *
1381 * NOTATIONs *
1382 * *
1383 ************************************************************************/
1384/**
1385 * xmlCreateNotationTable:
1386 *
1387 * create and initialize an empty notation hash table.
1388 *
1389 * Returns the xmlNotationTablePtr just created or NULL in case
1390 * of error.
1391 */
1392xmlNotationTablePtr
1393xmlCreateNotationTable(void) {
1394 xmlNotationTablePtr ret;
1395
1396 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001397 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001398 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001399 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001400 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001401 return(NULL);
1402 }
1403 ret->max_notations = XML_MIN_NOTATION_TABLE;
1404 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001405 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001406 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001407 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001408 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001409 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001410 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001411 return(NULL);
1412 }
1413 return(ret);
1414}
1415
1416
1417/**
1418 * xmlAddNotationDecl:
1419 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001420 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001421 * @name: the entity name
1422 * @PublicID: the public identifier or NULL
1423 * @SystemID: the system identifier or NULL
1424 *
1425 * Register a new notation declaration
1426 *
1427 * Returns NULL if not, othervise the entity
1428 */
1429xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001430xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1431 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001432 xmlNotationPtr ret, cur;
1433 xmlNotationTablePtr table;
1434 int i;
1435
1436 if (dtd == NULL) {
1437 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1438 return(NULL);
1439 }
1440 if (name == NULL) {
1441 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1442 return(NULL);
1443 }
1444 if ((PublicID == NULL) && (SystemID == NULL)) {
1445 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1446 }
1447
1448 /*
1449 * Create the Notation table if needed.
1450 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001451 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001452 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001453 dtd->notations = table = xmlCreateNotationTable();
Daniel Veillard1e346af1999-02-22 10:33:01 +00001454 if (table == NULL) {
1455 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1456 return(NULL);
1457 }
1458
1459 /*
1460 * Validity Check:
1461 * Search the DTD for previous declarations of the ATTLIST
1462 */
1463 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001464 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001465 if (xmlStrEqual(cur->name, name)) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001466 /*
1467 * The notation is already defined in this Dtd.
1468 */
1469 fprintf(stderr,
1470 "xmlAddNotationDecl: %s already defined\n", name);
1471 }
1472 }
1473
1474 /*
1475 * Grow the table, if needed.
1476 */
1477 if (table->nb_notations >= table->max_notations) {
1478 /*
1479 * need more notations.
1480 */
1481 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001482 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001483 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001484 sizeof(xmlNotationPtr));
1485 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001486 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1487 return(NULL);
1488 }
1489 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001490 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001491 if (ret == NULL) {
1492 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1493 return(NULL);
1494 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001495 memset(ret, 0, sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001496 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001497
1498 /*
1499 * fill the structure.
1500 */
1501 ret->name = xmlStrdup(name);
1502 if (SystemID != NULL)
1503 ret->SystemID = xmlStrdup(SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001504 if (PublicID != NULL)
1505 ret->PublicID = xmlStrdup(PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001506 table->nb_notations++;
1507
1508 return(ret);
1509}
1510
1511/**
1512 * xmlFreeNotation:
1513 * @not: A notation
1514 *
1515 * Deallocate the memory used by an notation definition
1516 */
1517void
1518xmlFreeNotation(xmlNotationPtr nota) {
1519 if (nota == NULL) return;
1520 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001521 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001522 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001523 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001524 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001525 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001526 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001527 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001528}
1529
1530/**
1531 * xmlFreeNotationTable:
1532 * @table: An notation table
1533 *
1534 * Deallocate the memory used by an entities hash table.
1535 */
1536void
1537xmlFreeNotationTable(xmlNotationTablePtr table) {
1538 int i;
1539
1540 if (table == NULL) return;
1541
1542 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001543 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001544 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001545 xmlFree(table->table);
1546 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001547}
1548
1549/**
1550 * xmlCopyNotationTable:
1551 * @table: A notation table
1552 *
1553 * Build a copy of a notation table.
1554 *
1555 * Returns the new xmlNotationTablePtr or NULL in case of error.
1556 */
1557xmlNotationTablePtr
1558xmlCopyNotationTable(xmlNotationTablePtr table) {
1559 xmlNotationTablePtr ret;
1560 xmlNotationPtr cur, nota;
1561 int i;
1562
Daniel Veillard6454aec1999-09-02 22:04:43 +00001563 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001564 if (ret == NULL) {
1565 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1566 return(NULL);
1567 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001568 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001569 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001570 if (ret->table == NULL) {
1571 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001572 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001573 return(NULL);
1574 }
1575 ret->max_notations = table->max_notations;
1576 ret->nb_notations = table->nb_notations;
1577 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001578 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001579 if (cur == NULL) {
1580 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001581 xmlFree(ret);
1582 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001583 return(NULL);
1584 }
1585 ret->table[i] = cur;
1586 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001587 if (nota->name != NULL)
1588 cur->name = xmlStrdup(nota->name);
1589 else
1590 cur->name = NULL;
1591 if (nota->PublicID != NULL)
1592 cur->PublicID = xmlStrdup(nota->PublicID);
1593 else
1594 cur->PublicID = NULL;
1595 if (nota->SystemID != NULL)
1596 cur->SystemID = xmlStrdup(nota->SystemID);
1597 else
1598 cur->SystemID = NULL;
1599 }
1600 return(ret);
1601}
1602
1603/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001604 * xmlDumpNotationDecl:
1605 * @buf: the XML buffer output
1606 * @nota: A notation declaration
1607 *
1608 * This will dump the content the notation declaration as an XML DTD definition
1609 */
1610void
1611xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
1612 xmlBufferWriteChar(buf, "<!NOTATION ");
1613 xmlBufferWriteCHAR(buf, nota->name);
1614 if (nota->PublicID != NULL) {
1615 xmlBufferWriteChar(buf, " PUBLIC ");
1616 xmlBufferWriteQuotedString(buf, nota->PublicID);
1617 if (nota->SystemID != NULL) {
1618 xmlBufferWriteChar(buf, " ");
1619 xmlBufferWriteCHAR(buf, nota->SystemID);
1620 }
1621 } else {
1622 xmlBufferWriteChar(buf, " SYSTEM ");
1623 xmlBufferWriteCHAR(buf, nota->SystemID);
1624 }
1625 xmlBufferWriteChar(buf, " >\n");
1626}
1627
1628/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001629 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001630 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001631 * @table: A notation table
1632 *
1633 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001634 */
1635void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001636xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001637 int i;
1638 xmlNotationPtr cur;
1639
1640 if (table == NULL) return;
1641
1642 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001643 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001644 xmlDumpNotationDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001645 }
1646}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001647
1648/************************************************************************
1649 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001650 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001651 * *
1652 ************************************************************************/
1653/**
1654 * xmlCreateIDTable:
1655 *
1656 * create and initialize an empty id hash table.
1657 *
1658 * Returns the xmlIDTablePtr just created or NULL in case
1659 * of error.
1660 */
1661xmlIDTablePtr
1662xmlCreateIDTable(void) {
1663 xmlIDTablePtr ret;
1664
1665 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001666 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001667 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001668 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001669 (long)sizeof(xmlIDTable));
1670 return(NULL);
1671 }
1672 ret->max_ids = XML_MIN_NOTATION_TABLE;
1673 ret->nb_ids = 0;
1674 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001675 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001676 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001677 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001678 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001679 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001680 return(NULL);
1681 }
1682 return(ret);
1683}
1684
1685
1686/**
1687 * xmlAddID:
1688 * @ctxt: the validation context
1689 * @doc: pointer to the document
1690 * @value: the value name
1691 * @attr: the attribute holding the ID
1692 *
1693 * Register a new id declaration
1694 *
1695 * Returns NULL if not, othervise the new xmlIDPtr
1696 */
1697xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001698xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001699 xmlAttrPtr attr) {
1700 xmlIDPtr ret, cur;
1701 xmlIDTablePtr table;
1702 int i;
1703
1704 if (doc == NULL) {
1705 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1706 return(NULL);
1707 }
1708 if (value == NULL) {
1709 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1710 return(NULL);
1711 }
1712 if (attr == NULL) {
1713 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1714 return(NULL);
1715 }
1716
1717 /*
1718 * Create the ID table if needed.
1719 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001720 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001721 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001722 doc->ids = table = xmlCreateIDTable();
Daniel Veillard991e63d1999-08-15 23:32:28 +00001723 if (table == NULL) {
1724 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1725 return(NULL);
1726 }
1727
1728 /*
1729 * Validity Check:
1730 * Search the DTD for previous declarations of the ATTLIST
1731 */
1732 for (i = 0;i < table->nb_ids;i++) {
1733 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001734 if (xmlStrEqual(cur->value, value)) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001735 /*
1736 * The id is already defined in this Dtd.
1737 */
1738 VERROR(ctxt->userData, "ID %s already defined\n", value);
1739 return(NULL);
1740 }
1741 }
1742
1743 /*
1744 * Grow the table, if needed.
1745 */
1746 if (table->nb_ids >= table->max_ids) {
1747 /*
1748 * need more ids.
1749 */
1750 table->max_ids *= 2;
1751 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001752 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001753 sizeof(xmlIDPtr));
1754 if (table->table == NULL) {
1755 fprintf(stderr, "xmlAddID: out of memory\n");
1756 return(NULL);
1757 }
1758 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001759 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001760 if (ret == NULL) {
1761 fprintf(stderr, "xmlAddID: out of memory\n");
1762 return(NULL);
1763 }
1764 table->table[table->nb_ids] = ret;
1765
1766 /*
1767 * fill the structure.
1768 */
1769 ret->value = xmlStrdup(value);
1770 ret->attr = attr;
1771 table->nb_ids++;
1772
1773 return(ret);
1774}
1775
1776/**
1777 * xmlFreeID:
1778 * @not: A id
1779 *
1780 * Deallocate the memory used by an id definition
1781 */
1782void
1783xmlFreeID(xmlIDPtr id) {
1784 if (id == NULL) return;
1785 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001786 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001787 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001788 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001789}
1790
1791/**
1792 * xmlFreeIDTable:
1793 * @table: An id table
1794 *
1795 * Deallocate the memory used by an ID hash table.
1796 */
1797void
1798xmlFreeIDTable(xmlIDTablePtr table) {
1799 int i;
1800
1801 if (table == NULL) return;
1802
1803 for (i = 0;i < table->nb_ids;i++) {
1804 xmlFreeID(table->table[i]);
1805 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001806 xmlFree(table->table);
1807 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001808}
1809
1810/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001811 * xmlIsID:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001812 * @doc: the document
1813 * @elem: the element carrying the attribute
1814 * @attr: the attribute
1815 *
1816 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1817 * then this is simple, otherwise we use an heuristic: name ID (upper
1818 * or lowercase).
1819 *
1820 * Returns 0 or 1 depending on the lookup result
1821 */
1822int
1823xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00001824 if (doc == NULL) return(0);
1825 if (attr == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001826 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillarde8282ed2000-10-10 23:01:31 +00001827 return(0);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001828 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001829 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
1830 (xmlStrEqual(BAD_CAST "name", attr->name)))
Daniel Veillard71b656e2000-01-05 14:46:17 +00001831 return(1);
1832 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001833 } else {
1834 xmlAttributePtr attrDecl;
1835
Daniel Veillard71b656e2000-01-05 14:46:17 +00001836 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001837 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1838 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1839 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1840 attr->name);
1841
Daniel Veillardcf461992000-03-14 18:30:20 +00001842 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001843 return(1);
1844 }
1845 return(0);
1846}
1847
Daniel Veillardb96e6431999-08-29 21:02:19 +00001848/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001849 * xmlRemoveID
1850 * @doc: the document
1851 * @attr: the attribute
1852 *
1853 * Remove the given attribute from the ID table maintained internally.
1854 *
1855 * Returns -1 if the lookup failed and 0 otherwise
1856 */
1857int
1858xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1859 xmlIDPtr cur;
1860 xmlIDTablePtr table;
1861 int i;
1862
1863 if (doc == NULL) return(-1);
1864 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001865 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001866 if (table == NULL)
1867 return(-1);
1868
1869 /*
1870 * Search the ID list.
1871 */
1872 for (i = 0;i < table->nb_ids;i++) {
1873 cur = table->table[i];
1874 if (cur->attr == attr) {
1875 table->nb_ids--;
1876 memmove(&table->table[i], &table->table[i+1],
1877 (table->nb_ids - i) * sizeof(xmlIDPtr));
1878 return(0);
1879 }
1880 }
1881 return(-1);
1882}
1883
1884/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001885 * xmlGetID:
1886 * @doc: pointer to the document
1887 * @ID: the ID value
1888 *
1889 * Search the attribute declaring the given ID
1890 *
1891 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1892 */
1893xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001894xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001895 xmlIDPtr cur;
1896 xmlIDTablePtr table;
1897 int i;
1898
1899 if (doc == NULL) {
1900 fprintf(stderr, "xmlGetID: doc == NULL\n");
1901 return(NULL);
1902 }
1903
1904 if (ID == NULL) {
1905 fprintf(stderr, "xmlGetID: ID == NULL\n");
1906 return(NULL);
1907 }
1908
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001909 table = (xmlIDTablePtr) doc->ids;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001910 if (table == NULL)
1911 return(NULL);
1912
1913 /*
1914 * Search the ID list.
1915 */
1916 for (i = 0;i < table->nb_ids;i++) {
1917 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001918 if (xmlStrEqual(cur->value, ID)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001919 return(cur->attr);
1920 }
1921 }
1922 return(NULL);
1923}
1924
Daniel Veillard991e63d1999-08-15 23:32:28 +00001925/************************************************************************
1926 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001927 * Refs *
1928 * *
1929 ************************************************************************/
1930/**
1931 * xmlCreateRefTable:
1932 *
1933 * create and initialize an empty ref hash table.
1934 *
1935 * Returns the xmlRefTablePtr just created or NULL in case
1936 * of error.
1937 */
1938xmlRefTablePtr
1939xmlCreateRefTable(void) {
1940 xmlRefTablePtr ret;
1941
1942 ret = (xmlRefTablePtr)
1943 xmlMalloc(sizeof(xmlRefTable));
1944 if (ret == NULL) {
1945 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1946 (long)sizeof(xmlRefTable));
1947 return(NULL);
1948 }
1949 ret->max_refs = XML_MIN_NOTATION_TABLE;
1950 ret->nb_refs = 0;
1951 ret->table = (xmlRefPtr *)
1952 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001953 if (ret->table == NULL) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001954 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1955 ret->max_refs * (long)sizeof(xmlRef));
1956 xmlFree(ret);
1957 return(NULL);
1958 }
1959 return(ret);
1960}
1961
1962
1963/**
1964 * xmlAddRef:
1965 * @ctxt: the validation context
1966 * @doc: pointer to the document
1967 * @value: the value name
1968 * @attr: the attribute holding the Ref
1969 *
1970 * Register a new ref declaration
1971 *
1972 * Returns NULL if not, othervise the new xmlRefPtr
1973 */
1974xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001975xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001976 xmlAttrPtr attr) {
1977 xmlRefPtr ret;
1978 xmlRefTablePtr table;
1979
1980 if (doc == NULL) {
1981 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1982 return(NULL);
1983 }
1984 if (value == NULL) {
1985 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1986 return(NULL);
1987 }
1988 if (attr == NULL) {
1989 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1990 return(NULL);
1991 }
1992
1993 /*
1994 * Create the Ref table if needed.
1995 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001996 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001997 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001998 doc->refs = table = xmlCreateRefTable();
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001999 if (table == NULL) {
2000 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
2001 return(NULL);
2002 }
2003
2004 /*
2005 * Grow the table, if needed.
2006 */
2007 if (table->nb_refs >= table->max_refs) {
2008 /*
2009 * need more refs.
2010 */
2011 table->max_refs *= 2;
2012 table->table = (xmlRefPtr *)
2013 xmlRealloc(table->table, table->max_refs *
2014 sizeof(xmlRefPtr));
2015 if (table->table == NULL) {
2016 fprintf(stderr, "xmlAddRef: out of memory\n");
2017 return(NULL);
2018 }
2019 }
2020 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2021 if (ret == NULL) {
2022 fprintf(stderr, "xmlAddRef: out of memory\n");
2023 return(NULL);
2024 }
2025 table->table[table->nb_refs] = ret;
2026
2027 /*
2028 * fill the structure.
2029 */
2030 ret->value = xmlStrdup(value);
2031 ret->attr = attr;
2032 table->nb_refs++;
2033
2034 return(ret);
2035}
2036
2037/**
2038 * xmlFreeRef:
2039 * @not: A ref
2040 *
2041 * Deallocate the memory used by an ref definition
2042 */
2043void
2044xmlFreeRef(xmlRefPtr ref) {
2045 if (ref == NULL) return;
2046 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002047 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002048 memset(ref, -1, sizeof(xmlRef));
2049 xmlFree(ref);
2050}
2051
2052/**
2053 * xmlFreeRefTable:
2054 * @table: An ref table
2055 *
2056 * Deallocate the memory used by an Ref hash table.
2057 */
2058void
2059xmlFreeRefTable(xmlRefTablePtr table) {
2060 int i;
2061
2062 if (table == NULL) return;
2063
2064 for (i = 0;i < table->nb_refs;i++) {
2065 xmlFreeRef(table->table[i]);
2066 }
2067 xmlFree(table->table);
2068 xmlFree(table);
2069}
2070
2071/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002072 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002073 * @doc: the document
2074 * @elem: the element carrying the attribute
2075 * @attr: the attribute
2076 *
2077 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
2078 * then this is simple, otherwise we use an heuristic: name Ref (upper
2079 * or lowercase).
2080 *
2081 * Returns 0 or 1 depending on the lookup result
2082 */
2083int
2084xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2085 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2086 return(0);
2087 /*******************
2088 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
2089 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
2090 (attr->name[2] == 0)) return(1);
2091 *******************/
Daniel Veillardd83eb822000-06-30 18:39:56 +00002092 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2093 /* TODO @@@ */
2094 return(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002095 } else {
2096 xmlAttributePtr attrDecl;
2097
2098 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2099 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2100 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2101 attr->name);
2102
Daniel Veillardcf461992000-03-14 18:30:20 +00002103 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002104 return(1);
2105 }
2106 return(0);
2107}
2108
2109/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002110 * xmlRemoveRef
2111 * @doc: the document
2112 * @attr: the attribute
2113 *
2114 * Remove the given attribute from the Ref table maintained internally.
2115 *
2116 * Returns -1 if the lookup failed and 0 otherwise
2117 */
2118int
2119xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2120 xmlRefPtr cur;
2121 xmlRefTablePtr table;
2122 int i;
2123
2124 if (doc == NULL) return(-1);
2125 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002126 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard71b656e2000-01-05 14:46:17 +00002127 if (table == NULL)
2128 return(-1);
2129
2130 /*
2131 * Search the Ref list.
2132 */
2133 for (i = 0;i < table->nb_refs;i++) {
2134 cur = table->table[i];
2135 if (cur->attr == attr) {
2136 table->nb_refs--;
2137 memmove(&table->table[i], &table->table[i+1],
2138 (table->nb_refs - i) * sizeof(xmlRefPtr));
2139 return(0);
2140 }
2141 }
2142 return(-1);
2143}
2144
2145/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002146 * xmlGetRef:
2147 * @doc: pointer to the document
2148 * @Ref: the Ref value
2149 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00002150 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002151 *
2152 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
2153 */
2154xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002155xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002156 xmlRefPtr cur;
2157 xmlRefTablePtr table;
2158 int i;
2159
2160 if (doc == NULL) {
2161 fprintf(stderr, "xmlGetRef: doc == NULL\n");
2162 return(NULL);
2163 }
2164
2165 if (Ref == NULL) {
2166 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
2167 return(NULL);
2168 }
2169
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002170 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002171 if (table == NULL)
2172 return(NULL);
2173
2174 /*
2175 * Search the Ref list.
2176 */
2177 for (i = 0;i < table->nb_refs;i++) {
2178 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002179 if (xmlStrEqual(cur->value, Ref)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002180 return(cur->attr);
2181 }
2182 }
2183 return(NULL);
2184}
2185
2186/************************************************************************
2187 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002188 * Routines for validity checking *
2189 * *
2190 ************************************************************************/
2191
2192/**
2193 * xmlGetDtdElementDesc:
2194 * @dtd: a pointer to the DtD to search
2195 * @name: the element name
2196 *
2197 * Search the Dtd for the description of this element
2198 *
2199 * returns the xmlElementPtr if found or NULL
2200 */
2201
2202xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002203xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002204 xmlElementTablePtr table;
2205 xmlElementPtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002206 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002207 int i;
2208
2209 if (dtd == NULL) return(NULL);
2210 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002211 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002212
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00002213 if ((table->last >= 0) && (table->last < table->nb_elements)) {
2214 cur = table->table[table->last];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002215 if (xmlStrEqual(cur->name, name))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002216 return(cur);
2217 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00002218 for (i = 0;i < table->nb_elements;i++) {
2219 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002220 if (xmlStrEqual(cur->name, name)) {
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00002221 table->last = i;
2222 return(cur);
2223 }
2224 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002225
2226 /*
2227 * Specific case if name is a QName.
2228 */
2229 uqname = xmlSplitQName2(name, &prefix);
2230 if (uqname == NULL) return(NULL);
2231
2232 for (i = 0;i < table->nb_elements;i++) {
2233 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002234 if ((xmlStrEqual(cur->name, uqname)) &&
Daniel Veillardbe803962000-06-28 23:40:59 +00002235 ((prefix == cur->prefix) ||
2236 ((prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002237 (xmlStrEqual(cur->prefix, prefix))))) {
Daniel Veillardbe803962000-06-28 23:40:59 +00002238 if (prefix != NULL) xmlFree(prefix);
2239 if (uqname != NULL) xmlFree(uqname);
2240 return(cur);
2241 }
2242 }
2243 if (prefix != NULL) xmlFree(prefix);
2244 if (uqname != NULL) xmlFree(uqname);
2245 return(NULL);
2246}
2247
2248/**
2249 * xmlGetDtdQElementDesc:
2250 * @dtd: a pointer to the DtD to search
2251 * @name: the element name
2252 * @prefix: the element namespace prefix
2253 *
2254 * Search the Dtd for the description of this element
2255 *
2256 * returns the xmlElementPtr if found or NULL
2257 */
2258
2259xmlElementPtr
2260xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2261 const xmlChar *prefix) {
2262 xmlElementTablePtr table;
2263 xmlElementPtr cur;
2264 int i;
2265
2266 if (dtd == NULL) return(NULL);
2267 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002268 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardbe803962000-06-28 23:40:59 +00002269
2270 for (i = 0;i < table->nb_elements;i++) {
2271 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002272 if (xmlStrEqual(cur->name, name) &&
Daniel Veillardbe803962000-06-28 23:40:59 +00002273 ((prefix == cur->prefix) ||
2274 ((prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002275 (xmlStrEqual(cur->prefix, prefix)))))
Daniel Veillardbe803962000-06-28 23:40:59 +00002276 return(cur);
2277 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002278 return(NULL);
2279}
2280
2281/**
2282 * xmlGetDtdAttrDesc:
2283 * @dtd: a pointer to the DtD to search
2284 * @elem: the element name
2285 * @name: the attribute name
2286 *
2287 * Search the Dtd for the description of this attribute on
2288 * this element.
2289 *
2290 * returns the xmlAttributePtr if found or NULL
2291 */
2292
2293xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002294xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002295 xmlAttributeTablePtr table;
Daniel Veillardb1059e22000-09-16 14:02:43 +00002296 xmlElementTablePtr etable;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002297 xmlAttributePtr cur;
Daniel Veillardb1059e22000-09-16 14:02:43 +00002298 xmlElementPtr ecur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002299 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002300 int i;
2301
2302 if (dtd == NULL) return(NULL);
2303 if (dtd->attributes == NULL) return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002304
Daniel Veillardb1059e22000-09-16 14:02:43 +00002305 /*
2306 * Faster lookup through the element table
2307 */
2308 etable = (xmlElementTablePtr) dtd->elements;
2309 if (etable != NULL) {
2310 for (i = 0;i < etable->nb_elements;i++) {
2311 ecur = etable->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002312 if (xmlStrEqual(ecur->name, elem)) {
Daniel Veillardb1059e22000-09-16 14:02:43 +00002313 cur = ecur->attributes;
2314 while (cur != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002315 if (xmlStrEqual(cur->name, name))
Daniel Veillardb1059e22000-09-16 14:02:43 +00002316 return(cur);
2317 cur = cur->nexth;
2318 }
2319 /* TODO: same accelerator for QNames !!! */
2320 break;
2321 }
2322 }
2323 }
2324 /*
2325 * Miss on the element table, retry on the attribute one
2326 */
2327
2328 table = (xmlAttributeTablePtr) dtd->attributes;
2329 if (table == NULL)
2330 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002331 for (i = 0;i < table->nb_attributes;i++) {
2332 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002333 if ((xmlStrEqual(cur->name, name)) &&
2334 (xmlStrEqual(cur->elem, elem)))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002335 return(cur);
2336 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002337
2338 /*
2339 * Specific case if name is a QName.
2340 */
2341 uqname = xmlSplitQName2(name, &prefix);
2342 if (uqname == NULL) return(NULL);
2343
2344 for (i = 0;i < table->nb_attributes;i++) {
2345 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002346 if ((xmlStrEqual(cur->name, uqname)) &&
2347 (xmlStrEqual(cur->elem, elem)) &&
Daniel Veillardbe803962000-06-28 23:40:59 +00002348 ((prefix == cur->prefix) ||
2349 ((prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002350 (xmlStrEqual(cur->prefix, prefix))))) {
Daniel Veillardbe803962000-06-28 23:40:59 +00002351 if (prefix != NULL) xmlFree(prefix);
2352 if (uqname != NULL) xmlFree(uqname);
2353 return(cur);
2354 }
2355 }
2356 if (prefix != NULL) xmlFree(prefix);
2357 if (uqname != NULL) xmlFree(uqname);
2358 return(NULL);
2359}
2360
2361/**
2362 * xmlGetDtdQAttrDesc:
2363 * @dtd: a pointer to the DtD to search
2364 * @elem: the element name
2365 * @name: the attribute name
2366 * @prefix: the attribute namespace prefix
2367 *
2368 * Search the Dtd for the description of this qualified attribute on
2369 * this element.
2370 *
2371 * returns the xmlAttributePtr if found or NULL
2372 */
2373
2374xmlAttributePtr
2375xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2376 const xmlChar *prefix) {
2377 xmlAttributeTablePtr table;
2378 xmlAttributePtr cur;
2379 int i;
2380
2381 if (dtd == NULL) return(NULL);
2382 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002383 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardbe803962000-06-28 23:40:59 +00002384
2385 for (i = 0;i < table->nb_attributes;i++) {
2386 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002387 if ((xmlStrEqual(cur->name, name)) &&
2388 (xmlStrEqual(cur->elem, elem)) &&
Daniel Veillardbe803962000-06-28 23:40:59 +00002389 ((prefix == cur->prefix) ||
2390 ((prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002391 (xmlStrEqual(cur->prefix, prefix)))))
Daniel Veillardbe803962000-06-28 23:40:59 +00002392 return(cur);
2393 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002394 return(NULL);
2395}
2396
2397/**
2398 * xmlGetDtdNotationDesc:
2399 * @dtd: a pointer to the DtD to search
2400 * @name: the notation name
2401 *
2402 * Search the Dtd for the description of this notation
2403 *
2404 * returns the xmlNotationPtr if found or NULL
2405 */
2406
2407xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002408xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002409 xmlNotationTablePtr table;
2410 xmlNotationPtr cur;
2411 int i;
2412
2413 if (dtd == NULL) return(NULL);
2414 if (dtd->notations == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002415 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002416
2417 for (i = 0;i < table->nb_notations;i++) {
2418 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002419 if (xmlStrEqual(cur->name, name))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002420 return(cur);
2421 }
2422 return(NULL);
2423}
2424
2425/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002426 * xmlValidateNotationUse:
2427 * @ctxt: the validation context
2428 * @doc: the document
2429 * @notationName: the notation name to check
2430 *
2431 * Validate that the given mame match a notation declaration.
2432 * - [ VC: Notation Declared ]
2433 *
2434 * returns 1 if valid or 0 otherwise
2435 */
2436
2437int
2438xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002439 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002440 xmlNotationPtr notaDecl;
2441 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2442
2443 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2444 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2445 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2446
2447 if (notaDecl == NULL) {
2448 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2449 notationName);
2450 return(0);
2451 }
2452 return(1);
2453}
2454
2455/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002456 * xmlIsMixedElement
2457 * @doc: the document
2458 * @name: the element name
2459 *
2460 * Search in the DtDs whether an element accept Mixed content (or ANY)
2461 * basically if it is supposed to accept text childs
2462 *
2463 * returns 0 if no, 1 if yes, and -1 if no element description is available
2464 */
2465
2466int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002467xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002468 xmlElementPtr elemDecl;
2469
2470 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2471
2472 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2473 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2474 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2475 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002476 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002477 case XML_ELEMENT_TYPE_ELEMENT:
2478 return(0);
2479 case XML_ELEMENT_TYPE_EMPTY:
2480 /*
2481 * return 1 for EMPTY since we want VC error to pop up
2482 * on <empty> </empty> for example
2483 */
2484 case XML_ELEMENT_TYPE_ANY:
2485 case XML_ELEMENT_TYPE_MIXED:
2486 return(1);
2487 }
2488 return(1);
2489}
2490
2491/**
2492 * xmlValidateNameValue:
2493 * @value: an Name value
2494 *
2495 * Validate that the given value match Name production
2496 *
2497 * returns 1 if valid or 0 otherwise
2498 */
2499
2500int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002501xmlValidateNameValue(const xmlChar *value) {
2502 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002503
2504 if (value == NULL) return(0);
2505 cur = value;
2506
2507 if (!IS_LETTER(*cur) && (*cur != '_') &&
2508 (*cur != ':')) {
2509 return(0);
2510 }
2511
2512 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2513 (*cur == '.') || (*cur == '-') ||
2514 (*cur == '_') || (*cur == ':') ||
2515 (IS_COMBINING(*cur)) ||
2516 (IS_EXTENDER(*cur)))
2517 cur++;
2518
2519 if (*cur != 0) return(0);
2520
2521 return(1);
2522}
2523
2524/**
2525 * xmlValidateNamesValue:
2526 * @value: an Names value
2527 *
2528 * Validate that the given value match Names production
2529 *
2530 * returns 1 if valid or 0 otherwise
2531 */
2532
2533int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002534xmlValidateNamesValue(const xmlChar *value) {
2535 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002536
2537 if (value == NULL) return(0);
2538 cur = value;
2539
2540 if (!IS_LETTER(*cur) && (*cur != '_') &&
2541 (*cur != ':')) {
2542 return(0);
2543 }
2544
2545 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2546 (*cur == '.') || (*cur == '-') ||
2547 (*cur == '_') || (*cur == ':') ||
2548 (IS_COMBINING(*cur)) ||
2549 (IS_EXTENDER(*cur)))
2550 cur++;
2551
2552 while (IS_BLANK(*cur)) {
2553 while (IS_BLANK(*cur)) cur++;
2554
2555 if (!IS_LETTER(*cur) && (*cur != '_') &&
2556 (*cur != ':')) {
2557 return(0);
2558 }
2559
2560 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2561 (*cur == '.') || (*cur == '-') ||
2562 (*cur == '_') || (*cur == ':') ||
2563 (IS_COMBINING(*cur)) ||
2564 (IS_EXTENDER(*cur)))
2565 cur++;
2566 }
2567
2568 if (*cur != 0) return(0);
2569
2570 return(1);
2571}
2572
2573/**
2574 * xmlValidateNmtokenValue:
2575 * @value: an Mntoken value
2576 *
2577 * Validate that the given value match Nmtoken production
2578 *
2579 * [ VC: Name Token ]
2580 *
2581 * returns 1 if valid or 0 otherwise
2582 */
2583
2584int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002585xmlValidateNmtokenValue(const xmlChar *value) {
2586 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002587
2588 if (value == NULL) return(0);
2589 cur = value;
2590
2591 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2592 (*cur != '.') && (*cur != '-') &&
2593 (*cur != '_') && (*cur != ':') &&
2594 (!IS_COMBINING(*cur)) &&
2595 (!IS_EXTENDER(*cur)))
2596 return(0);
2597
2598 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2599 (*cur == '.') || (*cur == '-') ||
2600 (*cur == '_') || (*cur == ':') ||
2601 (IS_COMBINING(*cur)) ||
2602 (IS_EXTENDER(*cur)))
2603 cur++;
2604
2605 if (*cur != 0) return(0);
2606
2607 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002608}
2609
2610/**
2611 * xmlValidateNmtokensValue:
2612 * @value: an Mntokens value
2613 *
2614 * Validate that the given value match Nmtokens production
2615 *
2616 * [ VC: Name Token ]
2617 *
2618 * returns 1 if valid or 0 otherwise
2619 */
2620
2621int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002622xmlValidateNmtokensValue(const xmlChar *value) {
2623 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002624
2625 if (value == NULL) return(0);
2626 cur = value;
2627
Daniel Veillardcf461992000-03-14 18:30:20 +00002628 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002629 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2630 (*cur != '.') && (*cur != '-') &&
2631 (*cur != '_') && (*cur != ':') &&
2632 (!IS_COMBINING(*cur)) &&
2633 (!IS_EXTENDER(*cur)))
2634 return(0);
2635
2636 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2637 (*cur == '.') || (*cur == '-') ||
2638 (*cur == '_') || (*cur == ':') ||
2639 (IS_COMBINING(*cur)) ||
2640 (IS_EXTENDER(*cur)))
2641 cur++;
2642
2643 while (IS_BLANK(*cur)) {
2644 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002645 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002646
2647 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2648 (*cur != '.') && (*cur != '-') &&
2649 (*cur != '_') && (*cur != ':') &&
2650 (!IS_COMBINING(*cur)) &&
2651 (!IS_EXTENDER(*cur)))
2652 return(0);
2653
2654 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2655 (*cur == '.') || (*cur == '-') ||
2656 (*cur == '_') || (*cur == ':') ||
2657 (IS_COMBINING(*cur)) ||
2658 (IS_EXTENDER(*cur)))
2659 cur++;
2660 }
2661
2662 if (*cur != 0) return(0);
2663
2664 return(1);
2665}
2666
2667/**
2668 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002669 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002670 * @doc: a document instance
2671 * @nota: a notation definition
2672 *
2673 * Try to validate a single notation definition
2674 * basically it does the following checks as described by the
2675 * XML-1.0 recommendation:
2676 * - it seems that no validity constraing exist on notation declarations
2677 * But this function get called anyway ...
2678 *
2679 * returns 1 if valid or 0 otherwise
2680 */
2681
2682int
2683xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2684 xmlNotationPtr nota) {
2685 int ret = 1;
2686
2687 return(ret);
2688}
2689
2690/**
2691 * xmlValidateAttributeValue:
2692 * @type: an attribute type
2693 * @value: an attribute value
2694 *
2695 * Validate that the given attribute value match the proper production
2696 *
2697 * [ VC: ID ]
2698 * Values of type ID must match the Name production....
2699 *
2700 * [ VC: IDREF ]
2701 * Values of type IDREF must match the Name production, and values
2702 * of type IDREFS must match Names ...
2703 *
2704 * [ VC: Entity Name ]
2705 * Values of type ENTITY must match the Name production, values
2706 * of type ENTITIES must match Names ...
2707 *
2708 * [ VC: Name Token ]
2709 * Values of type NMTOKEN must match the Nmtoken production; values
2710 * of type NMTOKENS must match Nmtokens.
2711 *
2712 * returns 1 if valid or 0 otherwise
2713 */
2714
2715int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002716xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002717 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002718 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002719 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002720 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002721 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002722 case XML_ATTRIBUTE_IDREF:
2723 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002724 case XML_ATTRIBUTE_NOTATION:
2725 return(xmlValidateNameValue(value));
2726 case XML_ATTRIBUTE_NMTOKENS:
2727 case XML_ATTRIBUTE_ENUMERATION:
2728 return(xmlValidateNmtokensValue(value));
2729 case XML_ATTRIBUTE_NMTOKEN:
2730 return(xmlValidateNmtokenValue(value));
2731 case XML_ATTRIBUTE_CDATA:
2732 break;
2733 }
2734 return(1);
2735}
2736
2737/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002738 * xmlValidateAttributeValue2:
2739 * @ctxt: the validation context
2740 * @doc: the document
2741 * @name: the attribute name (used for error reporting only)
2742 * @type: the attribute type
2743 * @value: the attribute value
2744 *
2745 * Validate that the given attribute value match a given type.
2746 * This typically cannot be done before having finished parsing
2747 * the subsets.
2748 *
2749 * [ VC: IDREF ]
2750 * Values of type IDREF must match one of the declared IDs
2751 * Values of type IDREFS must match a sequence of the declared IDs
2752 * each Name must match the value of an ID attribute on some element
2753 * in the XML document; i.e. IDREF values must match the value of
2754 * some ID attribute
2755 *
2756 * [ VC: Entity Name ]
2757 * Values of type ENTITY must match one declared entity
2758 * Values of type ENTITIES must match a sequence of declared entities
2759 *
2760 * [ VC: Notation Attributes ]
2761 * all notation names in the declaration must be declared.
2762 *
2763 * returns 1 if valid or 0 otherwise
2764 */
2765
2766int
2767xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2768 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2769 int ret = 1;
2770 switch (type) {
2771 case XML_ATTRIBUTE_IDREFS:
2772 case XML_ATTRIBUTE_IDREF:
2773 case XML_ATTRIBUTE_ID:
2774 case XML_ATTRIBUTE_NMTOKENS:
2775 case XML_ATTRIBUTE_ENUMERATION:
2776 case XML_ATTRIBUTE_NMTOKEN:
2777 case XML_ATTRIBUTE_CDATA:
2778 break;
2779 case XML_ATTRIBUTE_ENTITY: {
2780 xmlEntityPtr ent;
2781
2782 ent = xmlGetDocEntity(doc, value);
2783 if (ent == NULL) {
2784 VERROR(ctxt->userData,
2785 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2786 name, value);
2787 ret = 0;
2788 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2789 VERROR(ctxt->userData,
2790 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2791 name, value);
2792 ret = 0;
2793 }
2794 break;
2795 }
2796 case XML_ATTRIBUTE_ENTITIES: {
2797 xmlChar *dup, *nam = NULL, *cur, save;
2798 xmlEntityPtr ent;
2799
2800 dup = xmlStrdup(value);
2801 if (dup == NULL)
2802 return(0);
2803 cur = dup;
2804 while (*cur != 0) {
2805 nam = cur;
2806 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2807 save = *cur;
2808 *cur = 0;
2809 ent = xmlGetDocEntity(doc, nam);
2810 if (ent == NULL) {
2811 VERROR(ctxt->userData,
2812 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2813 name, nam);
2814 ret = 0;
2815 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2816 VERROR(ctxt->userData,
2817 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2818 name, nam);
2819 ret = 0;
2820 }
2821 if (save == 0)
2822 break;
2823 *cur = save;
2824 while (IS_BLANK(*cur)) cur++;
2825 }
2826 xmlFree(dup);
2827 break;
2828 }
2829 case XML_ATTRIBUTE_NOTATION: {
2830 xmlNotationPtr nota;
2831
2832 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2833 if ((nota == NULL) && (doc->extSubset != NULL))
2834 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2835
2836 if (nota == NULL) {
2837 VERROR(ctxt->userData,
2838 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2839 name, value);
2840 ret = 0;
2841 }
2842 break;
2843 }
2844 }
2845 return(ret);
2846}
2847
2848/**
2849 * xmlValidNormalizeAttributeValue:
2850 * @doc: the document
2851 * @elem: the parent
2852 * @name: the attribute name
2853 * @value: the attribute value
2854 *
2855 * Does the validation related extra step of the normalization of attribute
2856 * values:
2857 *
2858 * If the declared value is not CDATA, then the XML processor must further
2859 * process the normalized attribute value by discarding any leading and
2860 * trailing space (#x20) characters, and by replacing sequences of space
2861 * (#x20) characters by single space (#x20) character.
2862 *
2863 * returns a new normalized string if normalization is needed, NULL otherwise
2864 * the caller must free the returned value.
2865 */
2866
2867xmlChar *
2868xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2869 const xmlChar *name, const xmlChar *value) {
2870 xmlChar *ret, *dst;
2871 const xmlChar *src;
Daniel Veillardbe803962000-06-28 23:40:59 +00002872 xmlAttributePtr attrDecl = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002873
2874 if (doc == NULL) return(NULL);
2875 if (elem == NULL) return(NULL);
2876 if (name == NULL) return(NULL);
2877 if (value == NULL) return(NULL);
2878
Daniel Veillardbe803962000-06-28 23:40:59 +00002879 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2880 xmlChar qname[500];
2881#ifdef HAVE_SNPRINTF
2882 snprintf((char *) qname, sizeof(qname), "%s:%s",
2883 elem->ns->prefix, elem->name);
2884#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00002885 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00002886#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00002887 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00002888 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2889 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2890 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2891 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002892 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2893 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2894 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2895
2896 if (attrDecl == NULL)
2897 return(NULL);
2898 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2899 return(NULL);
2900
2901 ret = xmlStrdup(value);
2902 if (ret == NULL)
2903 return(NULL);
2904 src = value;
2905 dst = ret;
2906 while (*src == 0x20) src++;
2907 while (*src != 0) {
2908 if (*src == 0x20) {
2909 while (*src == 0x20) src++;
2910 if (*src != 0)
2911 *dst++ = 0x20;
2912 } else {
2913 *dst++ = *src++;
2914 }
2915 }
2916 *dst = 0;
2917 return(ret);
2918}
2919
2920/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002921 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002922 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002923 * @doc: a document instance
2924 * @attr: an attribute definition
2925 *
2926 * Try to validate a single attribute definition
2927 * basically it does the following checks as described by the
2928 * XML-1.0 recommendation:
2929 * - [ VC: Attribute Default Legal ]
2930 * - [ VC: Enumeration ]
2931 * - [ VC: ID Attribute Default ]
2932 *
2933 * The ID/IDREF uniqueness and matching are done separately
2934 *
2935 * returns 1 if valid or 0 otherwise
2936 */
2937
2938int
2939xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2940 xmlAttributePtr attr) {
2941 int ret = 1;
2942 int val;
2943 CHECK_DTD;
2944 if(attr == NULL) return(1);
2945
2946 /* Attribute Default Legal */
2947 /* Enumeration */
2948 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002949 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002950 if (val == 0) {
2951 VERROR(ctxt->userData,
2952 "Syntax of default value for attribute %s on %s is not valid\n",
2953 attr->name, attr->elem);
2954 }
2955 ret &= val;
2956 }
2957
2958 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002959 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002960 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2961 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2962 VERROR(ctxt->userData,
2963 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2964 attr->name, attr->elem);
2965 ret = 0;
2966 }
2967
Daniel Veillardb96e6431999-08-29 21:02:19 +00002968 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002969 if (attr->atype == XML_ATTRIBUTE_ID) {
2970 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002971
2972 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002973 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002974 attr->elem);
2975 if (elem != NULL) {
2976 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002977 } else {
2978 xmlAttributeTablePtr table;
2979 int i;
2980
2981 /*
2982 * The attribute may be declared in the internal subset and the
2983 * element in the external subset.
2984 */
2985 nbId = 0;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002986 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00002987 if (table != NULL) {
2988 for (i = 0;i < table->nb_attributes;i++) {
2989 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002990 (xmlStrEqual(table->table[i]->elem, attr->elem))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002991 nbId++;
2992 }
2993 }
2994 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002995 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002996 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002997 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002998 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2999 attr->elem, nbId, attr->name);
3000 } else if (doc->extSubset != NULL) {
3001 int extId = 0;
3002 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3003 if (elem != NULL) {
3004 extId = xmlScanIDAttributeDecl(NULL, elem);
3005 }
3006 if (extId > 1) {
3007 VERROR(ctxt->userData,
3008 "Element %s has %d ID attribute defined in the external subset : %s\n",
3009 attr->elem, extId, attr->name);
3010 } else if (extId + nbId > 1) {
3011 VERROR(ctxt->userData,
3012"Element %s has ID attributes defined in the internal and external subset : %s\n",
3013 attr->elem, attr->name);
3014 }
3015 }
3016 }
3017
3018 /* Validity Constraint: Enumeration */
3019 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3020 xmlEnumerationPtr tree = attr->tree;
3021 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003022 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003023 tree = tree->next;
3024 }
3025 if (tree == NULL) {
3026 VERROR(ctxt->userData,
3027"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
3028 attr->defaultValue, attr->name, attr->elem);
3029 ret = 0;
3030 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003031 }
3032
3033 return(ret);
3034}
3035
3036/**
3037 * xmlValidateElementDecl:
3038 * @ctxt: the validation context
3039 * @doc: a document instance
3040 * @elem: an element definition
3041 *
3042 * Try to validate a single element definition
3043 * basically it does the following checks as described by the
3044 * XML-1.0 recommendation:
3045 * - [ VC: One ID per Element Type ]
3046 * - [ VC: No Duplicate Types ]
3047 * - [ VC: Unique Element Type Declaration ]
3048 *
3049 * returns 1 if valid or 0 otherwise
3050 */
3051
3052int
3053xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3054 xmlElementPtr elem) {
3055 int ret = 1;
3056 xmlElementPtr tst;
3057
3058 CHECK_DTD;
3059
3060 if (elem == NULL) return(1);
3061
3062 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00003063 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003064 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003065 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003066
3067 cur = elem->content;
3068 while (cur != NULL) {
3069 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3070 if (cur->c1 == NULL) break;
3071 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3072 name = cur->c1->name;
3073 next = cur->c2;
3074 while (next != NULL) {
3075 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003076 if (xmlStrEqual(next->name, name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003077 VERROR(ctxt->userData,
3078 "Definition of %s has duplicate references of %s\n",
3079 elem->name, name);
3080 ret = 0;
3081 }
3082 break;
3083 }
3084 if (next->c1 == NULL) break;
3085 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003086 if (xmlStrEqual(next->c1->name, name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003087 VERROR(ctxt->userData,
3088 "Definition of %s has duplicate references of %s\n",
3089 elem->name, name);
3090 ret = 0;
3091 }
3092 next = next->c2;
3093 }
3094 }
3095 cur = cur->c2;
3096 }
3097 }
3098
3099 /* VC: Unique Element Type Declaration */
3100 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3101 if ((tst != NULL ) && (tst != elem)) {
3102 VERROR(ctxt->userData, "Redefinition of element %s\n",
3103 elem->name);
3104 ret = 0;
3105 }
3106 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3107 if ((tst != NULL ) && (tst != elem)) {
3108 VERROR(ctxt->userData, "Redefinition of element %s\n",
3109 elem->name);
3110 ret = 0;
3111 }
3112
3113 /* One ID per Element Type */
3114 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3115 ret = 0;
3116 }
3117 return(ret);
3118}
3119
3120/**
3121 * xmlValidateOneAttribute:
3122 * @ctxt: the validation context
3123 * @doc: a document instance
3124 * @elem: an element instance
3125 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00003126 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003127 *
3128 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00003129 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00003130 * XML-1.0 recommendation:
3131 * - [ VC: Attribute Value Type ]
3132 * - [ VC: Fixed Attribute Default ]
3133 * - [ VC: Entity Name ]
3134 * - [ VC: Name Token ]
3135 * - [ VC: ID ]
3136 * - [ VC: IDREF ]
3137 * - [ VC: Entity Name ]
3138 * - [ VC: Notation Attributes ]
3139 *
3140 * The ID/IDREF uniqueness and matching are done separately
3141 *
3142 * returns 1 if valid or 0 otherwise
3143 */
3144
3145int
3146xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003147 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003148 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00003149 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003150 int val;
3151 int ret = 1;
3152
3153 CHECK_DTD;
3154 if ((elem == NULL) || (elem->name == NULL)) return(0);
3155 if ((attr == NULL) || (attr->name == NULL)) return(0);
3156
Daniel Veillardbe803962000-06-28 23:40:59 +00003157 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3158 xmlChar qname[500];
3159#ifdef HAVE_SNPRINTF
3160 snprintf((char *) qname, sizeof(qname), "%s:%s",
3161 elem->ns->prefix, elem->name);
3162#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003163 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003164#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003165 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00003166 if (attr->ns != NULL) {
3167 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3168 attr->name, attr->ns->prefix);
3169 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3170 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3171 attr->name, attr->ns->prefix);
3172 } else {
3173 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3174 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3175 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3176 qname, attr->name);
3177 }
3178 }
3179 if (attrDecl == NULL) {
3180 if (attr->ns != NULL) {
3181 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3182 attr->name, attr->ns->prefix);
3183 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3184 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3185 attr->name, attr->ns->prefix);
3186 } else {
3187 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3188 elem->name, attr->name);
3189 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3190 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3191 elem->name, attr->name);
3192 }
3193 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003194
3195
3196 /* Validity Constraint: Attribute Value Type */
3197 if (attrDecl == NULL) {
3198 VERROR(ctxt->userData,
3199 "No declaration for attribute %s on element %s\n",
3200 attr->name, elem->name);
3201 return(0);
3202 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003203 attr->atype = attrDecl->atype;
3204
3205 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003206 if (val == 0) {
3207 VERROR(ctxt->userData,
3208 "Syntax of value for attribute %s on %s is not valid\n",
3209 attr->name, elem->name);
3210 ret = 0;
3211 }
3212
Daniel Veillardcf461992000-03-14 18:30:20 +00003213 /* Validity constraint: Fixed Attribute Default */
3214 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003215 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003216 VERROR(ctxt->userData,
3217 "Value for attribute %s on %s is differnt from default \"%s\"\n",
3218 attr->name, elem->name, attrDecl->defaultValue);
3219 ret = 0;
3220 }
3221 }
3222
Daniel Veillardb96e6431999-08-29 21:02:19 +00003223 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00003224 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003225 xmlAddID(ctxt, doc, value, attr);
3226 }
3227
Daniel Veillardcf461992000-03-14 18:30:20 +00003228 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3229 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003230 xmlAddRef(ctxt, doc, value, attr);
3231 }
3232
Daniel Veillardb05deb71999-08-10 19:04:08 +00003233 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00003234 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003235 xmlEnumerationPtr tree = attrDecl->tree;
3236 xmlNotationPtr nota;
3237
3238 /* First check that the given NOTATION was declared */
3239 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3240 if (nota == NULL)
3241 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3242
3243 if (nota == NULL) {
3244 VERROR(ctxt->userData,
3245 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3246 value, attr->name, elem->name);
3247 ret = 0;
3248 }
3249
3250 /* Second, verify that it's among the list */
3251 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003252 if (xmlStrEqual(tree->name, value)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003253 tree = tree->next;
3254 }
3255 if (tree == NULL) {
3256 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003257"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003258 value, attr->name, elem->name);
3259 ret = 0;
3260 }
3261 }
3262
3263 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00003264 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003265 xmlEnumerationPtr tree = attrDecl->tree;
3266 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003267 if (xmlStrEqual(tree->name, value)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003268 tree = tree->next;
3269 }
3270 if (tree == NULL) {
3271 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003272 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003273 value, attr->name, elem->name);
3274 ret = 0;
3275 }
3276 }
3277
3278 /* Fixed Attribute Default */
3279 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003280 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003281 VERROR(ctxt->userData,
3282 "Value for attribute %s on %s must be \"%s\"\n",
3283 attr->name, elem->name, attrDecl->defaultValue);
3284 ret = 0;
3285 }
3286
Daniel Veillardcf461992000-03-14 18:30:20 +00003287 /* Extra check for the attribute value */
3288 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3289 attrDecl->atype, value);
3290
Daniel Veillardb05deb71999-08-10 19:04:08 +00003291 return(ret);
3292}
3293
3294int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3295 xmlElementContentPtr cont);
3296
3297/**
3298 * xmlValidateElementTypeExpr:
3299 * @ctxt: the validation context
3300 * @child: pointer to the child list
3301 * @cont: pointer to the content declaration
3302 *
3303 * Try to validate the content of an element of type element
3304 * but don't handle the occurence factor
3305 *
3306 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3307 * also update child value in-situ.
3308 */
3309
3310int
3311xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3312 xmlElementContentPtr cont) {
3313 xmlNodePtr cur;
3314 int ret = 1;
3315
3316 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003317 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003318 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003319 if ((*child)->type == XML_ENTITY_REF_NODE) {
3320 /*
3321 * If there is an entity declared an it's not empty
3322 * Push the current node on the stack and process with the
3323 * entity content.
3324 */
3325 if (((*child)->children != NULL) &&
3326 ((*child)->children->children != NULL)) {
3327 nodeVPush(ctxt, *child);
3328 *child = (*child)->children->children;
3329 } else
3330 *child = (*child)->next;
3331 continue;
3332 }
Daniel Veillardcd429612000-10-11 15:57:05 +00003333 if (((*child)->type == XML_TEXT_NODE) &&
3334 (xmlIsBlankNode(*child)) &&
3335 ((cont->type == XML_ELEMENT_CONTENT_ELEMENT) ||
3336 (cont->type == XML_ELEMENT_CONTENT_SEQ) ||
3337 (cont->type == XML_ELEMENT_CONTENT_OR))) {
3338 *child = (*child)->next;
3339 continue;
3340 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003341 if ((*child)->type == XML_PI_NODE) {
3342 *child = (*child)->next;
3343 continue;
3344 }
3345 if ((*child)->type == XML_COMMENT_NODE) {
3346 *child = (*child)->next;
3347 continue;
3348 }
3349 else if ((*child)->type != XML_ELEMENT_NODE) {
3350 return(-1);
3351 }
3352 break;
3353 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003354 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003355 switch (cont->type) {
3356 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003357 if (*child == NULL) return(0);
3358 if ((*child)->type == XML_TEXT_NODE) return(1);
3359 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003360 case XML_ELEMENT_CONTENT_ELEMENT:
3361 if (*child == NULL) return(0);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003362 ret = (xmlStrEqual((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003363 if (ret == 1) {
3364 while ((*child)->next == NULL) {
3365 if (((*child)->parent != NULL) &&
3366 ((*child)->parent->type == XML_ENTITY_DECL)) {
3367 *child = nodeVPop(ctxt);
3368 } else
3369 break;
3370 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003371 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003372 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003373 return(ret);
3374 case XML_ELEMENT_CONTENT_OR:
3375 cur = *child;
3376 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3377 if (ret == -1) return(-1);
3378 if (ret == 1) {
3379 return(1);
3380 }
3381 /* rollback and retry the other path */
3382 *child = cur;
3383 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3384 if (ret == -1) return(-1);
3385 if (ret == 0) {
3386 *child = cur;
3387 return(0);
3388 }
3389 return(1);
3390 case XML_ELEMENT_CONTENT_SEQ:
3391 cur = *child;
3392 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3393 if (ret == -1) return(-1);
3394 if (ret == 0) {
3395 *child = cur;
3396 return(0);
3397 }
3398 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3399 if (ret == -1) return(-1);
3400 if (ret == 0) {
3401 *child = cur;
3402 return(0);
3403 }
3404 return(1);
3405 }
3406 return(ret);
3407}
3408
3409/**
3410 * xmlValidateElementTypeElement:
3411 * @ctxt: the validation context
3412 * @child: pointer to the child list
3413 * @cont: pointer to the content declaration
3414 *
3415 * Try to validate the content of an element of type element
3416 * yeah, Yet Another Regexp Implementation, and recursive
3417 *
3418 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3419 * also update child and content values in-situ.
3420 */
3421
3422int
3423xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3424 xmlElementContentPtr cont) {
3425 xmlNodePtr cur;
3426 int ret = 1;
3427
3428 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003429
3430 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003431 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003432 if ((*child)->type == XML_ENTITY_REF_NODE) {
3433 /*
3434 * If there is an entity declared an it's not empty
3435 * Push the current node on the stack and process with the
3436 * entity content.
3437 */
3438 if (((*child)->children != NULL) &&
3439 ((*child)->children->children != NULL)) {
3440 nodeVPush(ctxt, *child);
3441 *child = (*child)->children->children;
3442 } else
3443 *child = (*child)->next;
3444 continue;
3445 }
Daniel Veillardcd429612000-10-11 15:57:05 +00003446 if (((*child)->type == XML_TEXT_NODE) &&
3447 (xmlIsBlankNode(*child)) &&
3448 ((cont->type == XML_ELEMENT_CONTENT_ELEMENT) ||
3449 (cont->type == XML_ELEMENT_CONTENT_SEQ) ||
3450 (cont->type == XML_ELEMENT_CONTENT_OR))) {
3451 *child = (*child)->next;
3452 continue;
3453 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003454 if ((*child)->type == XML_PI_NODE) {
3455 *child = (*child)->next;
3456 continue;
3457 }
3458 if ((*child)->type == XML_COMMENT_NODE) {
3459 *child = (*child)->next;
3460 continue;
3461 }
3462 else if ((*child)->type != XML_ELEMENT_NODE) {
3463 return(-1);
3464 }
3465 break;
3466 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003467 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003468 cur = *child;
3469 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3470 if (ret == -1) return(-1);
3471 switch (cont->ocur) {
3472 case XML_ELEMENT_CONTENT_ONCE:
3473 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003474 /* skip ignorable elems */
3475 while ((*child != NULL) &&
3476 (((*child)->type == XML_PI_NODE) ||
3477 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003478 while ((*child)->next == NULL) {
3479 if (((*child)->parent != NULL) &&
3480 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3481 *child = (*child)->parent;
3482 } else
3483 break;
3484 }
3485 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003486 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003487 return(1);
3488 }
3489 *child = cur;
3490 return(0);
3491 case XML_ELEMENT_CONTENT_OPT:
3492 if (ret == 0) {
3493 *child = cur;
3494 return(1);
3495 }
3496 break;
3497 case XML_ELEMENT_CONTENT_MULT:
3498 if (ret == 0) {
3499 *child = cur;
3500 break;
3501 }
3502 /* no break on purpose */
3503 case XML_ELEMENT_CONTENT_PLUS:
3504 if (ret == 0) {
3505 *child = cur;
3506 return(0);
3507 }
3508 do {
3509 cur = *child;
3510 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3511 } while (ret == 1);
3512 if (ret == -1) return(-1);
3513 *child = cur;
3514 break;
3515 }
3516 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003517 if ((*child)->type == XML_ENTITY_REF_NODE) {
3518 /*
3519 * If there is an entity declared an it's not empty
3520 * Push the current node on the stack and process with the
3521 * entity content.
3522 */
3523 if (((*child)->children != NULL) &&
3524 ((*child)->children->children != NULL)) {
3525 nodeVPush(ctxt, *child);
3526 *child = (*child)->children->children;
3527 } else
3528 *child = (*child)->next;
3529 continue;
3530 }
Daniel Veillardcd429612000-10-11 15:57:05 +00003531 if (((*child)->type == XML_TEXT_NODE) &&
3532 (xmlIsBlankNode(*child)) &&
3533 ((cont->type == XML_ELEMENT_CONTENT_ELEMENT) ||
3534 (cont->type == XML_ELEMENT_CONTENT_SEQ) ||
3535 (cont->type == XML_ELEMENT_CONTENT_OR))) {
3536 *child = (*child)->next;
3537 continue;
3538 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003539 if ((*child)->type == XML_PI_NODE) {
3540 *child = (*child)->next;
3541 continue;
3542 }
3543 if ((*child)->type == XML_COMMENT_NODE) {
3544 *child = (*child)->next;
3545 continue;
3546 }
3547 else if ((*child)->type != XML_ELEMENT_NODE) {
3548 return(-1);
3549 }
3550 break;
3551 }
3552 return(1);
3553}
3554
3555/**
3556 * xmlSprintfElementChilds:
3557 * @buf: an output buffer
3558 * @content: An element
3559 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3560 *
3561 * This will dump the list of childs to the buffer
3562 * Intended just for the debug routine
3563 */
3564void
3565xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3566 xmlNodePtr cur;
3567
3568 if (node == NULL) return;
3569 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003570 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003571 while (cur != NULL) {
3572 switch (cur->type) {
3573 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003574 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003575 if (cur->next != NULL)
3576 strcat(buf, " ");
3577 break;
3578 case XML_TEXT_NODE:
Daniel Veillardcd429612000-10-11 15:57:05 +00003579 if (xmlIsBlankNode(cur))
3580 break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003581 case XML_CDATA_SECTION_NODE:
3582 case XML_ENTITY_REF_NODE:
3583 strcat(buf, "CDATA");
3584 if (cur->next != NULL)
3585 strcat(buf, " ");
3586 break;
3587 case XML_ATTRIBUTE_NODE:
3588 case XML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00003589#ifdef LIBXML_SGML_ENABLED
3590 case XML_SGML_DOCUMENT_NODE:
3591#endif
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003592 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003593 case XML_DOCUMENT_TYPE_NODE:
3594 case XML_DOCUMENT_FRAG_NODE:
3595 case XML_NOTATION_NODE:
3596 strcat(buf, "???");
3597 if (cur->next != NULL)
3598 strcat(buf, " ");
3599 break;
3600 case XML_ENTITY_NODE:
3601 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003602 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003603 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003604 case XML_ELEMENT_DECL:
3605 case XML_ATTRIBUTE_DECL:
3606 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003607 break;
3608 }
3609 cur = cur->next;
3610 }
3611 if (glob) strcat(buf, ")");
3612}
3613
3614
3615/**
3616 * xmlValidateOneElement:
3617 * @ctxt: the validation context
3618 * @doc: a document instance
3619 * @elem: an element instance
3620 *
3621 * Try to validate a single element and it's attributes,
3622 * basically it does the following checks as described by the
3623 * XML-1.0 recommendation:
3624 * - [ VC: Element Valid ]
3625 * - [ VC: Required Attribute ]
3626 * Then call xmlValidateOneAttribute() for each attribute present.
3627 *
3628 * The ID/IDREF checkings are done separately
3629 *
3630 * returns 1 if valid or 0 otherwise
3631 */
3632
3633int
3634xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3635 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003636 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003637 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003638 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003639 xmlNodePtr child;
3640 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003641 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003642
3643 CHECK_DTD;
3644
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003645 if (elem == NULL) return(0);
3646 if (elem->type == XML_TEXT_NODE) {
3647 }
3648 switch (elem->type) {
3649 case XML_ATTRIBUTE_NODE:
3650 VERROR(ctxt->userData,
3651 "Attribute element not expected here\n");
3652 return(0);
3653 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003654 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003655 VERROR(ctxt->userData, "Text element has childs !\n");
3656 return(0);
3657 }
3658 if (elem->properties != NULL) {
3659 VERROR(ctxt->userData, "Text element has attributes !\n");
3660 return(0);
3661 }
3662 if (elem->ns != NULL) {
3663 VERROR(ctxt->userData, "Text element has namespace !\n");
3664 return(0);
3665 }
Daniel Veillard87b95392000-08-12 21:12:04 +00003666 if (elem->nsDef != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003667 VERROR(ctxt->userData,
3668 "Text element carries namespace definitions !\n");
3669 return(0);
3670 }
3671 if (elem->content == NULL) {
3672 VERROR(ctxt->userData,
3673 "Text element has no content !\n");
3674 return(0);
3675 }
3676 return(1);
3677 case XML_CDATA_SECTION_NODE:
3678 case XML_ENTITY_REF_NODE:
3679 case XML_PI_NODE:
3680 case XML_COMMENT_NODE:
3681 return(1);
3682 case XML_ENTITY_NODE:
3683 VERROR(ctxt->userData,
3684 "Entity element not expected here\n");
3685 return(0);
3686 case XML_NOTATION_NODE:
3687 VERROR(ctxt->userData,
3688 "Notation element not expected here\n");
3689 return(0);
3690 case XML_DOCUMENT_NODE:
3691 case XML_DOCUMENT_TYPE_NODE:
3692 case XML_DOCUMENT_FRAG_NODE:
3693 VERROR(ctxt->userData,
3694 "Document element not expected here\n");
3695 return(0);
3696 case XML_HTML_DOCUMENT_NODE:
3697 VERROR(ctxt->userData,
3698 "\n");
3699 return(0);
3700 case XML_ELEMENT_NODE:
3701 break;
3702 default:
3703 VERROR(ctxt->userData,
3704 "unknown element type %d\n", elem->type);
3705 return(0);
3706 }
3707 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003708
Daniel Veillardbe803962000-06-28 23:40:59 +00003709 /*
3710 * Fetch the declaration for the qualified name
3711 */
3712 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3713 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3714 elem->name, elem->ns->prefix);
3715 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3716 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3717 elem->name, elem->ns->prefix);
3718 }
3719
3720 /*
3721 * Fetch the declaration for the non qualified name
3722 */
3723 if (elemDecl == NULL) {
3724 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3725 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3726 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3727 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003728 if (elemDecl == NULL) {
3729 VERROR(ctxt->userData, "No declaration for element %s\n",
3730 elem->name);
3731 return(0);
3732 }
3733
3734 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003735 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003736 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003737 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003738 VERROR(ctxt->userData,
3739 "Element %s was declared EMPTY this one has content\n",
3740 elem->name);
3741 ret = 0;
3742 }
3743 break;
3744 case XML_ELEMENT_TYPE_ANY:
3745 /* I don't think anything is required then */
3746 break;
3747 case XML_ELEMENT_TYPE_MIXED:
3748 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003749 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003750 while (child != NULL) {
3751 if (child->type == XML_ELEMENT_NODE) {
3752 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003753 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3754 xmlChar qname[500];
3755#ifdef HAVE_SNPRINTF
3756 snprintf((char *) qname, sizeof(qname), "%s:%s",
3757 child->ns->prefix, child->name);
3758#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003759 sprintf((char *) qname, "%s:%s",
3760 child->ns->prefix, child->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003761#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003762 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00003763 cont = elemDecl->content;
3764 while (cont != NULL) {
3765 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003766 if (xmlStrEqual(cont->name, qname)) break;
Daniel Veillardbe803962000-06-28 23:40:59 +00003767 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3768 (cont->c1 != NULL) &&
3769 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003770 if (xmlStrEqual(cont->c1->name, qname)) break;
Daniel Veillardbe803962000-06-28 23:40:59 +00003771 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3772 (cont->c1 == NULL) ||
3773 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3774 /* Internal error !!! */
3775 fprintf(stderr, "Internal: MIXED struct bad\n");
3776 break;
3777 }
3778 cont = cont->c2;
3779 }
3780 if (cont != NULL)
3781 goto child_ok;
3782 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003783 cont = elemDecl->content;
3784 while (cont != NULL) {
3785 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003786 if (xmlStrEqual(cont->name, name)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003787 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3788 (cont->c1 != NULL) &&
3789 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003790 if (xmlStrEqual(cont->c1->name, name)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003791 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3792 (cont->c1 == NULL) ||
3793 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3794 /* Internal error !!! */
3795 fprintf(stderr, "Internal: MIXED struct bad\n");
3796 break;
3797 }
3798 cont = cont->c2;
3799 }
3800 if (cont == NULL) {
3801 VERROR(ctxt->userData,
3802 "Element %s is not declared in %s list of possible childs\n",
3803 name, elem->name);
3804 ret = 0;
3805 }
3806 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003807child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003808 child = child->next;
3809 }
3810 break;
3811 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003812 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003813 cont = elemDecl->content;
3814 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3815 if ((ret == 0) || (child != NULL)) {
3816 char expr[1000];
3817 char list[2000];
3818
3819 expr[0] = 0;
3820 xmlSprintfElementContent(expr, cont, 1);
3821 list[0] = 0;
3822 xmlSprintfElementChilds(list, elem, 1);
3823
3824 VERROR(ctxt->userData,
3825 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3826 elem->name, expr, list);
3827 ret = 0;
3828 }
3829 break;
3830 }
3831
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003832 /* [ VC: Required Attribute ] */
3833 attr = elemDecl->attributes;
3834 while (attr != NULL) {
3835 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3836 xmlAttrPtr attrib;
3837 int qualified = -1;
3838
3839 attrib = elem->properties;
3840 while (attrib != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003841 if (xmlStrEqual(attrib->name, attr->name)) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003842 if (attr->prefix != NULL) {
3843 xmlNsPtr nameSpace = attrib->ns;
3844
3845 if (nameSpace == NULL)
3846 nameSpace = elem->ns;
3847 /*
3848 * qualified names handling is problematic, having a
3849 * different prefix should be possible but DTDs don't
3850 * allow to define the URI instead of the prefix :-(
3851 */
3852 if (nameSpace == NULL) {
3853 if (qualified < 0)
3854 qualified = 0;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003855 } else if (!xmlStrEqual(nameSpace->prefix, attr->prefix)) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003856 if (qualified < 1)
3857 qualified = 1;
3858 } else
3859 goto found;
3860 } else {
3861 /*
3862 * We should allow applications to define namespaces
3863 * for their application even if the DTD doesn't
3864 * carry one, otherwise, basically we would always
3865 * break.
3866 */
3867 goto found;
3868 }
3869 }
3870 attrib = attrib->next;
3871 }
3872 if (qualified == -1) {
3873 if (attr->prefix == NULL) {
3874 VERROR(ctxt->userData,
3875 "Element %s doesn't carry attribute %s\n",
3876 elem->name, attr->name);
3877 } else {
3878 VERROR(ctxt->userData,
3879 "Element %s doesn't carry attribute %s:%s\n",
3880 elem->name, attr->prefix,attr->name);
3881 }
3882 } else if (qualified == 0) {
3883 VWARNING(ctxt->userData,
3884 "Element %s required attribute %s:%s has no prefix\n",
3885 elem->name, attr->prefix,attr->name);
3886 } else if (qualified == 1) {
3887 VWARNING(ctxt->userData,
3888 "Element %s required attribute %s:%s has different prefix\n",
3889 elem->name, attr->prefix,attr->name);
3890 }
3891 }
3892found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003893 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003894 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003895 return(ret);
3896}
3897
3898/**
3899 * xmlValidateRoot:
3900 * @ctxt: the validation context
3901 * @doc: a document instance
3902 *
3903 * Try to validate a the root element
3904 * basically it does the following check as described by the
3905 * XML-1.0 recommendation:
3906 * - [ VC: Root Element Type ]
3907 * it doesn't try to recurse or apply other check to the element
3908 *
3909 * returns 1 if valid or 0 otherwise
3910 */
3911
3912int
3913xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003914 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003915 if (doc == NULL) return(0);
3916
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003917 root = xmlDocGetRootElement(doc);
3918 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003919 VERROR(ctxt->userData, "Not valid: no root element\n");
3920 return(0);
3921 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003922
3923 /*
Daniel Veillardcd429612000-10-11 15:57:05 +00003924 * When doing post validation against a separate DTD, those may
3925 * no internal subset has been generated
Daniel Veillardbe803962000-06-28 23:40:59 +00003926 */
Daniel Veillardcd429612000-10-11 15:57:05 +00003927 if ((doc->intSubset != NULL) &&
3928 (doc->intSubset->name != NULL)) {
3929 /*
3930 * Check first the document root against the NQName
3931 */
3932 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
3933 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3934 xmlChar qname[500];
Daniel Veillardbe803962000-06-28 23:40:59 +00003935#ifdef HAVE_SNPRINTF
Daniel Veillardcd429612000-10-11 15:57:05 +00003936 snprintf((char *) qname, sizeof(qname), "%s:%s",
3937 root->ns->prefix, root->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003938#else
Daniel Veillardcd429612000-10-11 15:57:05 +00003939 sprintf((char *) qname, "%s:%s", root->ns->prefix, root->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003940#endif
Daniel Veillardcd429612000-10-11 15:57:05 +00003941 qname[sizeof(qname) - 1] = 0;
3942 if (xmlStrEqual(doc->intSubset->name, qname))
3943 goto name_ok;
3944 }
3945 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
3946 (xmlStrEqual(root->name, BAD_CAST "html")))
Daniel Veillardbe803962000-06-28 23:40:59 +00003947 goto name_ok;
Daniel Veillardcd429612000-10-11 15:57:05 +00003948 VERROR(ctxt->userData,
3949 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3950 root->name, doc->intSubset->name);
3951 return(0);
3952
3953 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003954 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003955name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003956 return(1);
3957}
3958
3959
3960/**
3961 * xmlValidateElement:
3962 * @ctxt: the validation context
3963 * @doc: a document instance
3964 * @elem: an element instance
3965 *
3966 * Try to validate the subtree under an element
3967 *
3968 * returns 1 if valid or 0 otherwise
3969 */
3970
3971int
3972xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003973 xmlNodePtr child;
3974 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003975 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003976 int ret = 1;
3977
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003978 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003979 CHECK_DTD;
3980
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003981 ret &= xmlValidateOneElement(ctxt, doc, elem);
3982 attr = elem->properties;
3983 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003984 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003985 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3986 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003987 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003988 attr= attr->next;
3989 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003990 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003991 while (child != NULL) {
3992 ret &= xmlValidateElement(ctxt, doc, child);
3993 child = child->next;
3994 }
3995
3996 return(ret);
3997}
3998
3999/**
4000 * xmlValidateDocumentFinal:
4001 * @ctxt: the validation context
4002 * @doc: a document instance
4003 *
4004 * Does the final step for the document validation once all the
4005 * incremental validation steps have been completed
4006 *
4007 * basically it does the following checks described by the XML Rec
4008 *
4009 *
4010 * returns 1 if valid or 0 otherwise
4011 */
4012
4013int
4014xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4015 int ret = 1, i;
4016 xmlRefTablePtr table;
4017 xmlAttrPtr id;
4018
4019 if (doc == NULL) {
4020 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
4021 return(0);
4022 }
4023
4024 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00004025 * Check all the NOTATION/NOTATIONS attributes
4026 */
4027 /*
4028 * Check all the ENTITY/ENTITIES attributes definition for validity
4029 */
4030 /*
4031 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004032 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004033 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004034 if (table != NULL) {
4035 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004036 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
4037 id = xmlGetID(doc, table->table[i]->value);
4038 if (id == NULL) {
4039 VERROR(ctxt->userData,
4040 "IDREF attribute %s reference an unknown ID \"%s\"\n",
4041 table->table[i]->attr->name, table->table[i]->value);
4042 ret = 0;
4043 }
4044 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
4045 xmlChar *dup, *name = NULL, *cur, save;
4046
4047 dup = xmlStrdup(table->table[i]->value);
4048 if (dup == NULL)
4049 return(0);
4050 cur = dup;
4051 while (*cur != 0) {
4052 name = cur;
4053 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
4054 save = *cur;
4055 *cur = 0;
4056 id = xmlGetID(doc, name);
4057 if (id == NULL) {
4058 VERROR(ctxt->userData,
4059 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
4060 table->table[i]->attr->name, name);
4061 ret = 0;
4062 }
4063 if (save == 0)
4064 break;
4065 *cur = save;
4066 while (IS_BLANK(*cur)) cur++;
4067 }
4068 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004069 }
4070 }
4071 }
4072 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004073}
4074
4075/**
4076 * xmlValidateDtd:
4077 * @ctxt: the validation context
4078 * @doc: a document instance
4079 * @dtd: a dtd instance
4080 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004081 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00004082 *
4083 * basically it does check all the definitions in the DtD.
4084 *
4085 * returns 1 if valid or 0 otherwise
4086 */
4087
4088int
4089xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004090 int ret;
4091 xmlDtdPtr oldExt;
4092 xmlNodePtr root;
4093
4094 if (dtd == NULL) return(0);
4095 if (doc == NULL) return(0);
4096 oldExt = doc->extSubset;
4097 doc->extSubset = dtd;
4098 ret = xmlValidateRoot(ctxt, doc);
4099 if (ret == 0) {
4100 doc->extSubset = oldExt;
4101 return(ret);
4102 }
4103 root = xmlDocGetRootElement(doc);
4104 ret = xmlValidateElement(ctxt, doc, root);
4105 ret &= xmlValidateDocumentFinal(ctxt, doc);
4106 doc->extSubset = oldExt;
4107 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004108}
4109
4110/**
Daniel Veillardcf461992000-03-14 18:30:20 +00004111 * xmlValidateDtdFinal:
4112 * @ctxt: the validation context
4113 * @doc: a document instance
4114 *
4115 * Does the final step for the dtds validation once all the
4116 * subsets have been parsed
4117 *
4118 * basically it does the following checks described by the XML Rec
4119 * - check that ENTITY and ENTITIES type attributes default or
4120 * possible values matches one of the defined entities.
4121 * - check that NOTATION type attributes default or
4122 * possible values matches one of the defined notations.
4123 *
4124 * returns 1 if valid or 0 otherwise
4125 */
4126
4127int
4128xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4129 int ret = 1, i;
4130 xmlDtdPtr dtd;
4131 xmlAttributeTablePtr table;
4132 xmlAttributePtr cur;
4133
4134 if (doc == NULL) return(0);
4135 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4136 return(0);
4137 dtd = doc->intSubset;
4138 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004139 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004140
4141 for (i = 0;i < table->nb_attributes;i++) {
4142 cur = table->table[i];
4143 switch (cur->atype) {
4144 case XML_ATTRIBUTE_CDATA:
4145 case XML_ATTRIBUTE_ID:
4146 case XML_ATTRIBUTE_IDREF :
4147 case XML_ATTRIBUTE_IDREFS:
4148 case XML_ATTRIBUTE_NMTOKEN:
4149 case XML_ATTRIBUTE_NMTOKENS:
4150 case XML_ATTRIBUTE_ENUMERATION:
4151 break;
4152 case XML_ATTRIBUTE_ENTITY:
4153 case XML_ATTRIBUTE_ENTITIES:
4154 case XML_ATTRIBUTE_NOTATION:
4155 if (cur->defaultValue != NULL) {
4156 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4157 cur->atype, cur->defaultValue);
4158 }
4159 if (cur->tree != NULL) {
4160 xmlEnumerationPtr tree = cur->tree;
4161 while (tree != NULL) {
4162 ret &= xmlValidateAttributeValue2(ctxt, doc,
4163 cur->name, cur->atype, tree->name);
4164 tree = tree->next;
4165 }
4166 }
4167 }
4168 }
4169 }
4170 dtd = doc->extSubset;
4171 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004172 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004173
4174 for (i = 0;i < table->nb_attributes;i++) {
4175 cur = table->table[i];
4176 switch (cur->atype) {
4177 case XML_ATTRIBUTE_CDATA:
4178 case XML_ATTRIBUTE_ID:
4179 case XML_ATTRIBUTE_IDREF :
4180 case XML_ATTRIBUTE_IDREFS:
4181 case XML_ATTRIBUTE_NMTOKEN:
4182 case XML_ATTRIBUTE_NMTOKENS:
4183 case XML_ATTRIBUTE_ENUMERATION:
4184 break;
4185 case XML_ATTRIBUTE_ENTITY:
4186 case XML_ATTRIBUTE_ENTITIES:
4187 case XML_ATTRIBUTE_NOTATION:
4188 if (cur->defaultValue != NULL) {
4189 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4190 cur->atype, cur->defaultValue);
4191 }
4192 if (cur->tree != NULL) {
4193 xmlEnumerationPtr tree = cur->tree;
4194 while (tree != NULL) {
4195 ret &= xmlValidateAttributeValue2(ctxt, doc,
4196 cur->name, cur->atype, tree->name);
4197 tree = tree->next;
4198 }
4199 }
4200 }
4201 }
4202 }
4203 return(ret);
4204}
4205
4206/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00004207 * xmlValidateDocument:
4208 * @ctxt: the validation context
4209 * @doc: a document instance
4210 *
4211 * Try to validate the document instance
4212 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004213 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00004214 * i.e. validates the internal and external subset (if present)
4215 * and validate the document tree.
4216 *
4217 * returns 1 if valid or 0 otherwise
4218 */
4219
4220int
4221xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004222 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004223 xmlNodePtr root;
4224
4225 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4226 return(0);
4227 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4228 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4229 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4230 doc->intSubset->SystemID);
4231 if (doc->extSubset == NULL) {
4232 if (doc->intSubset->SystemID != NULL) {
4233 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004234 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004235 doc->intSubset->SystemID);
4236 } else {
4237 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004238 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004239 doc->intSubset->ExternalID);
4240 }
4241 return(0);
4242 }
4243 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004244
Daniel Veillardcf461992000-03-14 18:30:20 +00004245 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004246 if (!xmlValidateRoot(ctxt, doc)) return(0);
4247
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004248 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00004249 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004250 ret &= xmlValidateDocumentFinal(ctxt, doc);
4251 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004252}
4253
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004254
4255/************************************************************************
4256 * *
4257 * Routines for dynamic validation editing *
4258 * *
4259 ************************************************************************/
4260
4261/**
4262 * xmlValidGetPotentialChildren:
4263 * @ctree: an element content tree
4264 * @list: an array to store the list of child names
4265 * @len: a pointer to the number of element in the list
4266 * @max: the size of the array
4267 *
4268 * Build/extend a list of potential children allowed by the content tree
4269 *
4270 * returns the number of element in the list, or -1 in case of error.
4271 */
4272
4273int
4274xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4275 int *len, int max) {
4276 int i;
4277
4278 if ((ctree == NULL) || (list == NULL) || (len == NULL))
4279 return(-1);
4280 if (*len >= max) return(*len);
4281
4282 switch (ctree->type) {
4283 case XML_ELEMENT_CONTENT_PCDATA:
4284 for (i = 0; i < *len;i++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004285 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
Daniel Veillarda819dac1999-11-24 18:04:22 +00004286 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004287 break;
4288 case XML_ELEMENT_CONTENT_ELEMENT:
4289 for (i = 0; i < *len;i++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004290 if (xmlStrEqual(ctree->name, list[i])) return(*len);
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004291 list[(*len)++] = ctree->name;
4292 break;
4293 case XML_ELEMENT_CONTENT_SEQ:
4294 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4295 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4296 break;
4297 case XML_ELEMENT_CONTENT_OR:
4298 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4299 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4300 break;
4301 }
4302
4303 return(*len);
4304}
4305
4306/**
4307 * xmlValidGetValidElements:
4308 * @prev: an element to insert after
4309 * @next: an element to insert next
4310 * @list: an array to store the list of child names
4311 * @max: the size of the array
4312 *
4313 * This function returns the list of authorized children to insert
4314 * within an existing tree while respecting the validity constraints
4315 * forced by the Dtd. The insertion point is defined using @prev and
4316 * @next in the following ways:
4317 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4318 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4319 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4320 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4321 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4322 *
4323 * pointers to the element names are inserted at the beginning of the array
4324 * and do not need to be freed.
4325 *
4326 * returns the number of element in the list, or -1 in case of error. If
4327 * the function returns the value @max the caller is invited to grow the
4328 * receiving array and retry.
4329 */
4330
4331int
4332xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4333 int max) {
4334 int nb_valid_elements = 0;
4335 const xmlChar *elements[256];
4336 int nb_elements = 0, i;
4337
4338 xmlNode *ref_node;
4339 xmlNode *parent;
4340 xmlNode *test_node;
4341
4342 xmlNode *prev_next;
4343 xmlNode *next_prev;
4344 xmlNode *parent_childs;
4345 xmlNode *parent_last;
4346
4347 xmlElement *element_desc;
4348
4349 if (prev == NULL && next == NULL)
4350 return(-1);
4351
4352 if (list == NULL) return(-1);
4353 if (max <= 0) return(-1);
4354
4355 nb_valid_elements = 0;
4356 ref_node = prev ? prev : next;
4357 parent = ref_node->parent;
4358
4359 /*
4360 * Retrieves the parent element declaration
4361 */
4362 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4363 parent->name);
4364 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4365 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4366 parent->name);
4367 if (element_desc == NULL) return(-1);
4368
4369 /*
4370 * Do a backup of the current tree structure
4371 */
4372 prev_next = prev ? prev->next : NULL;
4373 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004374 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004375 parent_last = parent->last;
4376
4377 /*
4378 * Creates a dummy node and insert it into the tree
4379 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004380 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004381 test_node->doc = ref_node->doc;
4382 test_node->parent = parent;
4383 test_node->prev = prev;
4384 test_node->next = next;
4385
4386 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00004387 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004388
4389 if (next) next->prev = test_node;
4390 else parent->last = test_node;
4391
4392 /*
4393 * Insert each potential child node and check if the parent is
4394 * still valid
4395 */
4396 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4397 elements, &nb_elements, 256);
4398
4399 for (i = 0;i < nb_elements;i++) {
4400 test_node->name = elements[i];
4401 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4402 int j;
4403
4404 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004405 if (xmlStrEqual(elements[i], list[j])) break;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004406 list[nb_valid_elements++] = elements[i];
4407 if (nb_valid_elements >= max) break;
4408 }
4409 }
4410
4411 /*
4412 * Restore the tree structure
4413 */
4414 if (prev) prev->next = prev_next;
4415 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004416 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004417 parent->last = parent_last;
4418
4419 return(nb_valid_elements);
4420}