blob: 7aa76abea4e94e86f9d6db5947ee89e1d9d232d3 [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); \
152 else if (doc->intSubset == NULL) return(0)
153
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000154xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
155xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000156
Daniel Veillardbe803962000-06-28 23:40:59 +0000157/************************************************************************
158 * *
159 * QName handling helper *
160 * *
161 ************************************************************************/
162
163/**
164 * xmlSplitQName2:
165 * @name: an XML parser context
166 * @prefix: a xmlChar **
167 *
168 * parse an XML qualified name string
169 *
170 * [NS 5] QName ::= (Prefix ':')? LocalPart
171 *
172 * [NS 6] Prefix ::= NCName
173 *
174 * [NS 7] LocalPart ::= NCName
175 *
176 * Returns NULL if not a QName, otherwise the local part, and prefix
177 * is updated to get the Prefix if any.
178 */
179
180xmlChar *
181xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
182 int len = 0;
183 xmlChar *ret = NULL;
184
185 *prefix = NULL;
186
187 /* xml: prefix is not really a namespace */
188 if ((name[0] == 'x') && (name[1] == 'm') &&
189 (name[2] == 'l') && (name[3] == ':'))
190 return(NULL);
191
192 /* nasty but valid */
193 if (name[0] == ':')
194 return(NULL);
195
196 /*
197 * we are not trying to validate but just to cut, and yes it will
198 * work even if this is as set of UTF-8 encoded chars
199 */
200 while ((name[len] != 0) && (name[len] != ':'))
201 len++;
202
203 if (name[len] == 0)
204 return(NULL);
205
206 *prefix = xmlStrndup(name, len);
207 ret = xmlStrdup(&name[len + 1]);
208
209 return(ret);
210}
211
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000212/****************************************************************
213 * *
214 * Util functions for data allocation/deallocation *
215 * *
216 ****************************************************************/
217
218/**
219 * xmlNewElementContent:
220 * @name: the subelement name or NULL
221 * @type: the type of element content decl
222 *
223 * Allocate an element content structure.
224 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000225 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000226 */
227xmlElementContentPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000228xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000229 xmlElementContentPtr ret;
230
231 switch(type) {
232 case XML_ELEMENT_CONTENT_ELEMENT:
233 if (name == NULL) {
234 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
235 }
236 break;
237 case XML_ELEMENT_CONTENT_PCDATA:
238 case XML_ELEMENT_CONTENT_SEQ:
239 case XML_ELEMENT_CONTENT_OR:
240 if (name != NULL) {
241 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
242 }
243 break;
244 default:
245 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
Daniel Veillard0142b842000-01-14 14:45:24 +0000246 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000247 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000248 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000249 if (ret == NULL) {
250 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
251 return(NULL);
252 }
253 ret->type = type;
254 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000255 if (name != NULL)
256 ret->name = xmlStrdup(name);
257 else
258 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000259 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000260 return(ret);
261}
262
263/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000264 * xmlCopyElementContent:
265 * @content: An element content pointer.
266 *
267 * Build a copy of an element content description.
268 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000269 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000270 */
271xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000272xmlCopyElementContent(xmlElementContentPtr cur) {
273 xmlElementContentPtr ret;
274
275 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000276 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +0000277 if (ret == NULL) {
278 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
279 return(NULL);
280 }
281 ret->ocur = cur->ocur;
282 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
283 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000284 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000285}
286
287/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000288 * xmlFreeElementContent:
289 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000290 *
291 * Free an element content structure. This is a recursive call !
292 */
293void
294xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000295 if (cur == NULL) return;
Daniel Veillard87b95392000-08-12 21:12:04 +0000296 switch (cur->type) {
297 case XML_ELEMENT_CONTENT_PCDATA:
298 case XML_ELEMENT_CONTENT_ELEMENT:
299 case XML_ELEMENT_CONTENT_SEQ:
300 case XML_ELEMENT_CONTENT_OR:
301 break;
302 default:
303 fprintf(stderr, "xmlFreeElementContent : type %d\n", cur->type);
304 return;
305 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000306 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
307 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000308 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000309 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000310 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000311}
312
Daniel Veillard1899e851999-02-01 12:18:54 +0000313/**
314 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000315 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000316 * @content: An element table
317 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
318 *
319 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000320 */
321void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000322xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000323 if (content == NULL) return;
324
Daniel Veillard5099ae81999-04-21 20:12:07 +0000325 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000326 switch (content->type) {
327 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000328 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000329 break;
330 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000331 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000332 break;
333 case XML_ELEMENT_CONTENT_SEQ:
334 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
335 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000336 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000337 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000338 xmlDumpElementContent(buf, content->c1, 0);
339 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000340 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000341 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000342 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000343 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000344 break;
345 case XML_ELEMENT_CONTENT_OR:
346 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
347 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000348 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000349 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000350 xmlDumpElementContent(buf, content->c1, 0);
351 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000352 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000353 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000354 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000355 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000356 break;
357 default:
358 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
359 content->type);
360 }
361 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000362 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000363 switch (content->ocur) {
364 case XML_ELEMENT_CONTENT_ONCE:
365 break;
366 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000367 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000368 break;
369 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000370 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000371 break;
372 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000373 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000374 break;
375 }
376}
377
Daniel Veillardb05deb71999-08-10 19:04:08 +0000378/**
379 * xmlSprintfElementContent:
380 * @buf: an output buffer
381 * @content: An element table
382 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
383 *
384 * This will dump the content of the element content definition
385 * Intended just for the debug routine
386 */
387void
388xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
389 if (content == NULL) return;
390 if (glob) strcat(buf, "(");
391 switch (content->type) {
392 case XML_ELEMENT_CONTENT_PCDATA:
393 strcat(buf, "#PCDATA");
394 break;
395 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000396 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000397 break;
398 case XML_ELEMENT_CONTENT_SEQ:
399 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
400 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
401 xmlSprintfElementContent(buf, content->c1, 1);
402 else
403 xmlSprintfElementContent(buf, content->c1, 0);
404 strcat(buf, " , ");
405 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
406 xmlSprintfElementContent(buf, content->c2, 1);
407 else
408 xmlSprintfElementContent(buf, content->c2, 0);
409 break;
410 case XML_ELEMENT_CONTENT_OR:
411 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
412 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
413 xmlSprintfElementContent(buf, content->c1, 1);
414 else
415 xmlSprintfElementContent(buf, content->c1, 0);
416 strcat(buf, " | ");
417 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
418 xmlSprintfElementContent(buf, content->c2, 1);
419 else
420 xmlSprintfElementContent(buf, content->c2, 0);
421 break;
422 }
423 if (glob)
424 strcat(buf, ")");
425 switch (content->ocur) {
426 case XML_ELEMENT_CONTENT_ONCE:
427 break;
428 case XML_ELEMENT_CONTENT_OPT:
429 strcat(buf, "?");
430 break;
431 case XML_ELEMENT_CONTENT_MULT:
432 strcat(buf, "*");
433 break;
434 case XML_ELEMENT_CONTENT_PLUS:
435 strcat(buf, "+");
436 break;
437 }
438}
439
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000440/****************************************************************
441 * *
442 * Registration of DTD declarations *
443 * *
444 ****************************************************************/
445
Daniel Veillard3b9def11999-01-31 22:15:06 +0000446/**
447 * xmlCreateElementTable:
448 *
449 * create and initialize an empty element hash table.
450 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000451 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000452 */
453xmlElementTablePtr
454xmlCreateElementTable(void) {
455 xmlElementTablePtr ret;
456
457 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000458 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000459 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000460 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000461 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000462 return(NULL);
463 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000464 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000465 ret->nb_elements = 0;
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000466 ret->last = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000467 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000468 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +0000469 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000470 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000471 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000472 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000473 return(NULL);
474 }
475 return(ret);
476}
477
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000478
479/**
480 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000481 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000482 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000483 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000484 * @type: the element type
485 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000486 *
487 * Register a new element declaration
488 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000489 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000490 */
491xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000492xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillardcf461992000-03-14 18:30:20 +0000493 xmlElementTypeVal type,
494 xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000495 xmlElementPtr ret, cur;
496 xmlElementTablePtr table;
Daniel Veillardbe803962000-06-28 23:40:59 +0000497 xmlChar *ns, *uqname;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000498 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000499
500 if (dtd == NULL) {
501 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
502 return(NULL);
503 }
504 if (name == NULL) {
505 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
506 return(NULL);
507 }
508 switch (type) {
509 case XML_ELEMENT_TYPE_EMPTY:
510 if (content != NULL) {
511 fprintf(stderr,
512 "xmlAddElementDecl: content != NULL for EMPTY\n");
513 return(NULL);
514 }
515 break;
516 case XML_ELEMENT_TYPE_ANY:
517 if (content != NULL) {
518 fprintf(stderr,
519 "xmlAddElementDecl: content != NULL for ANY\n");
520 return(NULL);
521 }
522 break;
523 case XML_ELEMENT_TYPE_MIXED:
524 if (content == NULL) {
525 fprintf(stderr,
526 "xmlAddElementDecl: content == NULL for MIXED\n");
527 return(NULL);
528 }
529 break;
530 case XML_ELEMENT_TYPE_ELEMENT:
531 if (content == NULL) {
532 fprintf(stderr,
533 "xmlAddElementDecl: content == NULL for ELEMENT\n");
534 return(NULL);
535 }
536 break;
537 default:
538 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
539 return(NULL);
540 }
541
542 /*
Daniel Veillardbe803962000-06-28 23:40:59 +0000543 * check if name is a QName
544 */
545 uqname = xmlSplitQName2(name, &ns);
546 if (uqname != NULL)
547 name = uqname;
548
549 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000550 * Create the Element table if needed.
551 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000552 table = (xmlElementTablePtr) dtd->elements;
553 if (table == NULL) {
554 table = xmlCreateElementTable();
555 dtd->elements = (void *) table;
556 }
Daniel Veillard3b9def11999-01-31 22:15:06 +0000557 if (table == NULL) {
558 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
559 return(NULL);
560 }
561
562 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000563 * Validity Check:
564 * Search the DTD for previous declarations of the ELEMENT
565 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000566 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000567 cur = table->table[i];
Daniel Veillardbe803962000-06-28 23:40:59 +0000568 if ((ns != NULL) && (cur->prefix == NULL)) continue;
569 if ((ns == NULL) && (cur->prefix != NULL)) continue;
570 if ((!xmlStrcmp(cur->name, name)) &&
571 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000572 /*
573 * The element is already defined in this Dtd.
574 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000575 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000576 return(NULL);
577 }
578 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000579
580 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000581 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000582 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000583 if (table->nb_elements >= table->max_elements) {
584 /*
585 * need more elements.
586 */
587 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000588 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000589 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000590 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000591 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
592 return(NULL);
593 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000594 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000595 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000596 if (ret == NULL) {
597 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
598 return(NULL);
599 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000600 memset(ret, 0, sizeof(xmlElement));
601 ret->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000602 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000603
604 /*
605 * fill the structure.
606 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000607 ret->etype = type;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000608 ret->name = xmlStrdup(name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000609 ret->prefix = ns;
Daniel Veillard14fff061999-06-22 21:49:07 +0000610 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000611 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000612 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000613
Daniel Veillardcf461992000-03-14 18:30:20 +0000614 /*
615 * Link it to the Dtd
616 */
617 ret->parent = dtd;
618 ret->doc = dtd->doc;
619 if (dtd->last == NULL) {
620 dtd->children = dtd->last = (xmlNodePtr) ret;
621 } else {
622 dtd->last->next = (xmlNodePtr) ret;
623 ret->prev = dtd->last;
624 dtd->last = (xmlNodePtr) ret;
625 }
Daniel Veillardbe803962000-06-28 23:40:59 +0000626 if (uqname != NULL)
627 xmlFree(uqname);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000628 return(ret);
629}
630
Daniel Veillard3b9def11999-01-31 22:15:06 +0000631/**
632 * xmlFreeElement:
633 * @elem: An element
634 *
635 * Deallocate the memory used by an element definition
636 */
637void
638xmlFreeElement(xmlElementPtr elem) {
639 if (elem == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +0000640 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000641 xmlFreeElementContent(elem->content);
642 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000643 xmlFree((xmlChar *) elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000644 if (elem->prefix != NULL)
645 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000646 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000647 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000648}
649
650/**
651 * xmlFreeElementTable:
652 * @table: An element table
653 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000654 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000655 */
656void
657xmlFreeElementTable(xmlElementTablePtr table) {
658 int i;
659
660 if (table == NULL) return;
661
662 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000663 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000664 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000665 xmlFree(table->table);
666 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000667}
668
669/**
670 * xmlCopyElementTable:
671 * @table: An element table
672 *
673 * Build a copy of an element table.
674 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000675 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000676 */
677xmlElementTablePtr
678xmlCopyElementTable(xmlElementTablePtr table) {
679 xmlElementTablePtr ret;
680 xmlElementPtr cur, ent;
681 int i;
682
Daniel Veillard6454aec1999-09-02 22:04:43 +0000683 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000684 if (ret == NULL) {
685 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
686 return(NULL);
687 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000688 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000689 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000690 if (ret->table == NULL) {
691 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000692 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000693 return(NULL);
694 }
695 ret->max_elements = table->max_elements;
696 ret->nb_elements = table->nb_elements;
697 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000698 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000699 if (cur == NULL) {
700 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000701 xmlFree(ret);
702 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000703 return(NULL);
704 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000705 memset(cur, 0, sizeof(xmlElement));
706 cur->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000707 ret->table[i] = cur;
708 ent = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000709 cur->etype = ent->etype;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000710 if (ent->name != NULL)
711 cur->name = xmlStrdup(ent->name);
712 else
713 cur->name = NULL;
714 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000715 /* TODO : rebuild the attribute list on the copy */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000716 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000717 }
718 return(ret);
719}
720
721/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000722 * xmlDumpElementDecl:
723 * @buf: the XML buffer output
724 * @elem: An element table
725 *
726 * This will dump the content of the element declaration as an XML
727 * DTD definition
728 */
729void
730xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
731 switch (elem->etype) {
732 case XML_ELEMENT_TYPE_EMPTY:
733 xmlBufferWriteChar(buf, "<!ELEMENT ");
734 xmlBufferWriteCHAR(buf, elem->name);
735 xmlBufferWriteChar(buf, " EMPTY>\n");
736 break;
737 case XML_ELEMENT_TYPE_ANY:
738 xmlBufferWriteChar(buf, "<!ELEMENT ");
739 xmlBufferWriteCHAR(buf, elem->name);
740 xmlBufferWriteChar(buf, " ANY>\n");
741 break;
742 case XML_ELEMENT_TYPE_MIXED:
743 xmlBufferWriteChar(buf, "<!ELEMENT ");
744 xmlBufferWriteCHAR(buf, elem->name);
745 xmlBufferWriteChar(buf, " ");
746 xmlDumpElementContent(buf, elem->content, 1);
747 xmlBufferWriteChar(buf, ">\n");
748 break;
749 case XML_ELEMENT_TYPE_ELEMENT:
750 xmlBufferWriteChar(buf, "<!ELEMENT ");
751 xmlBufferWriteCHAR(buf, elem->name);
752 xmlBufferWriteChar(buf, " ");
753 xmlDumpElementContent(buf, elem->content, 1);
754 xmlBufferWriteChar(buf, ">\n");
755 break;
756 default:
757 fprintf(stderr,
758 "xmlDumpElementDecl: internal: unknown type %d\n",
759 elem->etype);
760 }
761}
762
763/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000764 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000765 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000766 * @table: An element table
767 *
768 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000769 */
770void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000771xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000772 int i;
773 xmlElementPtr cur;
774
775 if (table == NULL) return;
776
777 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000778 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000779 xmlDumpElementDecl(buf, cur);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000780 }
781}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000782
783/**
784 * xmlCreateEnumeration:
785 * @name: the enumeration name or NULL
786 *
787 * create and initialize an enumeration attribute node.
788 *
789 * Returns the xmlEnumerationPtr just created or NULL in case
790 * of error.
791 */
792xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000793xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000794 xmlEnumerationPtr ret;
795
Daniel Veillard6454aec1999-09-02 22:04:43 +0000796 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000797 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000798 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000799 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000800 return(NULL);
801 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000802 memset(ret, 0, sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000803
804 if (name != NULL)
805 ret->name = xmlStrdup(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000806 return(ret);
807}
808
809/**
810 * xmlFreeEnumeration:
811 * @cur: the tree to free.
812 *
813 * free an enumeration attribute node (recursive).
814 */
815void
816xmlFreeEnumeration(xmlEnumerationPtr cur) {
817 if (cur == NULL) return;
818
819 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
820
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000821 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000822 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000823 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000824}
825
826/**
827 * xmlCopyEnumeration:
828 * @cur: the tree to copy.
829 *
830 * Copy an enumeration attribute node (recursive).
831 *
832 * Returns the xmlEnumerationPtr just created or NULL in case
833 * of error.
834 */
835xmlEnumerationPtr
836xmlCopyEnumeration(xmlEnumerationPtr cur) {
837 xmlEnumerationPtr ret;
838
839 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000840 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000841
842 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
843 else ret->next = NULL;
844
845 return(ret);
846}
847
848/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000849 * xmlDumpEnumeration:
850 * @buf: the XML buffer output
851 * @enum: An enumeration
852 *
853 * This will dump the content of the enumeration
854 */
855void
856xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
857 if (cur == NULL) return;
858
859 xmlBufferWriteCHAR(buf, cur->name);
860 if (cur->next == NULL)
861 xmlBufferWriteChar(buf, ")");
862 else {
863 xmlBufferWriteChar(buf, " | ");
864 xmlDumpEnumeration(buf, cur->next);
865 }
866}
867
868/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000869 * xmlCreateAttributeTable:
870 *
871 * create and initialize an empty attribute hash table.
872 *
873 * Returns the xmlAttributeTablePtr just created or NULL in case
874 * of error.
875 */
876xmlAttributeTablePtr
877xmlCreateAttributeTable(void) {
878 xmlAttributeTablePtr ret;
879
880 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000881 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000882 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000883 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000884 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000885 return(NULL);
886 }
887 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
888 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000889 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000890 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard87b95392000-08-12 21:12:04 +0000891 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000892 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000893 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000894 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000895 return(NULL);
896 }
897 return(ret);
898}
899
Daniel Veillardb05deb71999-08-10 19:04:08 +0000900/**
901 * xmlScanAttributeDecl:
902 * @dtd: pointer to the DTD
903 * @elem: the element name
904 *
905 * When inserting a new element scan the DtD for existing attributes
906 * for taht element and initialize the Attribute chain
907 *
908 * Returns the pointer to the first attribute decl in the chain,
909 * possibly NULL.
910 */
911xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000912xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000913 xmlAttributePtr ret = NULL;
914 xmlAttributeTablePtr table;
915 int i;
916
917 if (dtd == NULL) {
918 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
919 return(NULL);
920 }
921 if (elem == NULL) {
922 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
923 return(NULL);
924 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000925 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000926 if (table == NULL)
927 return(NULL);
928
929 for (i = 0;i < table->nb_attributes;i++) {
930 if (!xmlStrcmp(table->table[i]->elem, elem)) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000931 table->table[i]->nexth = ret;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000932 ret = table->table[i];
933 }
934 }
935 return(ret);
936}
937
938/**
939 * xmlScanIDAttributeDecl:
940 * @ctxt: the validation context
941 * @elem: the element name
942 *
Daniel Veillard71b656e2000-01-05 14:46:17 +0000943 * Verify that the element don't have too many ID attributes
Daniel Veillardb05deb71999-08-10 19:04:08 +0000944 * declared.
945 *
946 * Returns the number of ID attributes found.
947 */
948int
949xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
950 xmlAttributePtr cur;
951 int ret = 0;
952
953 if (elem == NULL) return(0);
954 cur = elem->attributes;
955 while (cur != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000956 if (cur->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000957 ret ++;
958 if (ret > 1)
959 VERROR(ctxt->userData,
960 "Element %s has too may ID attributes defined : %s\n",
961 elem->name, cur->name);
962 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000963 cur = cur->nexth;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000964 }
965 return(ret);
966}
967
Daniel Veillard1e346af1999-02-22 10:33:01 +0000968
969/**
970 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000971 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000972 * @dtd: pointer to the DTD
973 * @elem: the element name
974 * @name: the attribute name
Daniel Veillardcf461992000-03-14 18:30:20 +0000975 * @ns: the attribute namespace prefix
Daniel Veillard1e346af1999-02-22 10:33:01 +0000976 * @type: the attribute type
977 * @def: the attribute default type
978 * @defaultValue: the attribute default value
979 * @tree: if it's an enumeration, the associated list
980 *
981 * Register a new attribute declaration
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000982 * Note that @tree becomes the ownership of the DTD
Daniel Veillard1e346af1999-02-22 10:33:01 +0000983 *
Daniel Veillardbe803962000-06-28 23:40:59 +0000984 * Returns NULL if not new, othervise the attribute decl
Daniel Veillard1e346af1999-02-22 10:33:01 +0000985 */
986xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000987xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
Daniel Veillardcf461992000-03-14 18:30:20 +0000988 const xmlChar *name, const xmlChar *ns,
989 xmlAttributeType type, xmlAttributeDefault def,
990 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000991 xmlAttributePtr ret, cur;
992 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000993 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000994 int i;
995
996 if (dtd == NULL) {
997 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000998 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000999 return(NULL);
1000 }
1001 if (name == NULL) {
1002 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001003 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001004 return(NULL);
1005 }
1006 if (elem == NULL) {
1007 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001008 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001009 return(NULL);
1010 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001011 /*
1012 * Check the type and possibly the default value.
1013 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001014 switch (type) {
1015 case XML_ATTRIBUTE_CDATA:
1016 break;
1017 case XML_ATTRIBUTE_ID:
1018 break;
1019 case XML_ATTRIBUTE_IDREF:
1020 break;
1021 case XML_ATTRIBUTE_IDREFS:
1022 break;
1023 case XML_ATTRIBUTE_ENTITY:
1024 break;
1025 case XML_ATTRIBUTE_ENTITIES:
1026 break;
1027 case XML_ATTRIBUTE_NMTOKEN:
1028 break;
1029 case XML_ATTRIBUTE_NMTOKENS:
1030 break;
1031 case XML_ATTRIBUTE_ENUMERATION:
1032 break;
1033 case XML_ATTRIBUTE_NOTATION:
1034 break;
1035 default:
1036 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001037 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001038 return(NULL);
1039 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001040 if ((defaultValue != NULL) &&
1041 (!xmlValidateAttributeValue(type, defaultValue))) {
1042 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
1043 elem, name, defaultValue);
1044 defaultValue = NULL;
1045 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001046
1047 /*
1048 * Create the Attribute table if needed.
1049 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001050 table = (xmlAttributeTablePtr) dtd->attributes;
1051 if (table == NULL) {
1052 table = xmlCreateAttributeTable();
1053 dtd->attributes = (void *) table;
1054 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001055 if (table == NULL) {
1056 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
1057 return(NULL);
1058 }
1059
1060 /*
1061 * Validity Check:
1062 * Search the DTD for previous declarations of the ATTLIST
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001063 * The initial code used to walk the attribute table comparing
1064 * all pairs of element/attribute names, and was far too slow
1065 * for large DtDs, we now walk the attribute list associated to
1066 * the element declaration instead if this declaration is found.
Daniel Veillard1e346af1999-02-22 10:33:01 +00001067 */
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001068 elemDef = xmlGetDtdElementDesc(dtd, elem);
1069 if (elemDef != NULL) {
1070 /*
1071 * follow the attribute list.
1072 */
1073 cur = elemDef->attributes;
1074 while (cur != NULL) {
1075 if ((ns != NULL) && (cur->prefix == NULL)) {
1076 cur = cur->nexth;
1077 continue;
1078 }
1079 if ((ns == NULL) && (cur->prefix != NULL)) {
1080 cur = cur->nexth;
1081 continue;
1082 }
1083 if ((!xmlStrcmp(cur->name, name)) &&
1084 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
1085 /*
1086 * The attribute is already defined in this Dtd.
1087 */
1088 VWARNING(ctxt->userData,
1089 "Attribute %s on %s: already defined\n",
1090 name, elem);
1091 xmlFreeEnumeration(tree);
1092 return(NULL);
1093 }
1094 cur = cur->nexth;
1095 }
1096 } else {
1097 /*
1098 * Walk down the attribute table.
1099 */
1100 for (i = 0;i < table->nb_attributes;i++) {
1101 cur = table->table[i];
1102 if ((ns != NULL) && (cur->prefix == NULL)) continue;
1103 if ((ns == NULL) && (cur->prefix != NULL)) continue;
1104 if ((!xmlStrcmp(cur->name, name)) &&
1105 (!xmlStrcmp(cur->elem, elem)) &&
1106 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
1107 /*
1108 * The attribute is already defined in this Dtd.
1109 */
1110 VWARNING(ctxt->userData,
1111 "Attribute %s on %s: already defined\n",
1112 elem, name);
1113 xmlFreeEnumeration(tree);
1114 return(NULL);
1115 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001116 }
1117 }
1118
1119 /*
1120 * Grow the table, if needed.
1121 */
1122 if (table->nb_attributes >= table->max_attributes) {
1123 /*
1124 * need more attributes.
1125 */
1126 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001127 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001128 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001129 sizeof(xmlAttributePtr));
1130 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001131 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1132 return(NULL);
1133 }
1134 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001135 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001136 if (ret == NULL) {
1137 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1138 return(NULL);
1139 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001140 memset(ret, 0, sizeof(xmlAttribute));
1141 ret->type = XML_ATTRIBUTE_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001142 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001143
1144 /*
1145 * fill the structure.
1146 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001147 ret->atype = type;
1148 ret->name = xmlStrdup(name);
1149 ret->prefix = xmlStrdup(ns);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001150 ret->elem = xmlStrdup(elem);
1151 ret->def = def;
1152 ret->tree = tree;
1153 if (defaultValue != NULL)
1154 ret->defaultValue = xmlStrdup(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001155 if (elemDef != NULL) {
1156 if ((type == XML_ATTRIBUTE_ID) &&
1157 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
1158 VERROR(ctxt->userData,
1159 "Element %s has too may ID attributes defined : %s\n",
1160 elem, name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001161 ret->nexth = elemDef->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001162 elemDef->attributes = ret;
1163 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001164 table->nb_attributes++;
1165
Daniel Veillardcf461992000-03-14 18:30:20 +00001166 /*
1167 * Link it to the Dtd
1168 */
1169 ret->parent = dtd;
1170 ret->doc = dtd->doc;
1171 if (dtd->last == NULL) {
1172 dtd->children = dtd->last = (xmlNodePtr) ret;
1173 } else {
1174 dtd->last->next = (xmlNodePtr) ret;
1175 ret->prev = dtd->last;
1176 dtd->last = (xmlNodePtr) ret;
1177 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001178 return(ret);
1179}
1180
1181/**
1182 * xmlFreeAttribute:
1183 * @elem: An attribute
1184 *
1185 * Deallocate the memory used by an attribute definition
1186 */
1187void
1188xmlFreeAttribute(xmlAttributePtr attr) {
1189 if (attr == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +00001190 xmlUnlinkNode((xmlNodePtr) attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001191 if (attr->tree != NULL)
1192 xmlFreeEnumeration(attr->tree);
1193 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001194 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001195 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001196 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001197 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001198 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +00001199 if (attr->prefix != NULL)
1200 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001201 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001202 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001203}
1204
1205/**
1206 * xmlFreeAttributeTable:
1207 * @table: An attribute table
1208 *
1209 * Deallocate the memory used by an entities hash table.
1210 */
1211void
1212xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1213 int i;
1214
1215 if (table == NULL) return;
1216
1217 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001218 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001219 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001220 xmlFree(table->table);
1221 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001222}
1223
1224/**
1225 * xmlCopyAttributeTable:
1226 * @table: An attribute table
1227 *
1228 * Build a copy of an attribute table.
1229 *
1230 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1231 */
1232xmlAttributeTablePtr
1233xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1234 xmlAttributeTablePtr ret;
1235 xmlAttributePtr cur, attr;
1236 int i;
1237
Daniel Veillard6454aec1999-09-02 22:04:43 +00001238 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001239 if (ret == NULL) {
1240 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1241 return(NULL);
1242 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001243 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001244 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001245 if (ret->table == NULL) {
1246 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001247 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001248 return(NULL);
1249 }
1250 ret->max_attributes = table->max_attributes;
1251 ret->nb_attributes = table->nb_attributes;
1252 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001253 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001254 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001255 if (cur == NULL) {
1256 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001257 xmlFree(ret);
1258 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001259 return(NULL);
1260 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001261 memset(cur, 0, sizeof(xmlAttribute));
1262 /* !!! cur->type = XML_ATTRIBUTE_DECL; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001263 ret->table[i] = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001264 cur->atype = attr->atype;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001265 cur->def = attr->def;
1266 cur->tree = xmlCopyEnumeration(attr->tree);
1267 if (attr->elem != NULL)
1268 cur->elem = xmlStrdup(attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001269 if (attr->name != NULL)
1270 cur->name = xmlStrdup(attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001271 if (attr->defaultValue != NULL)
1272 cur->defaultValue = xmlStrdup(attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001273 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001274 }
1275 return(ret);
1276}
1277
1278/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001279 * xmlDumpAttributeDecl:
1280 * @buf: the XML buffer output
1281 * @attr: An attribute declaration
1282 *
1283 * This will dump the content of the attribute declaration as an XML
1284 * DTD definition
1285 */
1286void
1287xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1288 xmlBufferWriteChar(buf, "<!ATTLIST ");
1289 xmlBufferWriteCHAR(buf, attr->elem);
1290 xmlBufferWriteChar(buf, " ");
Daniel Veillardbe803962000-06-28 23:40:59 +00001291 if (attr->prefix != NULL) {
1292 xmlBufferWriteCHAR(buf, attr->prefix);
1293 xmlBufferWriteChar(buf, ":");
1294 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001295 xmlBufferWriteCHAR(buf, attr->name);
1296 switch (attr->atype) {
1297 case XML_ATTRIBUTE_CDATA:
1298 xmlBufferWriteChar(buf, " CDATA");
1299 break;
1300 case XML_ATTRIBUTE_ID:
1301 xmlBufferWriteChar(buf, " ID");
1302 break;
1303 case XML_ATTRIBUTE_IDREF:
1304 xmlBufferWriteChar(buf, " IDREF");
1305 break;
1306 case XML_ATTRIBUTE_IDREFS:
1307 xmlBufferWriteChar(buf, " IDREFS");
1308 break;
1309 case XML_ATTRIBUTE_ENTITY:
1310 xmlBufferWriteChar(buf, " ENTITY");
1311 break;
1312 case XML_ATTRIBUTE_ENTITIES:
1313 xmlBufferWriteChar(buf, " ENTITIES");
1314 break;
1315 case XML_ATTRIBUTE_NMTOKEN:
1316 xmlBufferWriteChar(buf, " NMTOKEN");
1317 break;
1318 case XML_ATTRIBUTE_NMTOKENS:
1319 xmlBufferWriteChar(buf, " NMTOKENS");
1320 break;
1321 case XML_ATTRIBUTE_ENUMERATION:
1322 xmlBufferWriteChar(buf, " (");
1323 xmlDumpEnumeration(buf, attr->tree);
1324 break;
1325 case XML_ATTRIBUTE_NOTATION:
1326 xmlBufferWriteChar(buf, " NOTATION (");
1327 xmlDumpEnumeration(buf, attr->tree);
1328 break;
1329 default:
1330 fprintf(stderr,
1331 "xmlDumpAttributeTable: internal: unknown type %d\n",
1332 attr->atype);
1333 }
1334 switch (attr->def) {
1335 case XML_ATTRIBUTE_NONE:
1336 break;
1337 case XML_ATTRIBUTE_REQUIRED:
1338 xmlBufferWriteChar(buf, " #REQUIRED");
1339 break;
1340 case XML_ATTRIBUTE_IMPLIED:
1341 xmlBufferWriteChar(buf, " #IMPLIED");
1342 break;
1343 case XML_ATTRIBUTE_FIXED:
1344 xmlBufferWriteChar(buf, " #FIXED");
1345 break;
1346 default:
1347 fprintf(stderr,
1348 "xmlDumpAttributeTable: internal: unknown default %d\n",
1349 attr->def);
1350 }
1351 if (attr->defaultValue != NULL) {
1352 xmlBufferWriteChar(buf, " ");
1353 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1354 }
1355 xmlBufferWriteChar(buf, ">\n");
1356}
1357
1358/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001359 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001360 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001361 * @table: An attribute table
1362 *
1363 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001364 */
1365void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001366xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001367 int i;
1368 xmlAttributePtr cur;
1369
1370 if (table == NULL) return;
1371
1372 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001373 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001374 xmlDumpAttributeDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001375 }
1376}
1377
1378/************************************************************************
1379 * *
1380 * NOTATIONs *
1381 * *
1382 ************************************************************************/
1383/**
1384 * xmlCreateNotationTable:
1385 *
1386 * create and initialize an empty notation hash table.
1387 *
1388 * Returns the xmlNotationTablePtr just created or NULL in case
1389 * of error.
1390 */
1391xmlNotationTablePtr
1392xmlCreateNotationTable(void) {
1393 xmlNotationTablePtr ret;
1394
1395 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001396 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001397 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001398 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001399 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001400 return(NULL);
1401 }
1402 ret->max_notations = XML_MIN_NOTATION_TABLE;
1403 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001404 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001405 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001406 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001407 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001408 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001409 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001410 return(NULL);
1411 }
1412 return(ret);
1413}
1414
1415
1416/**
1417 * xmlAddNotationDecl:
1418 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001419 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001420 * @name: the entity name
1421 * @PublicID: the public identifier or NULL
1422 * @SystemID: the system identifier or NULL
1423 *
1424 * Register a new notation declaration
1425 *
1426 * Returns NULL if not, othervise the entity
1427 */
1428xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001429xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1430 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001431 xmlNotationPtr ret, cur;
1432 xmlNotationTablePtr table;
1433 int i;
1434
1435 if (dtd == NULL) {
1436 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1437 return(NULL);
1438 }
1439 if (name == NULL) {
1440 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1441 return(NULL);
1442 }
1443 if ((PublicID == NULL) && (SystemID == NULL)) {
1444 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1445 }
1446
1447 /*
1448 * Create the Notation table if needed.
1449 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001450 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001451 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001452 dtd->notations = table = xmlCreateNotationTable();
Daniel Veillard1e346af1999-02-22 10:33:01 +00001453 if (table == NULL) {
1454 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1455 return(NULL);
1456 }
1457
1458 /*
1459 * Validity Check:
1460 * Search the DTD for previous declarations of the ATTLIST
1461 */
1462 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001463 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001464 if (!xmlStrcmp(cur->name, name)) {
1465 /*
1466 * The notation is already defined in this Dtd.
1467 */
1468 fprintf(stderr,
1469 "xmlAddNotationDecl: %s already defined\n", name);
1470 }
1471 }
1472
1473 /*
1474 * Grow the table, if needed.
1475 */
1476 if (table->nb_notations >= table->max_notations) {
1477 /*
1478 * need more notations.
1479 */
1480 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001481 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001482 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001483 sizeof(xmlNotationPtr));
1484 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001485 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1486 return(NULL);
1487 }
1488 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001489 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001490 if (ret == NULL) {
1491 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1492 return(NULL);
1493 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001494 memset(ret, 0, sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001495 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001496
1497 /*
1498 * fill the structure.
1499 */
1500 ret->name = xmlStrdup(name);
1501 if (SystemID != NULL)
1502 ret->SystemID = xmlStrdup(SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001503 if (PublicID != NULL)
1504 ret->PublicID = xmlStrdup(PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001505 table->nb_notations++;
1506
1507 return(ret);
1508}
1509
1510/**
1511 * xmlFreeNotation:
1512 * @not: A notation
1513 *
1514 * Deallocate the memory used by an notation definition
1515 */
1516void
1517xmlFreeNotation(xmlNotationPtr nota) {
1518 if (nota == NULL) return;
1519 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001520 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001521 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001522 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001523 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001524 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001525 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001526 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001527}
1528
1529/**
1530 * xmlFreeNotationTable:
1531 * @table: An notation table
1532 *
1533 * Deallocate the memory used by an entities hash table.
1534 */
1535void
1536xmlFreeNotationTable(xmlNotationTablePtr table) {
1537 int i;
1538
1539 if (table == NULL) return;
1540
1541 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001542 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001543 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001544 xmlFree(table->table);
1545 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001546}
1547
1548/**
1549 * xmlCopyNotationTable:
1550 * @table: A notation table
1551 *
1552 * Build a copy of a notation table.
1553 *
1554 * Returns the new xmlNotationTablePtr or NULL in case of error.
1555 */
1556xmlNotationTablePtr
1557xmlCopyNotationTable(xmlNotationTablePtr table) {
1558 xmlNotationTablePtr ret;
1559 xmlNotationPtr cur, nota;
1560 int i;
1561
Daniel Veillard6454aec1999-09-02 22:04:43 +00001562 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001563 if (ret == NULL) {
1564 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1565 return(NULL);
1566 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001567 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001568 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001569 if (ret->table == NULL) {
1570 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001571 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001572 return(NULL);
1573 }
1574 ret->max_notations = table->max_notations;
1575 ret->nb_notations = table->nb_notations;
1576 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001577 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001578 if (cur == NULL) {
1579 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001580 xmlFree(ret);
1581 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001582 return(NULL);
1583 }
1584 ret->table[i] = cur;
1585 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001586 if (nota->name != NULL)
1587 cur->name = xmlStrdup(nota->name);
1588 else
1589 cur->name = NULL;
1590 if (nota->PublicID != NULL)
1591 cur->PublicID = xmlStrdup(nota->PublicID);
1592 else
1593 cur->PublicID = NULL;
1594 if (nota->SystemID != NULL)
1595 cur->SystemID = xmlStrdup(nota->SystemID);
1596 else
1597 cur->SystemID = NULL;
1598 }
1599 return(ret);
1600}
1601
1602/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001603 * xmlDumpNotationDecl:
1604 * @buf: the XML buffer output
1605 * @nota: A notation declaration
1606 *
1607 * This will dump the content the notation declaration as an XML DTD definition
1608 */
1609void
1610xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
1611 xmlBufferWriteChar(buf, "<!NOTATION ");
1612 xmlBufferWriteCHAR(buf, nota->name);
1613 if (nota->PublicID != NULL) {
1614 xmlBufferWriteChar(buf, " PUBLIC ");
1615 xmlBufferWriteQuotedString(buf, nota->PublicID);
1616 if (nota->SystemID != NULL) {
1617 xmlBufferWriteChar(buf, " ");
1618 xmlBufferWriteCHAR(buf, nota->SystemID);
1619 }
1620 } else {
1621 xmlBufferWriteChar(buf, " SYSTEM ");
1622 xmlBufferWriteCHAR(buf, nota->SystemID);
1623 }
1624 xmlBufferWriteChar(buf, " >\n");
1625}
1626
1627/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001628 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001629 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001630 * @table: A notation table
1631 *
1632 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001633 */
1634void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001635xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001636 int i;
1637 xmlNotationPtr cur;
1638
1639 if (table == NULL) return;
1640
1641 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001642 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001643 xmlDumpNotationDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001644 }
1645}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001646
1647/************************************************************************
1648 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001649 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001650 * *
1651 ************************************************************************/
1652/**
1653 * xmlCreateIDTable:
1654 *
1655 * create and initialize an empty id hash table.
1656 *
1657 * Returns the xmlIDTablePtr just created or NULL in case
1658 * of error.
1659 */
1660xmlIDTablePtr
1661xmlCreateIDTable(void) {
1662 xmlIDTablePtr ret;
1663
1664 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001665 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001666 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001667 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001668 (long)sizeof(xmlIDTable));
1669 return(NULL);
1670 }
1671 ret->max_ids = XML_MIN_NOTATION_TABLE;
1672 ret->nb_ids = 0;
1673 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001674 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001675 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001676 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001677 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001678 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001679 return(NULL);
1680 }
1681 return(ret);
1682}
1683
1684
1685/**
1686 * xmlAddID:
1687 * @ctxt: the validation context
1688 * @doc: pointer to the document
1689 * @value: the value name
1690 * @attr: the attribute holding the ID
1691 *
1692 * Register a new id declaration
1693 *
1694 * Returns NULL if not, othervise the new xmlIDPtr
1695 */
1696xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001697xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001698 xmlAttrPtr attr) {
1699 xmlIDPtr ret, cur;
1700 xmlIDTablePtr table;
1701 int i;
1702
1703 if (doc == NULL) {
1704 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1705 return(NULL);
1706 }
1707 if (value == NULL) {
1708 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1709 return(NULL);
1710 }
1711 if (attr == NULL) {
1712 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1713 return(NULL);
1714 }
1715
1716 /*
1717 * Create the ID table if needed.
1718 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001719 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001720 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001721 doc->ids = table = xmlCreateIDTable();
Daniel Veillard991e63d1999-08-15 23:32:28 +00001722 if (table == NULL) {
1723 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1724 return(NULL);
1725 }
1726
1727 /*
1728 * Validity Check:
1729 * Search the DTD for previous declarations of the ATTLIST
1730 */
1731 for (i = 0;i < table->nb_ids;i++) {
1732 cur = table->table[i];
1733 if (!xmlStrcmp(cur->value, value)) {
1734 /*
1735 * The id is already defined in this Dtd.
1736 */
1737 VERROR(ctxt->userData, "ID %s already defined\n", value);
1738 return(NULL);
1739 }
1740 }
1741
1742 /*
1743 * Grow the table, if needed.
1744 */
1745 if (table->nb_ids >= table->max_ids) {
1746 /*
1747 * need more ids.
1748 */
1749 table->max_ids *= 2;
1750 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001751 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001752 sizeof(xmlIDPtr));
1753 if (table->table == NULL) {
1754 fprintf(stderr, "xmlAddID: out of memory\n");
1755 return(NULL);
1756 }
1757 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001758 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001759 if (ret == NULL) {
1760 fprintf(stderr, "xmlAddID: out of memory\n");
1761 return(NULL);
1762 }
1763 table->table[table->nb_ids] = ret;
1764
1765 /*
1766 * fill the structure.
1767 */
1768 ret->value = xmlStrdup(value);
1769 ret->attr = attr;
1770 table->nb_ids++;
1771
1772 return(ret);
1773}
1774
1775/**
1776 * xmlFreeID:
1777 * @not: A id
1778 *
1779 * Deallocate the memory used by an id definition
1780 */
1781void
1782xmlFreeID(xmlIDPtr id) {
1783 if (id == NULL) return;
1784 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001785 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001786 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001787 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001788}
1789
1790/**
1791 * xmlFreeIDTable:
1792 * @table: An id table
1793 *
1794 * Deallocate the memory used by an ID hash table.
1795 */
1796void
1797xmlFreeIDTable(xmlIDTablePtr table) {
1798 int i;
1799
1800 if (table == NULL) return;
1801
1802 for (i = 0;i < table->nb_ids;i++) {
1803 xmlFreeID(table->table[i]);
1804 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001805 xmlFree(table->table);
1806 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001807}
1808
1809/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001810 * xmlIsID:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001811 * @doc: the document
1812 * @elem: the element carrying the attribute
1813 * @attr: the attribute
1814 *
1815 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1816 * then this is simple, otherwise we use an heuristic: name ID (upper
1817 * or lowercase).
1818 *
1819 * Returns 0 or 1 depending on the lookup result
1820 */
1821int
1822xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00001823 if (doc == NULL) return(0);
1824 if (attr == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001825 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1826 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1827 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1828 (attr->name[2] == 0)) return(1);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001829 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1830 if ((!xmlStrcmp(BAD_CAST "id", attr->name)) ||
1831 (!xmlStrcmp(BAD_CAST "name", attr->name)))
1832 return(1);
1833 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001834 } else {
1835 xmlAttributePtr attrDecl;
1836
Daniel Veillard71b656e2000-01-05 14:46:17 +00001837 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001838 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1839 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1840 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1841 attr->name);
1842
Daniel Veillardcf461992000-03-14 18:30:20 +00001843 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001844 return(1);
1845 }
1846 return(0);
1847}
1848
Daniel Veillardb96e6431999-08-29 21:02:19 +00001849/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001850 * xmlRemoveID
1851 * @doc: the document
1852 * @attr: the attribute
1853 *
1854 * Remove the given attribute from the ID table maintained internally.
1855 *
1856 * Returns -1 if the lookup failed and 0 otherwise
1857 */
1858int
1859xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1860 xmlIDPtr cur;
1861 xmlIDTablePtr table;
1862 int i;
1863
1864 if (doc == NULL) return(-1);
1865 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001866 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001867 if (table == NULL)
1868 return(-1);
1869
1870 /*
1871 * Search the ID list.
1872 */
1873 for (i = 0;i < table->nb_ids;i++) {
1874 cur = table->table[i];
1875 if (cur->attr == attr) {
1876 table->nb_ids--;
1877 memmove(&table->table[i], &table->table[i+1],
1878 (table->nb_ids - i) * sizeof(xmlIDPtr));
1879 return(0);
1880 }
1881 }
1882 return(-1);
1883}
1884
1885/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001886 * xmlGetID:
1887 * @doc: pointer to the document
1888 * @ID: the ID value
1889 *
1890 * Search the attribute declaring the given ID
1891 *
1892 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1893 */
1894xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001895xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001896 xmlIDPtr cur;
1897 xmlIDTablePtr table;
1898 int i;
1899
1900 if (doc == NULL) {
1901 fprintf(stderr, "xmlGetID: doc == NULL\n");
1902 return(NULL);
1903 }
1904
1905 if (ID == NULL) {
1906 fprintf(stderr, "xmlGetID: ID == NULL\n");
1907 return(NULL);
1908 }
1909
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001910 table = (xmlIDTablePtr) doc->ids;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001911 if (table == NULL)
1912 return(NULL);
1913
1914 /*
1915 * Search the ID list.
1916 */
1917 for (i = 0;i < table->nb_ids;i++) {
1918 cur = table->table[i];
1919 if (!xmlStrcmp(cur->value, ID)) {
1920 return(cur->attr);
1921 }
1922 }
1923 return(NULL);
1924}
1925
Daniel Veillard991e63d1999-08-15 23:32:28 +00001926/************************************************************************
1927 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001928 * Refs *
1929 * *
1930 ************************************************************************/
1931/**
1932 * xmlCreateRefTable:
1933 *
1934 * create and initialize an empty ref hash table.
1935 *
1936 * Returns the xmlRefTablePtr just created or NULL in case
1937 * of error.
1938 */
1939xmlRefTablePtr
1940xmlCreateRefTable(void) {
1941 xmlRefTablePtr ret;
1942
1943 ret = (xmlRefTablePtr)
1944 xmlMalloc(sizeof(xmlRefTable));
1945 if (ret == NULL) {
1946 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1947 (long)sizeof(xmlRefTable));
1948 return(NULL);
1949 }
1950 ret->max_refs = XML_MIN_NOTATION_TABLE;
1951 ret->nb_refs = 0;
1952 ret->table = (xmlRefPtr *)
1953 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001954 if (ret->table == NULL) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001955 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1956 ret->max_refs * (long)sizeof(xmlRef));
1957 xmlFree(ret);
1958 return(NULL);
1959 }
1960 return(ret);
1961}
1962
1963
1964/**
1965 * xmlAddRef:
1966 * @ctxt: the validation context
1967 * @doc: pointer to the document
1968 * @value: the value name
1969 * @attr: the attribute holding the Ref
1970 *
1971 * Register a new ref declaration
1972 *
1973 * Returns NULL if not, othervise the new xmlRefPtr
1974 */
1975xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001976xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001977 xmlAttrPtr attr) {
1978 xmlRefPtr ret;
1979 xmlRefTablePtr table;
1980
1981 if (doc == NULL) {
1982 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1983 return(NULL);
1984 }
1985 if (value == NULL) {
1986 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1987 return(NULL);
1988 }
1989 if (attr == NULL) {
1990 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1991 return(NULL);
1992 }
1993
1994 /*
1995 * Create the Ref table if needed.
1996 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001997 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001998 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001999 doc->refs = table = xmlCreateRefTable();
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002000 if (table == NULL) {
2001 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
2002 return(NULL);
2003 }
2004
2005 /*
2006 * Grow the table, if needed.
2007 */
2008 if (table->nb_refs >= table->max_refs) {
2009 /*
2010 * need more refs.
2011 */
2012 table->max_refs *= 2;
2013 table->table = (xmlRefPtr *)
2014 xmlRealloc(table->table, table->max_refs *
2015 sizeof(xmlRefPtr));
2016 if (table->table == NULL) {
2017 fprintf(stderr, "xmlAddRef: out of memory\n");
2018 return(NULL);
2019 }
2020 }
2021 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2022 if (ret == NULL) {
2023 fprintf(stderr, "xmlAddRef: out of memory\n");
2024 return(NULL);
2025 }
2026 table->table[table->nb_refs] = ret;
2027
2028 /*
2029 * fill the structure.
2030 */
2031 ret->value = xmlStrdup(value);
2032 ret->attr = attr;
2033 table->nb_refs++;
2034
2035 return(ret);
2036}
2037
2038/**
2039 * xmlFreeRef:
2040 * @not: A ref
2041 *
2042 * Deallocate the memory used by an ref definition
2043 */
2044void
2045xmlFreeRef(xmlRefPtr ref) {
2046 if (ref == NULL) return;
2047 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002048 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002049 memset(ref, -1, sizeof(xmlRef));
2050 xmlFree(ref);
2051}
2052
2053/**
2054 * xmlFreeRefTable:
2055 * @table: An ref table
2056 *
2057 * Deallocate the memory used by an Ref hash table.
2058 */
2059void
2060xmlFreeRefTable(xmlRefTablePtr table) {
2061 int i;
2062
2063 if (table == NULL) return;
2064
2065 for (i = 0;i < table->nb_refs;i++) {
2066 xmlFreeRef(table->table[i]);
2067 }
2068 xmlFree(table->table);
2069 xmlFree(table);
2070}
2071
2072/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002073 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002074 * @doc: the document
2075 * @elem: the element carrying the attribute
2076 * @attr: the attribute
2077 *
2078 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
2079 * then this is simple, otherwise we use an heuristic: name Ref (upper
2080 * or lowercase).
2081 *
2082 * Returns 0 or 1 depending on the lookup result
2083 */
2084int
2085xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2086 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2087 return(0);
2088 /*******************
2089 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
2090 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
2091 (attr->name[2] == 0)) return(1);
2092 *******************/
Daniel Veillardd83eb822000-06-30 18:39:56 +00002093 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2094 /* TODO @@@ */
2095 return(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002096 } else {
2097 xmlAttributePtr attrDecl;
2098
2099 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2100 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2101 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2102 attr->name);
2103
Daniel Veillardcf461992000-03-14 18:30:20 +00002104 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002105 return(1);
2106 }
2107 return(0);
2108}
2109
2110/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002111 * xmlRemoveRef
2112 * @doc: the document
2113 * @attr: the attribute
2114 *
2115 * Remove the given attribute from the Ref table maintained internally.
2116 *
2117 * Returns -1 if the lookup failed and 0 otherwise
2118 */
2119int
2120xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2121 xmlRefPtr cur;
2122 xmlRefTablePtr table;
2123 int i;
2124
2125 if (doc == NULL) return(-1);
2126 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002127 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard71b656e2000-01-05 14:46:17 +00002128 if (table == NULL)
2129 return(-1);
2130
2131 /*
2132 * Search the Ref list.
2133 */
2134 for (i = 0;i < table->nb_refs;i++) {
2135 cur = table->table[i];
2136 if (cur->attr == attr) {
2137 table->nb_refs--;
2138 memmove(&table->table[i], &table->table[i+1],
2139 (table->nb_refs - i) * sizeof(xmlRefPtr));
2140 return(0);
2141 }
2142 }
2143 return(-1);
2144}
2145
2146/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002147 * xmlGetRef:
2148 * @doc: pointer to the document
2149 * @Ref: the Ref value
2150 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00002151 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002152 *
2153 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
2154 */
2155xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002156xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002157 xmlRefPtr cur;
2158 xmlRefTablePtr table;
2159 int i;
2160
2161 if (doc == NULL) {
2162 fprintf(stderr, "xmlGetRef: doc == NULL\n");
2163 return(NULL);
2164 }
2165
2166 if (Ref == NULL) {
2167 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
2168 return(NULL);
2169 }
2170
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002171 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002172 if (table == NULL)
2173 return(NULL);
2174
2175 /*
2176 * Search the Ref list.
2177 */
2178 for (i = 0;i < table->nb_refs;i++) {
2179 cur = table->table[i];
2180 if (!xmlStrcmp(cur->value, Ref)) {
2181 return(cur->attr);
2182 }
2183 }
2184 return(NULL);
2185}
2186
2187/************************************************************************
2188 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002189 * Routines for validity checking *
2190 * *
2191 ************************************************************************/
2192
2193/**
2194 * xmlGetDtdElementDesc:
2195 * @dtd: a pointer to the DtD to search
2196 * @name: the element name
2197 *
2198 * Search the Dtd for the description of this element
2199 *
2200 * returns the xmlElementPtr if found or NULL
2201 */
2202
2203xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002204xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002205 xmlElementTablePtr table;
2206 xmlElementPtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002207 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002208 int i;
2209
2210 if (dtd == NULL) return(NULL);
2211 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002212 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002213
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00002214 if ((table->last >= 0) && (table->last < table->nb_elements)) {
2215 cur = table->table[table->last];
Daniel Veillardb05deb71999-08-10 19:04:08 +00002216 if (!xmlStrcmp(cur->name, name))
2217 return(cur);
2218 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00002219 for (i = 0;i < table->nb_elements;i++) {
2220 cur = table->table[i];
2221 if (!xmlStrcmp(cur->name, name)) {
2222 table->last = i;
2223 return(cur);
2224 }
2225 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002226
2227 /*
2228 * Specific case if name is a QName.
2229 */
2230 uqname = xmlSplitQName2(name, &prefix);
2231 if (uqname == NULL) return(NULL);
2232
2233 for (i = 0;i < table->nb_elements;i++) {
2234 cur = table->table[i];
2235 if ((!xmlStrcmp(cur->name, uqname)) &&
2236 ((prefix == cur->prefix) ||
2237 ((prefix != NULL) && (cur->prefix != NULL) &&
2238 (!xmlStrcmp(cur->prefix, prefix))))) {
2239 if (prefix != NULL) xmlFree(prefix);
2240 if (uqname != NULL) xmlFree(uqname);
2241 return(cur);
2242 }
2243 }
2244 if (prefix != NULL) xmlFree(prefix);
2245 if (uqname != NULL) xmlFree(uqname);
2246 return(NULL);
2247}
2248
2249/**
2250 * xmlGetDtdQElementDesc:
2251 * @dtd: a pointer to the DtD to search
2252 * @name: the element name
2253 * @prefix: the element namespace prefix
2254 *
2255 * Search the Dtd for the description of this element
2256 *
2257 * returns the xmlElementPtr if found or NULL
2258 */
2259
2260xmlElementPtr
2261xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2262 const xmlChar *prefix) {
2263 xmlElementTablePtr table;
2264 xmlElementPtr cur;
2265 int i;
2266
2267 if (dtd == NULL) return(NULL);
2268 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002269 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardbe803962000-06-28 23:40:59 +00002270
2271 for (i = 0;i < table->nb_elements;i++) {
2272 cur = table->table[i];
2273 if (!xmlStrcmp(cur->name, name) &&
2274 ((prefix == cur->prefix) ||
2275 ((prefix != NULL) && (cur->prefix != NULL) &&
2276 (!xmlStrcmp(cur->prefix, prefix)))))
2277 return(cur);
2278 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002279 return(NULL);
2280}
2281
2282/**
2283 * xmlGetDtdAttrDesc:
2284 * @dtd: a pointer to the DtD to search
2285 * @elem: the element name
2286 * @name: the attribute name
2287 *
2288 * Search the Dtd for the description of this attribute on
2289 * this element.
2290 *
2291 * returns the xmlAttributePtr if found or NULL
2292 */
2293
2294xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002295xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002296 xmlAttributeTablePtr table;
2297 xmlAttributePtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002298 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002299 int i;
2300
2301 if (dtd == NULL) return(NULL);
2302 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002303 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002304
2305 for (i = 0;i < table->nb_attributes;i++) {
2306 cur = table->table[i];
2307 if ((!xmlStrcmp(cur->name, name)) &&
2308 (!xmlStrcmp(cur->elem, elem)))
2309 return(cur);
2310 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002311
2312 /*
2313 * Specific case if name is a QName.
2314 */
2315 uqname = xmlSplitQName2(name, &prefix);
2316 if (uqname == NULL) return(NULL);
2317
2318 for (i = 0;i < table->nb_attributes;i++) {
2319 cur = table->table[i];
2320 if ((!xmlStrcmp(cur->name, uqname)) &&
2321 (!xmlStrcmp(cur->elem, elem)) &&
2322 ((prefix == cur->prefix) ||
2323 ((prefix != NULL) && (cur->prefix != NULL) &&
2324 (!xmlStrcmp(cur->prefix, prefix))))) {
2325 if (prefix != NULL) xmlFree(prefix);
2326 if (uqname != NULL) xmlFree(uqname);
2327 return(cur);
2328 }
2329 }
2330 if (prefix != NULL) xmlFree(prefix);
2331 if (uqname != NULL) xmlFree(uqname);
2332 return(NULL);
2333}
2334
2335/**
2336 * xmlGetDtdQAttrDesc:
2337 * @dtd: a pointer to the DtD to search
2338 * @elem: the element name
2339 * @name: the attribute name
2340 * @prefix: the attribute namespace prefix
2341 *
2342 * Search the Dtd for the description of this qualified attribute on
2343 * this element.
2344 *
2345 * returns the xmlAttributePtr if found or NULL
2346 */
2347
2348xmlAttributePtr
2349xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2350 const xmlChar *prefix) {
2351 xmlAttributeTablePtr table;
2352 xmlAttributePtr cur;
2353 int i;
2354
2355 if (dtd == NULL) return(NULL);
2356 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002357 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardbe803962000-06-28 23:40:59 +00002358
2359 for (i = 0;i < table->nb_attributes;i++) {
2360 cur = table->table[i];
2361 if ((!xmlStrcmp(cur->name, name)) &&
2362 (!xmlStrcmp(cur->elem, elem)) &&
2363 ((prefix == cur->prefix) ||
2364 ((prefix != NULL) && (cur->prefix != NULL) &&
2365 (!xmlStrcmp(cur->prefix, prefix)))))
2366 return(cur);
2367 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002368 return(NULL);
2369}
2370
2371/**
2372 * xmlGetDtdNotationDesc:
2373 * @dtd: a pointer to the DtD to search
2374 * @name: the notation name
2375 *
2376 * Search the Dtd for the description of this notation
2377 *
2378 * returns the xmlNotationPtr if found or NULL
2379 */
2380
2381xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002382xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002383 xmlNotationTablePtr table;
2384 xmlNotationPtr cur;
2385 int i;
2386
2387 if (dtd == NULL) return(NULL);
2388 if (dtd->notations == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002389 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002390
2391 for (i = 0;i < table->nb_notations;i++) {
2392 cur = table->table[i];
2393 if (!xmlStrcmp(cur->name, name))
2394 return(cur);
2395 }
2396 return(NULL);
2397}
2398
2399/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002400 * xmlValidateNotationUse:
2401 * @ctxt: the validation context
2402 * @doc: the document
2403 * @notationName: the notation name to check
2404 *
2405 * Validate that the given mame match a notation declaration.
2406 * - [ VC: Notation Declared ]
2407 *
2408 * returns 1 if valid or 0 otherwise
2409 */
2410
2411int
2412xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002413 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002414 xmlNotationPtr notaDecl;
2415 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2416
2417 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2418 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2419 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2420
2421 if (notaDecl == NULL) {
2422 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2423 notationName);
2424 return(0);
2425 }
2426 return(1);
2427}
2428
2429/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002430 * xmlIsMixedElement
2431 * @doc: the document
2432 * @name: the element name
2433 *
2434 * Search in the DtDs whether an element accept Mixed content (or ANY)
2435 * basically if it is supposed to accept text childs
2436 *
2437 * returns 0 if no, 1 if yes, and -1 if no element description is available
2438 */
2439
2440int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002441xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002442 xmlElementPtr elemDecl;
2443
2444 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2445
2446 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2447 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2448 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2449 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002450 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002451 case XML_ELEMENT_TYPE_ELEMENT:
2452 return(0);
2453 case XML_ELEMENT_TYPE_EMPTY:
2454 /*
2455 * return 1 for EMPTY since we want VC error to pop up
2456 * on <empty> </empty> for example
2457 */
2458 case XML_ELEMENT_TYPE_ANY:
2459 case XML_ELEMENT_TYPE_MIXED:
2460 return(1);
2461 }
2462 return(1);
2463}
2464
2465/**
2466 * xmlValidateNameValue:
2467 * @value: an Name value
2468 *
2469 * Validate that the given value match Name production
2470 *
2471 * returns 1 if valid or 0 otherwise
2472 */
2473
2474int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002475xmlValidateNameValue(const xmlChar *value) {
2476 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002477
2478 if (value == NULL) return(0);
2479 cur = value;
2480
2481 if (!IS_LETTER(*cur) && (*cur != '_') &&
2482 (*cur != ':')) {
2483 return(0);
2484 }
2485
2486 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2487 (*cur == '.') || (*cur == '-') ||
2488 (*cur == '_') || (*cur == ':') ||
2489 (IS_COMBINING(*cur)) ||
2490 (IS_EXTENDER(*cur)))
2491 cur++;
2492
2493 if (*cur != 0) return(0);
2494
2495 return(1);
2496}
2497
2498/**
2499 * xmlValidateNamesValue:
2500 * @value: an Names value
2501 *
2502 * Validate that the given value match Names production
2503 *
2504 * returns 1 if valid or 0 otherwise
2505 */
2506
2507int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002508xmlValidateNamesValue(const xmlChar *value) {
2509 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002510
2511 if (value == NULL) return(0);
2512 cur = value;
2513
2514 if (!IS_LETTER(*cur) && (*cur != '_') &&
2515 (*cur != ':')) {
2516 return(0);
2517 }
2518
2519 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2520 (*cur == '.') || (*cur == '-') ||
2521 (*cur == '_') || (*cur == ':') ||
2522 (IS_COMBINING(*cur)) ||
2523 (IS_EXTENDER(*cur)))
2524 cur++;
2525
2526 while (IS_BLANK(*cur)) {
2527 while (IS_BLANK(*cur)) cur++;
2528
2529 if (!IS_LETTER(*cur) && (*cur != '_') &&
2530 (*cur != ':')) {
2531 return(0);
2532 }
2533
2534 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2535 (*cur == '.') || (*cur == '-') ||
2536 (*cur == '_') || (*cur == ':') ||
2537 (IS_COMBINING(*cur)) ||
2538 (IS_EXTENDER(*cur)))
2539 cur++;
2540 }
2541
2542 if (*cur != 0) return(0);
2543
2544 return(1);
2545}
2546
2547/**
2548 * xmlValidateNmtokenValue:
2549 * @value: an Mntoken value
2550 *
2551 * Validate that the given value match Nmtoken production
2552 *
2553 * [ VC: Name Token ]
2554 *
2555 * returns 1 if valid or 0 otherwise
2556 */
2557
2558int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002559xmlValidateNmtokenValue(const xmlChar *value) {
2560 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002561
2562 if (value == NULL) return(0);
2563 cur = value;
2564
2565 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2566 (*cur != '.') && (*cur != '-') &&
2567 (*cur != '_') && (*cur != ':') &&
2568 (!IS_COMBINING(*cur)) &&
2569 (!IS_EXTENDER(*cur)))
2570 return(0);
2571
2572 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2573 (*cur == '.') || (*cur == '-') ||
2574 (*cur == '_') || (*cur == ':') ||
2575 (IS_COMBINING(*cur)) ||
2576 (IS_EXTENDER(*cur)))
2577 cur++;
2578
2579 if (*cur != 0) return(0);
2580
2581 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002582}
2583
2584/**
2585 * xmlValidateNmtokensValue:
2586 * @value: an Mntokens value
2587 *
2588 * Validate that the given value match Nmtokens production
2589 *
2590 * [ VC: Name Token ]
2591 *
2592 * returns 1 if valid or 0 otherwise
2593 */
2594
2595int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002596xmlValidateNmtokensValue(const xmlChar *value) {
2597 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002598
2599 if (value == NULL) return(0);
2600 cur = value;
2601
Daniel Veillardcf461992000-03-14 18:30:20 +00002602 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002603 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2604 (*cur != '.') && (*cur != '-') &&
2605 (*cur != '_') && (*cur != ':') &&
2606 (!IS_COMBINING(*cur)) &&
2607 (!IS_EXTENDER(*cur)))
2608 return(0);
2609
2610 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2611 (*cur == '.') || (*cur == '-') ||
2612 (*cur == '_') || (*cur == ':') ||
2613 (IS_COMBINING(*cur)) ||
2614 (IS_EXTENDER(*cur)))
2615 cur++;
2616
2617 while (IS_BLANK(*cur)) {
2618 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002619 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002620
2621 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2622 (*cur != '.') && (*cur != '-') &&
2623 (*cur != '_') && (*cur != ':') &&
2624 (!IS_COMBINING(*cur)) &&
2625 (!IS_EXTENDER(*cur)))
2626 return(0);
2627
2628 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2629 (*cur == '.') || (*cur == '-') ||
2630 (*cur == '_') || (*cur == ':') ||
2631 (IS_COMBINING(*cur)) ||
2632 (IS_EXTENDER(*cur)))
2633 cur++;
2634 }
2635
2636 if (*cur != 0) return(0);
2637
2638 return(1);
2639}
2640
2641/**
2642 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002643 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002644 * @doc: a document instance
2645 * @nota: a notation definition
2646 *
2647 * Try to validate a single notation definition
2648 * basically it does the following checks as described by the
2649 * XML-1.0 recommendation:
2650 * - it seems that no validity constraing exist on notation declarations
2651 * But this function get called anyway ...
2652 *
2653 * returns 1 if valid or 0 otherwise
2654 */
2655
2656int
2657xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2658 xmlNotationPtr nota) {
2659 int ret = 1;
2660
2661 return(ret);
2662}
2663
2664/**
2665 * xmlValidateAttributeValue:
2666 * @type: an attribute type
2667 * @value: an attribute value
2668 *
2669 * Validate that the given attribute value match the proper production
2670 *
2671 * [ VC: ID ]
2672 * Values of type ID must match the Name production....
2673 *
2674 * [ VC: IDREF ]
2675 * Values of type IDREF must match the Name production, and values
2676 * of type IDREFS must match Names ...
2677 *
2678 * [ VC: Entity Name ]
2679 * Values of type ENTITY must match the Name production, values
2680 * of type ENTITIES must match Names ...
2681 *
2682 * [ VC: Name Token ]
2683 * Values of type NMTOKEN must match the Nmtoken production; values
2684 * of type NMTOKENS must match Nmtokens.
2685 *
2686 * returns 1 if valid or 0 otherwise
2687 */
2688
2689int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002690xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002691 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002692 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002693 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002694 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002695 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002696 case XML_ATTRIBUTE_IDREF:
2697 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002698 case XML_ATTRIBUTE_NOTATION:
2699 return(xmlValidateNameValue(value));
2700 case XML_ATTRIBUTE_NMTOKENS:
2701 case XML_ATTRIBUTE_ENUMERATION:
2702 return(xmlValidateNmtokensValue(value));
2703 case XML_ATTRIBUTE_NMTOKEN:
2704 return(xmlValidateNmtokenValue(value));
2705 case XML_ATTRIBUTE_CDATA:
2706 break;
2707 }
2708 return(1);
2709}
2710
2711/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002712 * xmlValidateAttributeValue2:
2713 * @ctxt: the validation context
2714 * @doc: the document
2715 * @name: the attribute name (used for error reporting only)
2716 * @type: the attribute type
2717 * @value: the attribute value
2718 *
2719 * Validate that the given attribute value match a given type.
2720 * This typically cannot be done before having finished parsing
2721 * the subsets.
2722 *
2723 * [ VC: IDREF ]
2724 * Values of type IDREF must match one of the declared IDs
2725 * Values of type IDREFS must match a sequence of the declared IDs
2726 * each Name must match the value of an ID attribute on some element
2727 * in the XML document; i.e. IDREF values must match the value of
2728 * some ID attribute
2729 *
2730 * [ VC: Entity Name ]
2731 * Values of type ENTITY must match one declared entity
2732 * Values of type ENTITIES must match a sequence of declared entities
2733 *
2734 * [ VC: Notation Attributes ]
2735 * all notation names in the declaration must be declared.
2736 *
2737 * returns 1 if valid or 0 otherwise
2738 */
2739
2740int
2741xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2742 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2743 int ret = 1;
2744 switch (type) {
2745 case XML_ATTRIBUTE_IDREFS:
2746 case XML_ATTRIBUTE_IDREF:
2747 case XML_ATTRIBUTE_ID:
2748 case XML_ATTRIBUTE_NMTOKENS:
2749 case XML_ATTRIBUTE_ENUMERATION:
2750 case XML_ATTRIBUTE_NMTOKEN:
2751 case XML_ATTRIBUTE_CDATA:
2752 break;
2753 case XML_ATTRIBUTE_ENTITY: {
2754 xmlEntityPtr ent;
2755
2756 ent = xmlGetDocEntity(doc, value);
2757 if (ent == NULL) {
2758 VERROR(ctxt->userData,
2759 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2760 name, value);
2761 ret = 0;
2762 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2763 VERROR(ctxt->userData,
2764 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2765 name, value);
2766 ret = 0;
2767 }
2768 break;
2769 }
2770 case XML_ATTRIBUTE_ENTITIES: {
2771 xmlChar *dup, *nam = NULL, *cur, save;
2772 xmlEntityPtr ent;
2773
2774 dup = xmlStrdup(value);
2775 if (dup == NULL)
2776 return(0);
2777 cur = dup;
2778 while (*cur != 0) {
2779 nam = cur;
2780 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2781 save = *cur;
2782 *cur = 0;
2783 ent = xmlGetDocEntity(doc, nam);
2784 if (ent == NULL) {
2785 VERROR(ctxt->userData,
2786 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2787 name, nam);
2788 ret = 0;
2789 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2790 VERROR(ctxt->userData,
2791 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2792 name, nam);
2793 ret = 0;
2794 }
2795 if (save == 0)
2796 break;
2797 *cur = save;
2798 while (IS_BLANK(*cur)) cur++;
2799 }
2800 xmlFree(dup);
2801 break;
2802 }
2803 case XML_ATTRIBUTE_NOTATION: {
2804 xmlNotationPtr nota;
2805
2806 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2807 if ((nota == NULL) && (doc->extSubset != NULL))
2808 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2809
2810 if (nota == NULL) {
2811 VERROR(ctxt->userData,
2812 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2813 name, value);
2814 ret = 0;
2815 }
2816 break;
2817 }
2818 }
2819 return(ret);
2820}
2821
2822/**
2823 * xmlValidNormalizeAttributeValue:
2824 * @doc: the document
2825 * @elem: the parent
2826 * @name: the attribute name
2827 * @value: the attribute value
2828 *
2829 * Does the validation related extra step of the normalization of attribute
2830 * values:
2831 *
2832 * If the declared value is not CDATA, then the XML processor must further
2833 * process the normalized attribute value by discarding any leading and
2834 * trailing space (#x20) characters, and by replacing sequences of space
2835 * (#x20) characters by single space (#x20) character.
2836 *
2837 * returns a new normalized string if normalization is needed, NULL otherwise
2838 * the caller must free the returned value.
2839 */
2840
2841xmlChar *
2842xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2843 const xmlChar *name, const xmlChar *value) {
2844 xmlChar *ret, *dst;
2845 const xmlChar *src;
Daniel Veillardbe803962000-06-28 23:40:59 +00002846 xmlAttributePtr attrDecl = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002847
2848 if (doc == NULL) return(NULL);
2849 if (elem == NULL) return(NULL);
2850 if (name == NULL) return(NULL);
2851 if (value == NULL) return(NULL);
2852
Daniel Veillardbe803962000-06-28 23:40:59 +00002853 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2854 xmlChar qname[500];
2855#ifdef HAVE_SNPRINTF
2856 snprintf((char *) qname, sizeof(qname), "%s:%s",
2857 elem->ns->prefix, elem->name);
2858#else
2859 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
2860#endif
2861 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2862 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2863 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2864 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002865 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2866 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2867 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2868
2869 if (attrDecl == NULL)
2870 return(NULL);
2871 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2872 return(NULL);
2873
2874 ret = xmlStrdup(value);
2875 if (ret == NULL)
2876 return(NULL);
2877 src = value;
2878 dst = ret;
2879 while (*src == 0x20) src++;
2880 while (*src != 0) {
2881 if (*src == 0x20) {
2882 while (*src == 0x20) src++;
2883 if (*src != 0)
2884 *dst++ = 0x20;
2885 } else {
2886 *dst++ = *src++;
2887 }
2888 }
2889 *dst = 0;
2890 return(ret);
2891}
2892
2893/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002894 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002895 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002896 * @doc: a document instance
2897 * @attr: an attribute definition
2898 *
2899 * Try to validate a single attribute definition
2900 * basically it does the following checks as described by the
2901 * XML-1.0 recommendation:
2902 * - [ VC: Attribute Default Legal ]
2903 * - [ VC: Enumeration ]
2904 * - [ VC: ID Attribute Default ]
2905 *
2906 * The ID/IDREF uniqueness and matching are done separately
2907 *
2908 * returns 1 if valid or 0 otherwise
2909 */
2910
2911int
2912xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2913 xmlAttributePtr attr) {
2914 int ret = 1;
2915 int val;
2916 CHECK_DTD;
2917 if(attr == NULL) return(1);
2918
2919 /* Attribute Default Legal */
2920 /* Enumeration */
2921 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002922 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002923 if (val == 0) {
2924 VERROR(ctxt->userData,
2925 "Syntax of default value for attribute %s on %s is not valid\n",
2926 attr->name, attr->elem);
2927 }
2928 ret &= val;
2929 }
2930
2931 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002932 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002933 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2934 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2935 VERROR(ctxt->userData,
2936 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2937 attr->name, attr->elem);
2938 ret = 0;
2939 }
2940
Daniel Veillardb96e6431999-08-29 21:02:19 +00002941 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002942 if (attr->atype == XML_ATTRIBUTE_ID) {
2943 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002944
2945 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002946 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002947 attr->elem);
2948 if (elem != NULL) {
2949 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002950 } else {
2951 xmlAttributeTablePtr table;
2952 int i;
2953
2954 /*
2955 * The attribute may be declared in the internal subset and the
2956 * element in the external subset.
2957 */
2958 nbId = 0;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002959 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00002960 if (table != NULL) {
2961 for (i = 0;i < table->nb_attributes;i++) {
2962 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2963 (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2964 nbId++;
2965 }
2966 }
2967 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002968 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002969 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002970 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002971 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2972 attr->elem, nbId, attr->name);
2973 } else if (doc->extSubset != NULL) {
2974 int extId = 0;
2975 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2976 if (elem != NULL) {
2977 extId = xmlScanIDAttributeDecl(NULL, elem);
2978 }
2979 if (extId > 1) {
2980 VERROR(ctxt->userData,
2981 "Element %s has %d ID attribute defined in the external subset : %s\n",
2982 attr->elem, extId, attr->name);
2983 } else if (extId + nbId > 1) {
2984 VERROR(ctxt->userData,
2985"Element %s has ID attributes defined in the internal and external subset : %s\n",
2986 attr->elem, attr->name);
2987 }
2988 }
2989 }
2990
2991 /* Validity Constraint: Enumeration */
2992 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2993 xmlEnumerationPtr tree = attr->tree;
2994 while (tree != NULL) {
2995 if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2996 tree = tree->next;
2997 }
2998 if (tree == NULL) {
2999 VERROR(ctxt->userData,
3000"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
3001 attr->defaultValue, attr->name, attr->elem);
3002 ret = 0;
3003 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003004 }
3005
3006 return(ret);
3007}
3008
3009/**
3010 * xmlValidateElementDecl:
3011 * @ctxt: the validation context
3012 * @doc: a document instance
3013 * @elem: an element definition
3014 *
3015 * Try to validate a single element definition
3016 * basically it does the following checks as described by the
3017 * XML-1.0 recommendation:
3018 * - [ VC: One ID per Element Type ]
3019 * - [ VC: No Duplicate Types ]
3020 * - [ VC: Unique Element Type Declaration ]
3021 *
3022 * returns 1 if valid or 0 otherwise
3023 */
3024
3025int
3026xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3027 xmlElementPtr elem) {
3028 int ret = 1;
3029 xmlElementPtr tst;
3030
3031 CHECK_DTD;
3032
3033 if (elem == NULL) return(1);
3034
3035 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00003036 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003037 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003038 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003039
3040 cur = elem->content;
3041 while (cur != NULL) {
3042 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3043 if (cur->c1 == NULL) break;
3044 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3045 name = cur->c1->name;
3046 next = cur->c2;
3047 while (next != NULL) {
3048 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
3049 if (!xmlStrcmp(next->name, name)) {
3050 VERROR(ctxt->userData,
3051 "Definition of %s has duplicate references of %s\n",
3052 elem->name, name);
3053 ret = 0;
3054 }
3055 break;
3056 }
3057 if (next->c1 == NULL) break;
3058 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
3059 if (!xmlStrcmp(next->c1->name, name)) {
3060 VERROR(ctxt->userData,
3061 "Definition of %s has duplicate references of %s\n",
3062 elem->name, name);
3063 ret = 0;
3064 }
3065 next = next->c2;
3066 }
3067 }
3068 cur = cur->c2;
3069 }
3070 }
3071
3072 /* VC: Unique Element Type Declaration */
3073 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3074 if ((tst != NULL ) && (tst != elem)) {
3075 VERROR(ctxt->userData, "Redefinition of element %s\n",
3076 elem->name);
3077 ret = 0;
3078 }
3079 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3080 if ((tst != NULL ) && (tst != elem)) {
3081 VERROR(ctxt->userData, "Redefinition of element %s\n",
3082 elem->name);
3083 ret = 0;
3084 }
3085
3086 /* One ID per Element Type */
3087 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3088 ret = 0;
3089 }
3090 return(ret);
3091}
3092
3093/**
3094 * xmlValidateOneAttribute:
3095 * @ctxt: the validation context
3096 * @doc: a document instance
3097 * @elem: an element instance
3098 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00003099 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003100 *
3101 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00003102 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00003103 * XML-1.0 recommendation:
3104 * - [ VC: Attribute Value Type ]
3105 * - [ VC: Fixed Attribute Default ]
3106 * - [ VC: Entity Name ]
3107 * - [ VC: Name Token ]
3108 * - [ VC: ID ]
3109 * - [ VC: IDREF ]
3110 * - [ VC: Entity Name ]
3111 * - [ VC: Notation Attributes ]
3112 *
3113 * The ID/IDREF uniqueness and matching are done separately
3114 *
3115 * returns 1 if valid or 0 otherwise
3116 */
3117
3118int
3119xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003120 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003121 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00003122 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003123 int val;
3124 int ret = 1;
3125
3126 CHECK_DTD;
3127 if ((elem == NULL) || (elem->name == NULL)) return(0);
3128 if ((attr == NULL) || (attr->name == NULL)) return(0);
3129
Daniel Veillardbe803962000-06-28 23:40:59 +00003130 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3131 xmlChar qname[500];
3132#ifdef HAVE_SNPRINTF
3133 snprintf((char *) qname, sizeof(qname), "%s:%s",
3134 elem->ns->prefix, elem->name);
3135#else
3136 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
3137#endif
3138 if (attr->ns != NULL) {
3139 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3140 attr->name, attr->ns->prefix);
3141 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3142 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3143 attr->name, attr->ns->prefix);
3144 } else {
3145 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3146 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3147 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3148 qname, attr->name);
3149 }
3150 }
3151 if (attrDecl == NULL) {
3152 if (attr->ns != NULL) {
3153 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3154 attr->name, attr->ns->prefix);
3155 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3156 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3157 attr->name, attr->ns->prefix);
3158 } else {
3159 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3160 elem->name, attr->name);
3161 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3162 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3163 elem->name, attr->name);
3164 }
3165 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003166
3167
3168 /* Validity Constraint: Attribute Value Type */
3169 if (attrDecl == NULL) {
3170 VERROR(ctxt->userData,
3171 "No declaration for attribute %s on element %s\n",
3172 attr->name, elem->name);
3173 return(0);
3174 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003175 attr->atype = attrDecl->atype;
3176
3177 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003178 if (val == 0) {
3179 VERROR(ctxt->userData,
3180 "Syntax of value for attribute %s on %s is not valid\n",
3181 attr->name, elem->name);
3182 ret = 0;
3183 }
3184
Daniel Veillardcf461992000-03-14 18:30:20 +00003185 /* Validity constraint: Fixed Attribute Default */
3186 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3187 if (xmlStrcmp(value, attrDecl->defaultValue)) {
3188 VERROR(ctxt->userData,
3189 "Value for attribute %s on %s is differnt from default \"%s\"\n",
3190 attr->name, elem->name, attrDecl->defaultValue);
3191 ret = 0;
3192 }
3193 }
3194
Daniel Veillardb96e6431999-08-29 21:02:19 +00003195 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00003196 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003197 xmlAddID(ctxt, doc, value, attr);
3198 }
3199
Daniel Veillardcf461992000-03-14 18:30:20 +00003200 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3201 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003202 xmlAddRef(ctxt, doc, value, attr);
3203 }
3204
Daniel Veillardb05deb71999-08-10 19:04:08 +00003205 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00003206 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003207 xmlEnumerationPtr tree = attrDecl->tree;
3208 xmlNotationPtr nota;
3209
3210 /* First check that the given NOTATION was declared */
3211 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3212 if (nota == NULL)
3213 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3214
3215 if (nota == NULL) {
3216 VERROR(ctxt->userData,
3217 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3218 value, attr->name, elem->name);
3219 ret = 0;
3220 }
3221
3222 /* Second, verify that it's among the list */
3223 while (tree != NULL) {
3224 if (!xmlStrcmp(tree->name, value)) break;
3225 tree = tree->next;
3226 }
3227 if (tree == NULL) {
3228 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003229"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003230 value, attr->name, elem->name);
3231 ret = 0;
3232 }
3233 }
3234
3235 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00003236 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003237 xmlEnumerationPtr tree = attrDecl->tree;
3238 while (tree != NULL) {
3239 if (!xmlStrcmp(tree->name, value)) break;
3240 tree = tree->next;
3241 }
3242 if (tree == NULL) {
3243 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003244 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003245 value, attr->name, elem->name);
3246 ret = 0;
3247 }
3248 }
3249
3250 /* Fixed Attribute Default */
3251 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3252 (xmlStrcmp(attrDecl->defaultValue, value))) {
3253 VERROR(ctxt->userData,
3254 "Value for attribute %s on %s must be \"%s\"\n",
3255 attr->name, elem->name, attrDecl->defaultValue);
3256 ret = 0;
3257 }
3258
Daniel Veillardcf461992000-03-14 18:30:20 +00003259 /* Extra check for the attribute value */
3260 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3261 attrDecl->atype, value);
3262
Daniel Veillardb05deb71999-08-10 19:04:08 +00003263 return(ret);
3264}
3265
3266int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3267 xmlElementContentPtr cont);
3268
3269/**
3270 * xmlValidateElementTypeExpr:
3271 * @ctxt: the validation context
3272 * @child: pointer to the child list
3273 * @cont: pointer to the content declaration
3274 *
3275 * Try to validate the content of an element of type element
3276 * but don't handle the occurence factor
3277 *
3278 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3279 * also update child value in-situ.
3280 */
3281
3282int
3283xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3284 xmlElementContentPtr cont) {
3285 xmlNodePtr cur;
3286 int ret = 1;
3287
3288 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003289 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003290 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003291 if ((*child)->type == XML_ENTITY_REF_NODE) {
3292 /*
3293 * If there is an entity declared an it's not empty
3294 * Push the current node on the stack and process with the
3295 * entity content.
3296 */
3297 if (((*child)->children != NULL) &&
3298 ((*child)->children->children != NULL)) {
3299 nodeVPush(ctxt, *child);
3300 *child = (*child)->children->children;
3301 } else
3302 *child = (*child)->next;
3303 continue;
3304 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003305 if ((*child)->type == XML_PI_NODE) {
3306 *child = (*child)->next;
3307 continue;
3308 }
3309 if ((*child)->type == XML_COMMENT_NODE) {
3310 *child = (*child)->next;
3311 continue;
3312 }
3313 else if ((*child)->type != XML_ELEMENT_NODE) {
3314 return(-1);
3315 }
3316 break;
3317 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003318 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003319 switch (cont->type) {
3320 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003321 if (*child == NULL) return(0);
3322 if ((*child)->type == XML_TEXT_NODE) return(1);
3323 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003324 case XML_ELEMENT_CONTENT_ELEMENT:
3325 if (*child == NULL) return(0);
3326 ret = (!xmlStrcmp((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003327 if (ret == 1) {
3328 while ((*child)->next == NULL) {
3329 if (((*child)->parent != NULL) &&
3330 ((*child)->parent->type == XML_ENTITY_DECL)) {
3331 *child = nodeVPop(ctxt);
3332 } else
3333 break;
3334 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003335 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003336 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003337 return(ret);
3338 case XML_ELEMENT_CONTENT_OR:
3339 cur = *child;
3340 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3341 if (ret == -1) return(-1);
3342 if (ret == 1) {
3343 return(1);
3344 }
3345 /* rollback and retry the other path */
3346 *child = cur;
3347 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3348 if (ret == -1) return(-1);
3349 if (ret == 0) {
3350 *child = cur;
3351 return(0);
3352 }
3353 return(1);
3354 case XML_ELEMENT_CONTENT_SEQ:
3355 cur = *child;
3356 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3357 if (ret == -1) return(-1);
3358 if (ret == 0) {
3359 *child = cur;
3360 return(0);
3361 }
3362 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3363 if (ret == -1) return(-1);
3364 if (ret == 0) {
3365 *child = cur;
3366 return(0);
3367 }
3368 return(1);
3369 }
3370 return(ret);
3371}
3372
3373/**
3374 * xmlValidateElementTypeElement:
3375 * @ctxt: the validation context
3376 * @child: pointer to the child list
3377 * @cont: pointer to the content declaration
3378 *
3379 * Try to validate the content of an element of type element
3380 * yeah, Yet Another Regexp Implementation, and recursive
3381 *
3382 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3383 * also update child and content values in-situ.
3384 */
3385
3386int
3387xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3388 xmlElementContentPtr cont) {
3389 xmlNodePtr cur;
3390 int ret = 1;
3391
3392 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003393
3394 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003395 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003396 if ((*child)->type == XML_ENTITY_REF_NODE) {
3397 /*
3398 * If there is an entity declared an it's not empty
3399 * Push the current node on the stack and process with the
3400 * entity content.
3401 */
3402 if (((*child)->children != NULL) &&
3403 ((*child)->children->children != NULL)) {
3404 nodeVPush(ctxt, *child);
3405 *child = (*child)->children->children;
3406 } else
3407 *child = (*child)->next;
3408 continue;
3409 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003410 if ((*child)->type == XML_PI_NODE) {
3411 *child = (*child)->next;
3412 continue;
3413 }
3414 if ((*child)->type == XML_COMMENT_NODE) {
3415 *child = (*child)->next;
3416 continue;
3417 }
3418 else if ((*child)->type != XML_ELEMENT_NODE) {
3419 return(-1);
3420 }
3421 break;
3422 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003423 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003424 cur = *child;
3425 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3426 if (ret == -1) return(-1);
3427 switch (cont->ocur) {
3428 case XML_ELEMENT_CONTENT_ONCE:
3429 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003430 /* skip ignorable elems */
3431 while ((*child != NULL) &&
3432 (((*child)->type == XML_PI_NODE) ||
3433 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003434 while ((*child)->next == NULL) {
3435 if (((*child)->parent != NULL) &&
3436 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3437 *child = (*child)->parent;
3438 } else
3439 break;
3440 }
3441 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003442 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003443 return(1);
3444 }
3445 *child = cur;
3446 return(0);
3447 case XML_ELEMENT_CONTENT_OPT:
3448 if (ret == 0) {
3449 *child = cur;
3450 return(1);
3451 }
3452 break;
3453 case XML_ELEMENT_CONTENT_MULT:
3454 if (ret == 0) {
3455 *child = cur;
3456 break;
3457 }
3458 /* no break on purpose */
3459 case XML_ELEMENT_CONTENT_PLUS:
3460 if (ret == 0) {
3461 *child = cur;
3462 return(0);
3463 }
3464 do {
3465 cur = *child;
3466 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3467 } while (ret == 1);
3468 if (ret == -1) return(-1);
3469 *child = cur;
3470 break;
3471 }
3472 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003473 if ((*child)->type == XML_ENTITY_REF_NODE) {
3474 /*
3475 * If there is an entity declared an it's not empty
3476 * Push the current node on the stack and process with the
3477 * entity content.
3478 */
3479 if (((*child)->children != NULL) &&
3480 ((*child)->children->children != NULL)) {
3481 nodeVPush(ctxt, *child);
3482 *child = (*child)->children->children;
3483 } else
3484 *child = (*child)->next;
3485 continue;
3486 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003487 if ((*child)->type == XML_PI_NODE) {
3488 *child = (*child)->next;
3489 continue;
3490 }
3491 if ((*child)->type == XML_COMMENT_NODE) {
3492 *child = (*child)->next;
3493 continue;
3494 }
3495 else if ((*child)->type != XML_ELEMENT_NODE) {
3496 return(-1);
3497 }
3498 break;
3499 }
3500 return(1);
3501}
3502
3503/**
3504 * xmlSprintfElementChilds:
3505 * @buf: an output buffer
3506 * @content: An element
3507 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3508 *
3509 * This will dump the list of childs to the buffer
3510 * Intended just for the debug routine
3511 */
3512void
3513xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3514 xmlNodePtr cur;
3515
3516 if (node == NULL) return;
3517 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003518 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003519 while (cur != NULL) {
3520 switch (cur->type) {
3521 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003522 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003523 if (cur->next != NULL)
3524 strcat(buf, " ");
3525 break;
3526 case XML_TEXT_NODE:
3527 case XML_CDATA_SECTION_NODE:
3528 case XML_ENTITY_REF_NODE:
3529 strcat(buf, "CDATA");
3530 if (cur->next != NULL)
3531 strcat(buf, " ");
3532 break;
3533 case XML_ATTRIBUTE_NODE:
3534 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003535 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003536 case XML_DOCUMENT_TYPE_NODE:
3537 case XML_DOCUMENT_FRAG_NODE:
3538 case XML_NOTATION_NODE:
3539 strcat(buf, "???");
3540 if (cur->next != NULL)
3541 strcat(buf, " ");
3542 break;
3543 case XML_ENTITY_NODE:
3544 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003545 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003546 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003547 case XML_ELEMENT_DECL:
3548 case XML_ATTRIBUTE_DECL:
3549 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003550 break;
3551 }
3552 cur = cur->next;
3553 }
3554 if (glob) strcat(buf, ")");
3555}
3556
3557
3558/**
3559 * xmlValidateOneElement:
3560 * @ctxt: the validation context
3561 * @doc: a document instance
3562 * @elem: an element instance
3563 *
3564 * Try to validate a single element and it's attributes,
3565 * basically it does the following checks as described by the
3566 * XML-1.0 recommendation:
3567 * - [ VC: Element Valid ]
3568 * - [ VC: Required Attribute ]
3569 * Then call xmlValidateOneAttribute() for each attribute present.
3570 *
3571 * The ID/IDREF checkings are done separately
3572 *
3573 * returns 1 if valid or 0 otherwise
3574 */
3575
3576int
3577xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3578 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003579 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003580 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003581 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003582 xmlNodePtr child;
3583 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003584 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003585
3586 CHECK_DTD;
3587
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003588 if (elem == NULL) return(0);
3589 if (elem->type == XML_TEXT_NODE) {
3590 }
3591 switch (elem->type) {
3592 case XML_ATTRIBUTE_NODE:
3593 VERROR(ctxt->userData,
3594 "Attribute element not expected here\n");
3595 return(0);
3596 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003597 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003598 VERROR(ctxt->userData, "Text element has childs !\n");
3599 return(0);
3600 }
3601 if (elem->properties != NULL) {
3602 VERROR(ctxt->userData, "Text element has attributes !\n");
3603 return(0);
3604 }
3605 if (elem->ns != NULL) {
3606 VERROR(ctxt->userData, "Text element has namespace !\n");
3607 return(0);
3608 }
Daniel Veillard87b95392000-08-12 21:12:04 +00003609 if (elem->nsDef != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003610 VERROR(ctxt->userData,
3611 "Text element carries namespace definitions !\n");
3612 return(0);
3613 }
3614 if (elem->content == NULL) {
3615 VERROR(ctxt->userData,
3616 "Text element has no content !\n");
3617 return(0);
3618 }
3619 return(1);
3620 case XML_CDATA_SECTION_NODE:
3621 case XML_ENTITY_REF_NODE:
3622 case XML_PI_NODE:
3623 case XML_COMMENT_NODE:
3624 return(1);
3625 case XML_ENTITY_NODE:
3626 VERROR(ctxt->userData,
3627 "Entity element not expected here\n");
3628 return(0);
3629 case XML_NOTATION_NODE:
3630 VERROR(ctxt->userData,
3631 "Notation element not expected here\n");
3632 return(0);
3633 case XML_DOCUMENT_NODE:
3634 case XML_DOCUMENT_TYPE_NODE:
3635 case XML_DOCUMENT_FRAG_NODE:
3636 VERROR(ctxt->userData,
3637 "Document element not expected here\n");
3638 return(0);
3639 case XML_HTML_DOCUMENT_NODE:
3640 VERROR(ctxt->userData,
3641 "\n");
3642 return(0);
3643 case XML_ELEMENT_NODE:
3644 break;
3645 default:
3646 VERROR(ctxt->userData,
3647 "unknown element type %d\n", elem->type);
3648 return(0);
3649 }
3650 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003651
Daniel Veillardbe803962000-06-28 23:40:59 +00003652 /*
3653 * Fetch the declaration for the qualified name
3654 */
3655 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3656 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3657 elem->name, elem->ns->prefix);
3658 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3659 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3660 elem->name, elem->ns->prefix);
3661 }
3662
3663 /*
3664 * Fetch the declaration for the non qualified name
3665 */
3666 if (elemDecl == NULL) {
3667 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3668 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3669 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3670 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003671 if (elemDecl == NULL) {
3672 VERROR(ctxt->userData, "No declaration for element %s\n",
3673 elem->name);
3674 return(0);
3675 }
3676
3677 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003678 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003679 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003680 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003681 VERROR(ctxt->userData,
3682 "Element %s was declared EMPTY this one has content\n",
3683 elem->name);
3684 ret = 0;
3685 }
3686 break;
3687 case XML_ELEMENT_TYPE_ANY:
3688 /* I don't think anything is required then */
3689 break;
3690 case XML_ELEMENT_TYPE_MIXED:
3691 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003692 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003693 while (child != NULL) {
3694 if (child->type == XML_ELEMENT_NODE) {
3695 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003696 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3697 xmlChar qname[500];
3698#ifdef HAVE_SNPRINTF
3699 snprintf((char *) qname, sizeof(qname), "%s:%s",
3700 child->ns->prefix, child->name);
3701#else
3702 sprintf(qname, "%s:%s", child->name, child->ns->prefix);
3703#endif
3704 cont = elemDecl->content;
3705 while (cont != NULL) {
3706 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3707 if (!xmlStrcmp(cont->name, qname)) break;
3708 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3709 (cont->c1 != NULL) &&
3710 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
3711 if (!xmlStrcmp(cont->c1->name, qname)) break;
3712 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3713 (cont->c1 == NULL) ||
3714 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3715 /* Internal error !!! */
3716 fprintf(stderr, "Internal: MIXED struct bad\n");
3717 break;
3718 }
3719 cont = cont->c2;
3720 }
3721 if (cont != NULL)
3722 goto child_ok;
3723 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003724 cont = elemDecl->content;
3725 while (cont != NULL) {
3726 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3727 if (!xmlStrcmp(cont->name, name)) break;
3728 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3729 (cont->c1 != NULL) &&
3730 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3731 if (!xmlStrcmp(cont->c1->name, name)) break;
3732 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3733 (cont->c1 == NULL) ||
3734 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3735 /* Internal error !!! */
3736 fprintf(stderr, "Internal: MIXED struct bad\n");
3737 break;
3738 }
3739 cont = cont->c2;
3740 }
3741 if (cont == NULL) {
3742 VERROR(ctxt->userData,
3743 "Element %s is not declared in %s list of possible childs\n",
3744 name, elem->name);
3745 ret = 0;
3746 }
3747 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003748child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003749 child = child->next;
3750 }
3751 break;
3752 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003753 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003754 cont = elemDecl->content;
3755 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3756 if ((ret == 0) || (child != NULL)) {
3757 char expr[1000];
3758 char list[2000];
3759
3760 expr[0] = 0;
3761 xmlSprintfElementContent(expr, cont, 1);
3762 list[0] = 0;
3763 xmlSprintfElementChilds(list, elem, 1);
3764
3765 VERROR(ctxt->userData,
3766 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3767 elem->name, expr, list);
3768 ret = 0;
3769 }
3770 break;
3771 }
3772
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003773 /* [ VC: Required Attribute ] */
3774 attr = elemDecl->attributes;
3775 while (attr != NULL) {
3776 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3777 xmlAttrPtr attrib;
3778 int qualified = -1;
3779
3780 attrib = elem->properties;
3781 while (attrib != NULL) {
3782 if (!xmlStrcmp(attrib->name, attr->name)) {
3783 if (attr->prefix != NULL) {
3784 xmlNsPtr nameSpace = attrib->ns;
3785
3786 if (nameSpace == NULL)
3787 nameSpace = elem->ns;
3788 /*
3789 * qualified names handling is problematic, having a
3790 * different prefix should be possible but DTDs don't
3791 * allow to define the URI instead of the prefix :-(
3792 */
3793 if (nameSpace == NULL) {
3794 if (qualified < 0)
3795 qualified = 0;
3796 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3797 if (qualified < 1)
3798 qualified = 1;
3799 } else
3800 goto found;
3801 } else {
3802 /*
3803 * We should allow applications to define namespaces
3804 * for their application even if the DTD doesn't
3805 * carry one, otherwise, basically we would always
3806 * break.
3807 */
3808 goto found;
3809 }
3810 }
3811 attrib = attrib->next;
3812 }
3813 if (qualified == -1) {
3814 if (attr->prefix == NULL) {
3815 VERROR(ctxt->userData,
3816 "Element %s doesn't carry attribute %s\n",
3817 elem->name, attr->name);
3818 } else {
3819 VERROR(ctxt->userData,
3820 "Element %s doesn't carry attribute %s:%s\n",
3821 elem->name, attr->prefix,attr->name);
3822 }
3823 } else if (qualified == 0) {
3824 VWARNING(ctxt->userData,
3825 "Element %s required attribute %s:%s has no prefix\n",
3826 elem->name, attr->prefix,attr->name);
3827 } else if (qualified == 1) {
3828 VWARNING(ctxt->userData,
3829 "Element %s required attribute %s:%s has different prefix\n",
3830 elem->name, attr->prefix,attr->name);
3831 }
3832 }
3833found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003834 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003835 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003836 return(ret);
3837}
3838
3839/**
3840 * xmlValidateRoot:
3841 * @ctxt: the validation context
3842 * @doc: a document instance
3843 *
3844 * Try to validate a the root element
3845 * basically it does the following check as described by the
3846 * XML-1.0 recommendation:
3847 * - [ VC: Root Element Type ]
3848 * it doesn't try to recurse or apply other check to the element
3849 *
3850 * returns 1 if valid or 0 otherwise
3851 */
3852
3853int
3854xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003855 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003856 if (doc == NULL) return(0);
3857
3858 if ((doc->intSubset == NULL) ||
3859 (doc->intSubset->name == NULL)) {
3860 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3861 return(0);
3862 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003863 root = xmlDocGetRootElement(doc);
3864 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003865 VERROR(ctxt->userData, "Not valid: no root element\n");
3866 return(0);
3867 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003868
3869 /*
3870 * Check first the document root against the NQName
3871 */
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003872 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003873 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3874 xmlChar qname[500];
3875#ifdef HAVE_SNPRINTF
3876 snprintf((char *) qname, sizeof(qname), "%s:%s",
3877 root->ns->prefix, root->name);
3878#else
3879 sprintf(qname, "%s:%s", root->name, root->ns->prefix);
3880#endif
3881 if (!xmlStrcmp(doc->intSubset->name, qname))
3882 goto name_ok;
3883 }
3884 if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
3885 (!xmlStrcmp(root->name, BAD_CAST "html")))
3886 goto name_ok;
3887 VERROR(ctxt->userData,
3888 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3889 root->name, doc->intSubset->name);
3890 return(0);
3891
Daniel Veillardb05deb71999-08-10 19:04:08 +00003892 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003893name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003894 return(1);
3895}
3896
3897
3898/**
3899 * xmlValidateElement:
3900 * @ctxt: the validation context
3901 * @doc: a document instance
3902 * @elem: an element instance
3903 *
3904 * Try to validate the subtree under an element
3905 *
3906 * returns 1 if valid or 0 otherwise
3907 */
3908
3909int
3910xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003911 xmlNodePtr child;
3912 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003913 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003914 int ret = 1;
3915
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003916 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003917 CHECK_DTD;
3918
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003919 ret &= xmlValidateOneElement(ctxt, doc, elem);
3920 attr = elem->properties;
3921 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003922 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003923 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3924 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003925 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003926 attr= attr->next;
3927 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003928 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003929 while (child != NULL) {
3930 ret &= xmlValidateElement(ctxt, doc, child);
3931 child = child->next;
3932 }
3933
3934 return(ret);
3935}
3936
3937/**
3938 * xmlValidateDocumentFinal:
3939 * @ctxt: the validation context
3940 * @doc: a document instance
3941 *
3942 * Does the final step for the document validation once all the
3943 * incremental validation steps have been completed
3944 *
3945 * basically it does the following checks described by the XML Rec
3946 *
3947 *
3948 * returns 1 if valid or 0 otherwise
3949 */
3950
3951int
3952xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3953 int ret = 1, i;
3954 xmlRefTablePtr table;
3955 xmlAttrPtr id;
3956
3957 if (doc == NULL) {
3958 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3959 return(0);
3960 }
3961
3962 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003963 * Check all the NOTATION/NOTATIONS attributes
3964 */
3965 /*
3966 * Check all the ENTITY/ENTITIES attributes definition for validity
3967 */
3968 /*
3969 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003970 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003971 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003972 if (table != NULL) {
3973 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003974 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3975 id = xmlGetID(doc, table->table[i]->value);
3976 if (id == NULL) {
3977 VERROR(ctxt->userData,
3978 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3979 table->table[i]->attr->name, table->table[i]->value);
3980 ret = 0;
3981 }
3982 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
3983 xmlChar *dup, *name = NULL, *cur, save;
3984
3985 dup = xmlStrdup(table->table[i]->value);
3986 if (dup == NULL)
3987 return(0);
3988 cur = dup;
3989 while (*cur != 0) {
3990 name = cur;
3991 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3992 save = *cur;
3993 *cur = 0;
3994 id = xmlGetID(doc, name);
3995 if (id == NULL) {
3996 VERROR(ctxt->userData,
3997 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3998 table->table[i]->attr->name, name);
3999 ret = 0;
4000 }
4001 if (save == 0)
4002 break;
4003 *cur = save;
4004 while (IS_BLANK(*cur)) cur++;
4005 }
4006 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004007 }
4008 }
4009 }
4010 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004011}
4012
4013/**
4014 * xmlValidateDtd:
4015 * @ctxt: the validation context
4016 * @doc: a document instance
4017 * @dtd: a dtd instance
4018 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004019 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00004020 *
4021 * basically it does check all the definitions in the DtD.
4022 *
4023 * returns 1 if valid or 0 otherwise
4024 */
4025
4026int
4027xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004028 int ret;
4029 xmlDtdPtr oldExt;
4030 xmlNodePtr root;
4031
4032 if (dtd == NULL) return(0);
4033 if (doc == NULL) return(0);
4034 oldExt = doc->extSubset;
4035 doc->extSubset = dtd;
4036 ret = xmlValidateRoot(ctxt, doc);
4037 if (ret == 0) {
4038 doc->extSubset = oldExt;
4039 return(ret);
4040 }
4041 root = xmlDocGetRootElement(doc);
4042 ret = xmlValidateElement(ctxt, doc, root);
4043 ret &= xmlValidateDocumentFinal(ctxt, doc);
4044 doc->extSubset = oldExt;
4045 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004046}
4047
4048/**
Daniel Veillardcf461992000-03-14 18:30:20 +00004049 * xmlValidateDtdFinal:
4050 * @ctxt: the validation context
4051 * @doc: a document instance
4052 *
4053 * Does the final step for the dtds validation once all the
4054 * subsets have been parsed
4055 *
4056 * basically it does the following checks described by the XML Rec
4057 * - check that ENTITY and ENTITIES type attributes default or
4058 * possible values matches one of the defined entities.
4059 * - check that NOTATION type attributes default or
4060 * possible values matches one of the defined notations.
4061 *
4062 * returns 1 if valid or 0 otherwise
4063 */
4064
4065int
4066xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4067 int ret = 1, i;
4068 xmlDtdPtr dtd;
4069 xmlAttributeTablePtr table;
4070 xmlAttributePtr cur;
4071
4072 if (doc == NULL) return(0);
4073 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4074 return(0);
4075 dtd = doc->intSubset;
4076 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004077 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004078
4079 for (i = 0;i < table->nb_attributes;i++) {
4080 cur = table->table[i];
4081 switch (cur->atype) {
4082 case XML_ATTRIBUTE_CDATA:
4083 case XML_ATTRIBUTE_ID:
4084 case XML_ATTRIBUTE_IDREF :
4085 case XML_ATTRIBUTE_IDREFS:
4086 case XML_ATTRIBUTE_NMTOKEN:
4087 case XML_ATTRIBUTE_NMTOKENS:
4088 case XML_ATTRIBUTE_ENUMERATION:
4089 break;
4090 case XML_ATTRIBUTE_ENTITY:
4091 case XML_ATTRIBUTE_ENTITIES:
4092 case XML_ATTRIBUTE_NOTATION:
4093 if (cur->defaultValue != NULL) {
4094 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4095 cur->atype, cur->defaultValue);
4096 }
4097 if (cur->tree != NULL) {
4098 xmlEnumerationPtr tree = cur->tree;
4099 while (tree != NULL) {
4100 ret &= xmlValidateAttributeValue2(ctxt, doc,
4101 cur->name, cur->atype, tree->name);
4102 tree = tree->next;
4103 }
4104 }
4105 }
4106 }
4107 }
4108 dtd = doc->extSubset;
4109 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004110 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004111
4112 for (i = 0;i < table->nb_attributes;i++) {
4113 cur = table->table[i];
4114 switch (cur->atype) {
4115 case XML_ATTRIBUTE_CDATA:
4116 case XML_ATTRIBUTE_ID:
4117 case XML_ATTRIBUTE_IDREF :
4118 case XML_ATTRIBUTE_IDREFS:
4119 case XML_ATTRIBUTE_NMTOKEN:
4120 case XML_ATTRIBUTE_NMTOKENS:
4121 case XML_ATTRIBUTE_ENUMERATION:
4122 break;
4123 case XML_ATTRIBUTE_ENTITY:
4124 case XML_ATTRIBUTE_ENTITIES:
4125 case XML_ATTRIBUTE_NOTATION:
4126 if (cur->defaultValue != NULL) {
4127 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4128 cur->atype, cur->defaultValue);
4129 }
4130 if (cur->tree != NULL) {
4131 xmlEnumerationPtr tree = cur->tree;
4132 while (tree != NULL) {
4133 ret &= xmlValidateAttributeValue2(ctxt, doc,
4134 cur->name, cur->atype, tree->name);
4135 tree = tree->next;
4136 }
4137 }
4138 }
4139 }
4140 }
4141 return(ret);
4142}
4143
4144/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00004145 * xmlValidateDocument:
4146 * @ctxt: the validation context
4147 * @doc: a document instance
4148 *
4149 * Try to validate the document instance
4150 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004151 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00004152 * i.e. validates the internal and external subset (if present)
4153 * and validate the document tree.
4154 *
4155 * returns 1 if valid or 0 otherwise
4156 */
4157
4158int
4159xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004160 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004161 xmlNodePtr root;
4162
4163 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4164 return(0);
4165 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4166 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4167 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4168 doc->intSubset->SystemID);
4169 if (doc->extSubset == NULL) {
4170 if (doc->intSubset->SystemID != NULL) {
4171 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004172 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004173 doc->intSubset->SystemID);
4174 } else {
4175 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004176 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004177 doc->intSubset->ExternalID);
4178 }
4179 return(0);
4180 }
4181 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004182
Daniel Veillardcf461992000-03-14 18:30:20 +00004183 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004184 if (!xmlValidateRoot(ctxt, doc)) return(0);
4185
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004186 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00004187 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004188 ret &= xmlValidateDocumentFinal(ctxt, doc);
4189 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004190}
4191
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004192
4193/************************************************************************
4194 * *
4195 * Routines for dynamic validation editing *
4196 * *
4197 ************************************************************************/
4198
4199/**
4200 * xmlValidGetPotentialChildren:
4201 * @ctree: an element content tree
4202 * @list: an array to store the list of child names
4203 * @len: a pointer to the number of element in the list
4204 * @max: the size of the array
4205 *
4206 * Build/extend a list of potential children allowed by the content tree
4207 *
4208 * returns the number of element in the list, or -1 in case of error.
4209 */
4210
4211int
4212xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4213 int *len, int max) {
4214 int i;
4215
4216 if ((ctree == NULL) || (list == NULL) || (len == NULL))
4217 return(-1);
4218 if (*len >= max) return(*len);
4219
4220 switch (ctree->type) {
4221 case XML_ELEMENT_CONTENT_PCDATA:
4222 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00004223 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
4224 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004225 break;
4226 case XML_ELEMENT_CONTENT_ELEMENT:
4227 for (i = 0; i < *len;i++)
4228 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
4229 list[(*len)++] = ctree->name;
4230 break;
4231 case XML_ELEMENT_CONTENT_SEQ:
4232 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4233 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4234 break;
4235 case XML_ELEMENT_CONTENT_OR:
4236 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4237 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4238 break;
4239 }
4240
4241 return(*len);
4242}
4243
4244/**
4245 * xmlValidGetValidElements:
4246 * @prev: an element to insert after
4247 * @next: an element to insert next
4248 * @list: an array to store the list of child names
4249 * @max: the size of the array
4250 *
4251 * This function returns the list of authorized children to insert
4252 * within an existing tree while respecting the validity constraints
4253 * forced by the Dtd. The insertion point is defined using @prev and
4254 * @next in the following ways:
4255 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4256 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4257 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4258 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4259 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4260 *
4261 * pointers to the element names are inserted at the beginning of the array
4262 * and do not need to be freed.
4263 *
4264 * returns the number of element in the list, or -1 in case of error. If
4265 * the function returns the value @max the caller is invited to grow the
4266 * receiving array and retry.
4267 */
4268
4269int
4270xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4271 int max) {
4272 int nb_valid_elements = 0;
4273 const xmlChar *elements[256];
4274 int nb_elements = 0, i;
4275
4276 xmlNode *ref_node;
4277 xmlNode *parent;
4278 xmlNode *test_node;
4279
4280 xmlNode *prev_next;
4281 xmlNode *next_prev;
4282 xmlNode *parent_childs;
4283 xmlNode *parent_last;
4284
4285 xmlElement *element_desc;
4286
4287 if (prev == NULL && next == NULL)
4288 return(-1);
4289
4290 if (list == NULL) return(-1);
4291 if (max <= 0) return(-1);
4292
4293 nb_valid_elements = 0;
4294 ref_node = prev ? prev : next;
4295 parent = ref_node->parent;
4296
4297 /*
4298 * Retrieves the parent element declaration
4299 */
4300 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4301 parent->name);
4302 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4303 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4304 parent->name);
4305 if (element_desc == NULL) return(-1);
4306
4307 /*
4308 * Do a backup of the current tree structure
4309 */
4310 prev_next = prev ? prev->next : NULL;
4311 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004312 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004313 parent_last = parent->last;
4314
4315 /*
4316 * Creates a dummy node and insert it into the tree
4317 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004318 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004319 test_node->doc = ref_node->doc;
4320 test_node->parent = parent;
4321 test_node->prev = prev;
4322 test_node->next = next;
4323
4324 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00004325 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004326
4327 if (next) next->prev = test_node;
4328 else parent->last = test_node;
4329
4330 /*
4331 * Insert each potential child node and check if the parent is
4332 * still valid
4333 */
4334 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4335 elements, &nb_elements, 256);
4336
4337 for (i = 0;i < nb_elements;i++) {
4338 test_node->name = elements[i];
4339 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4340 int j;
4341
4342 for (j = 0; j < nb_valid_elements;j++)
4343 if (!xmlStrcmp(elements[i], list[j])) break;
4344 list[nb_valid_elements++] = elements[i];
4345 if (nb_valid_elements >= max) break;
4346 }
4347 }
4348
4349 /*
4350 * Restore the tree structure
4351 */
4352 if (prev) prev->next = prev_next;
4353 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004354 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004355 parent->last = parent_last;
4356
4357 return(nb_valid_elements);
4358}