blob: dc091e661267892683fe3c3c7b43ae54718b93d5 [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
Daniel Veillard39c7d712000-09-10 16:14:55 +00002859 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00002860#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00002861 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00002862 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2863 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2864 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2865 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002866 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2867 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2868 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2869
2870 if (attrDecl == NULL)
2871 return(NULL);
2872 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2873 return(NULL);
2874
2875 ret = xmlStrdup(value);
2876 if (ret == NULL)
2877 return(NULL);
2878 src = value;
2879 dst = ret;
2880 while (*src == 0x20) src++;
2881 while (*src != 0) {
2882 if (*src == 0x20) {
2883 while (*src == 0x20) src++;
2884 if (*src != 0)
2885 *dst++ = 0x20;
2886 } else {
2887 *dst++ = *src++;
2888 }
2889 }
2890 *dst = 0;
2891 return(ret);
2892}
2893
2894/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002895 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002896 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002897 * @doc: a document instance
2898 * @attr: an attribute definition
2899 *
2900 * Try to validate a single attribute definition
2901 * basically it does the following checks as described by the
2902 * XML-1.0 recommendation:
2903 * - [ VC: Attribute Default Legal ]
2904 * - [ VC: Enumeration ]
2905 * - [ VC: ID Attribute Default ]
2906 *
2907 * The ID/IDREF uniqueness and matching are done separately
2908 *
2909 * returns 1 if valid or 0 otherwise
2910 */
2911
2912int
2913xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2914 xmlAttributePtr attr) {
2915 int ret = 1;
2916 int val;
2917 CHECK_DTD;
2918 if(attr == NULL) return(1);
2919
2920 /* Attribute Default Legal */
2921 /* Enumeration */
2922 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002923 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002924 if (val == 0) {
2925 VERROR(ctxt->userData,
2926 "Syntax of default value for attribute %s on %s is not valid\n",
2927 attr->name, attr->elem);
2928 }
2929 ret &= val;
2930 }
2931
2932 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002933 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002934 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2935 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2936 VERROR(ctxt->userData,
2937 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2938 attr->name, attr->elem);
2939 ret = 0;
2940 }
2941
Daniel Veillardb96e6431999-08-29 21:02:19 +00002942 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002943 if (attr->atype == XML_ATTRIBUTE_ID) {
2944 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002945
2946 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002947 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002948 attr->elem);
2949 if (elem != NULL) {
2950 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002951 } else {
2952 xmlAttributeTablePtr table;
2953 int i;
2954
2955 /*
2956 * The attribute may be declared in the internal subset and the
2957 * element in the external subset.
2958 */
2959 nbId = 0;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002960 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00002961 if (table != NULL) {
2962 for (i = 0;i < table->nb_attributes;i++) {
2963 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2964 (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2965 nbId++;
2966 }
2967 }
2968 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002969 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002970 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002971 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002972 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2973 attr->elem, nbId, attr->name);
2974 } else if (doc->extSubset != NULL) {
2975 int extId = 0;
2976 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2977 if (elem != NULL) {
2978 extId = xmlScanIDAttributeDecl(NULL, elem);
2979 }
2980 if (extId > 1) {
2981 VERROR(ctxt->userData,
2982 "Element %s has %d ID attribute defined in the external subset : %s\n",
2983 attr->elem, extId, attr->name);
2984 } else if (extId + nbId > 1) {
2985 VERROR(ctxt->userData,
2986"Element %s has ID attributes defined in the internal and external subset : %s\n",
2987 attr->elem, attr->name);
2988 }
2989 }
2990 }
2991
2992 /* Validity Constraint: Enumeration */
2993 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2994 xmlEnumerationPtr tree = attr->tree;
2995 while (tree != NULL) {
2996 if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2997 tree = tree->next;
2998 }
2999 if (tree == NULL) {
3000 VERROR(ctxt->userData,
3001"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
3002 attr->defaultValue, attr->name, attr->elem);
3003 ret = 0;
3004 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003005 }
3006
3007 return(ret);
3008}
3009
3010/**
3011 * xmlValidateElementDecl:
3012 * @ctxt: the validation context
3013 * @doc: a document instance
3014 * @elem: an element definition
3015 *
3016 * Try to validate a single element definition
3017 * basically it does the following checks as described by the
3018 * XML-1.0 recommendation:
3019 * - [ VC: One ID per Element Type ]
3020 * - [ VC: No Duplicate Types ]
3021 * - [ VC: Unique Element Type Declaration ]
3022 *
3023 * returns 1 if valid or 0 otherwise
3024 */
3025
3026int
3027xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3028 xmlElementPtr elem) {
3029 int ret = 1;
3030 xmlElementPtr tst;
3031
3032 CHECK_DTD;
3033
3034 if (elem == NULL) return(1);
3035
3036 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00003037 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003038 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003039 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003040
3041 cur = elem->content;
3042 while (cur != NULL) {
3043 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3044 if (cur->c1 == NULL) break;
3045 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3046 name = cur->c1->name;
3047 next = cur->c2;
3048 while (next != NULL) {
3049 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
3050 if (!xmlStrcmp(next->name, name)) {
3051 VERROR(ctxt->userData,
3052 "Definition of %s has duplicate references of %s\n",
3053 elem->name, name);
3054 ret = 0;
3055 }
3056 break;
3057 }
3058 if (next->c1 == NULL) break;
3059 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
3060 if (!xmlStrcmp(next->c1->name, name)) {
3061 VERROR(ctxt->userData,
3062 "Definition of %s has duplicate references of %s\n",
3063 elem->name, name);
3064 ret = 0;
3065 }
3066 next = next->c2;
3067 }
3068 }
3069 cur = cur->c2;
3070 }
3071 }
3072
3073 /* VC: Unique Element Type Declaration */
3074 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3075 if ((tst != NULL ) && (tst != elem)) {
3076 VERROR(ctxt->userData, "Redefinition of element %s\n",
3077 elem->name);
3078 ret = 0;
3079 }
3080 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3081 if ((tst != NULL ) && (tst != elem)) {
3082 VERROR(ctxt->userData, "Redefinition of element %s\n",
3083 elem->name);
3084 ret = 0;
3085 }
3086
3087 /* One ID per Element Type */
3088 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3089 ret = 0;
3090 }
3091 return(ret);
3092}
3093
3094/**
3095 * xmlValidateOneAttribute:
3096 * @ctxt: the validation context
3097 * @doc: a document instance
3098 * @elem: an element instance
3099 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00003100 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003101 *
3102 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00003103 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00003104 * XML-1.0 recommendation:
3105 * - [ VC: Attribute Value Type ]
3106 * - [ VC: Fixed Attribute Default ]
3107 * - [ VC: Entity Name ]
3108 * - [ VC: Name Token ]
3109 * - [ VC: ID ]
3110 * - [ VC: IDREF ]
3111 * - [ VC: Entity Name ]
3112 * - [ VC: Notation Attributes ]
3113 *
3114 * The ID/IDREF uniqueness and matching are done separately
3115 *
3116 * returns 1 if valid or 0 otherwise
3117 */
3118
3119int
3120xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003121 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003122 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00003123 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003124 int val;
3125 int ret = 1;
3126
3127 CHECK_DTD;
3128 if ((elem == NULL) || (elem->name == NULL)) return(0);
3129 if ((attr == NULL) || (attr->name == NULL)) return(0);
3130
Daniel Veillardbe803962000-06-28 23:40:59 +00003131 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3132 xmlChar qname[500];
3133#ifdef HAVE_SNPRINTF
3134 snprintf((char *) qname, sizeof(qname), "%s:%s",
3135 elem->ns->prefix, elem->name);
3136#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003137 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003138#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003139 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00003140 if (attr->ns != NULL) {
3141 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3142 attr->name, attr->ns->prefix);
3143 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3144 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3145 attr->name, attr->ns->prefix);
3146 } else {
3147 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3148 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3149 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3150 qname, attr->name);
3151 }
3152 }
3153 if (attrDecl == NULL) {
3154 if (attr->ns != NULL) {
3155 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3156 attr->name, attr->ns->prefix);
3157 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3158 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3159 attr->name, attr->ns->prefix);
3160 } else {
3161 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3162 elem->name, attr->name);
3163 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3164 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3165 elem->name, attr->name);
3166 }
3167 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003168
3169
3170 /* Validity Constraint: Attribute Value Type */
3171 if (attrDecl == NULL) {
3172 VERROR(ctxt->userData,
3173 "No declaration for attribute %s on element %s\n",
3174 attr->name, elem->name);
3175 return(0);
3176 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003177 attr->atype = attrDecl->atype;
3178
3179 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003180 if (val == 0) {
3181 VERROR(ctxt->userData,
3182 "Syntax of value for attribute %s on %s is not valid\n",
3183 attr->name, elem->name);
3184 ret = 0;
3185 }
3186
Daniel Veillardcf461992000-03-14 18:30:20 +00003187 /* Validity constraint: Fixed Attribute Default */
3188 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3189 if (xmlStrcmp(value, attrDecl->defaultValue)) {
3190 VERROR(ctxt->userData,
3191 "Value for attribute %s on %s is differnt from default \"%s\"\n",
3192 attr->name, elem->name, attrDecl->defaultValue);
3193 ret = 0;
3194 }
3195 }
3196
Daniel Veillardb96e6431999-08-29 21:02:19 +00003197 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00003198 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003199 xmlAddID(ctxt, doc, value, attr);
3200 }
3201
Daniel Veillardcf461992000-03-14 18:30:20 +00003202 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3203 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003204 xmlAddRef(ctxt, doc, value, attr);
3205 }
3206
Daniel Veillardb05deb71999-08-10 19:04:08 +00003207 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00003208 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003209 xmlEnumerationPtr tree = attrDecl->tree;
3210 xmlNotationPtr nota;
3211
3212 /* First check that the given NOTATION was declared */
3213 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3214 if (nota == NULL)
3215 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3216
3217 if (nota == NULL) {
3218 VERROR(ctxt->userData,
3219 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3220 value, attr->name, elem->name);
3221 ret = 0;
3222 }
3223
3224 /* Second, verify that it's among the list */
3225 while (tree != NULL) {
3226 if (!xmlStrcmp(tree->name, value)) break;
3227 tree = tree->next;
3228 }
3229 if (tree == NULL) {
3230 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003231"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003232 value, attr->name, elem->name);
3233 ret = 0;
3234 }
3235 }
3236
3237 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00003238 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003239 xmlEnumerationPtr tree = attrDecl->tree;
3240 while (tree != NULL) {
3241 if (!xmlStrcmp(tree->name, value)) break;
3242 tree = tree->next;
3243 }
3244 if (tree == NULL) {
3245 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003246 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003247 value, attr->name, elem->name);
3248 ret = 0;
3249 }
3250 }
3251
3252 /* Fixed Attribute Default */
3253 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3254 (xmlStrcmp(attrDecl->defaultValue, value))) {
3255 VERROR(ctxt->userData,
3256 "Value for attribute %s on %s must be \"%s\"\n",
3257 attr->name, elem->name, attrDecl->defaultValue);
3258 ret = 0;
3259 }
3260
Daniel Veillardcf461992000-03-14 18:30:20 +00003261 /* Extra check for the attribute value */
3262 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3263 attrDecl->atype, value);
3264
Daniel Veillardb05deb71999-08-10 19:04:08 +00003265 return(ret);
3266}
3267
3268int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3269 xmlElementContentPtr cont);
3270
3271/**
3272 * xmlValidateElementTypeExpr:
3273 * @ctxt: the validation context
3274 * @child: pointer to the child list
3275 * @cont: pointer to the content declaration
3276 *
3277 * Try to validate the content of an element of type element
3278 * but don't handle the occurence factor
3279 *
3280 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3281 * also update child value in-situ.
3282 */
3283
3284int
3285xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3286 xmlElementContentPtr cont) {
3287 xmlNodePtr cur;
3288 int ret = 1;
3289
3290 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003291 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003292 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003293 if ((*child)->type == XML_ENTITY_REF_NODE) {
3294 /*
3295 * If there is an entity declared an it's not empty
3296 * Push the current node on the stack and process with the
3297 * entity content.
3298 */
3299 if (((*child)->children != NULL) &&
3300 ((*child)->children->children != NULL)) {
3301 nodeVPush(ctxt, *child);
3302 *child = (*child)->children->children;
3303 } else
3304 *child = (*child)->next;
3305 continue;
3306 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003307 if ((*child)->type == XML_PI_NODE) {
3308 *child = (*child)->next;
3309 continue;
3310 }
3311 if ((*child)->type == XML_COMMENT_NODE) {
3312 *child = (*child)->next;
3313 continue;
3314 }
3315 else if ((*child)->type != XML_ELEMENT_NODE) {
3316 return(-1);
3317 }
3318 break;
3319 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003320 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003321 switch (cont->type) {
3322 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003323 if (*child == NULL) return(0);
3324 if ((*child)->type == XML_TEXT_NODE) return(1);
3325 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003326 case XML_ELEMENT_CONTENT_ELEMENT:
3327 if (*child == NULL) return(0);
3328 ret = (!xmlStrcmp((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003329 if (ret == 1) {
3330 while ((*child)->next == NULL) {
3331 if (((*child)->parent != NULL) &&
3332 ((*child)->parent->type == XML_ENTITY_DECL)) {
3333 *child = nodeVPop(ctxt);
3334 } else
3335 break;
3336 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003337 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003338 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003339 return(ret);
3340 case XML_ELEMENT_CONTENT_OR:
3341 cur = *child;
3342 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3343 if (ret == -1) return(-1);
3344 if (ret == 1) {
3345 return(1);
3346 }
3347 /* rollback and retry the other path */
3348 *child = cur;
3349 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3350 if (ret == -1) return(-1);
3351 if (ret == 0) {
3352 *child = cur;
3353 return(0);
3354 }
3355 return(1);
3356 case XML_ELEMENT_CONTENT_SEQ:
3357 cur = *child;
3358 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3359 if (ret == -1) return(-1);
3360 if (ret == 0) {
3361 *child = cur;
3362 return(0);
3363 }
3364 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3365 if (ret == -1) return(-1);
3366 if (ret == 0) {
3367 *child = cur;
3368 return(0);
3369 }
3370 return(1);
3371 }
3372 return(ret);
3373}
3374
3375/**
3376 * xmlValidateElementTypeElement:
3377 * @ctxt: the validation context
3378 * @child: pointer to the child list
3379 * @cont: pointer to the content declaration
3380 *
3381 * Try to validate the content of an element of type element
3382 * yeah, Yet Another Regexp Implementation, and recursive
3383 *
3384 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3385 * also update child and content values in-situ.
3386 */
3387
3388int
3389xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3390 xmlElementContentPtr cont) {
3391 xmlNodePtr cur;
3392 int ret = 1;
3393
3394 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003395
3396 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003397 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003398 if ((*child)->type == XML_ENTITY_REF_NODE) {
3399 /*
3400 * If there is an entity declared an it's not empty
3401 * Push the current node on the stack and process with the
3402 * entity content.
3403 */
3404 if (((*child)->children != NULL) &&
3405 ((*child)->children->children != NULL)) {
3406 nodeVPush(ctxt, *child);
3407 *child = (*child)->children->children;
3408 } else
3409 *child = (*child)->next;
3410 continue;
3411 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003412 if ((*child)->type == XML_PI_NODE) {
3413 *child = (*child)->next;
3414 continue;
3415 }
3416 if ((*child)->type == XML_COMMENT_NODE) {
3417 *child = (*child)->next;
3418 continue;
3419 }
3420 else if ((*child)->type != XML_ELEMENT_NODE) {
3421 return(-1);
3422 }
3423 break;
3424 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003425 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003426 cur = *child;
3427 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3428 if (ret == -1) return(-1);
3429 switch (cont->ocur) {
3430 case XML_ELEMENT_CONTENT_ONCE:
3431 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003432 /* skip ignorable elems */
3433 while ((*child != NULL) &&
3434 (((*child)->type == XML_PI_NODE) ||
3435 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003436 while ((*child)->next == NULL) {
3437 if (((*child)->parent != NULL) &&
3438 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3439 *child = (*child)->parent;
3440 } else
3441 break;
3442 }
3443 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003444 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003445 return(1);
3446 }
3447 *child = cur;
3448 return(0);
3449 case XML_ELEMENT_CONTENT_OPT:
3450 if (ret == 0) {
3451 *child = cur;
3452 return(1);
3453 }
3454 break;
3455 case XML_ELEMENT_CONTENT_MULT:
3456 if (ret == 0) {
3457 *child = cur;
3458 break;
3459 }
3460 /* no break on purpose */
3461 case XML_ELEMENT_CONTENT_PLUS:
3462 if (ret == 0) {
3463 *child = cur;
3464 return(0);
3465 }
3466 do {
3467 cur = *child;
3468 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3469 } while (ret == 1);
3470 if (ret == -1) return(-1);
3471 *child = cur;
3472 break;
3473 }
3474 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003475 if ((*child)->type == XML_ENTITY_REF_NODE) {
3476 /*
3477 * If there is an entity declared an it's not empty
3478 * Push the current node on the stack and process with the
3479 * entity content.
3480 */
3481 if (((*child)->children != NULL) &&
3482 ((*child)->children->children != NULL)) {
3483 nodeVPush(ctxt, *child);
3484 *child = (*child)->children->children;
3485 } else
3486 *child = (*child)->next;
3487 continue;
3488 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003489 if ((*child)->type == XML_PI_NODE) {
3490 *child = (*child)->next;
3491 continue;
3492 }
3493 if ((*child)->type == XML_COMMENT_NODE) {
3494 *child = (*child)->next;
3495 continue;
3496 }
3497 else if ((*child)->type != XML_ELEMENT_NODE) {
3498 return(-1);
3499 }
3500 break;
3501 }
3502 return(1);
3503}
3504
3505/**
3506 * xmlSprintfElementChilds:
3507 * @buf: an output buffer
3508 * @content: An element
3509 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3510 *
3511 * This will dump the list of childs to the buffer
3512 * Intended just for the debug routine
3513 */
3514void
3515xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3516 xmlNodePtr cur;
3517
3518 if (node == NULL) return;
3519 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003520 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003521 while (cur != NULL) {
3522 switch (cur->type) {
3523 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003524 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003525 if (cur->next != NULL)
3526 strcat(buf, " ");
3527 break;
3528 case XML_TEXT_NODE:
3529 case XML_CDATA_SECTION_NODE:
3530 case XML_ENTITY_REF_NODE:
3531 strcat(buf, "CDATA");
3532 if (cur->next != NULL)
3533 strcat(buf, " ");
3534 break;
3535 case XML_ATTRIBUTE_NODE:
3536 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003537 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003538 case XML_DOCUMENT_TYPE_NODE:
3539 case XML_DOCUMENT_FRAG_NODE:
3540 case XML_NOTATION_NODE:
3541 strcat(buf, "???");
3542 if (cur->next != NULL)
3543 strcat(buf, " ");
3544 break;
3545 case XML_ENTITY_NODE:
3546 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003547 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003548 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003549 case XML_ELEMENT_DECL:
3550 case XML_ATTRIBUTE_DECL:
3551 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003552 break;
3553 }
3554 cur = cur->next;
3555 }
3556 if (glob) strcat(buf, ")");
3557}
3558
3559
3560/**
3561 * xmlValidateOneElement:
3562 * @ctxt: the validation context
3563 * @doc: a document instance
3564 * @elem: an element instance
3565 *
3566 * Try to validate a single element and it's attributes,
3567 * basically it does the following checks as described by the
3568 * XML-1.0 recommendation:
3569 * - [ VC: Element Valid ]
3570 * - [ VC: Required Attribute ]
3571 * Then call xmlValidateOneAttribute() for each attribute present.
3572 *
3573 * The ID/IDREF checkings are done separately
3574 *
3575 * returns 1 if valid or 0 otherwise
3576 */
3577
3578int
3579xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3580 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003581 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003582 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003583 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003584 xmlNodePtr child;
3585 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003586 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003587
3588 CHECK_DTD;
3589
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003590 if (elem == NULL) return(0);
3591 if (elem->type == XML_TEXT_NODE) {
3592 }
3593 switch (elem->type) {
3594 case XML_ATTRIBUTE_NODE:
3595 VERROR(ctxt->userData,
3596 "Attribute element not expected here\n");
3597 return(0);
3598 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003599 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003600 VERROR(ctxt->userData, "Text element has childs !\n");
3601 return(0);
3602 }
3603 if (elem->properties != NULL) {
3604 VERROR(ctxt->userData, "Text element has attributes !\n");
3605 return(0);
3606 }
3607 if (elem->ns != NULL) {
3608 VERROR(ctxt->userData, "Text element has namespace !\n");
3609 return(0);
3610 }
Daniel Veillard87b95392000-08-12 21:12:04 +00003611 if (elem->nsDef != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003612 VERROR(ctxt->userData,
3613 "Text element carries namespace definitions !\n");
3614 return(0);
3615 }
3616 if (elem->content == NULL) {
3617 VERROR(ctxt->userData,
3618 "Text element has no content !\n");
3619 return(0);
3620 }
3621 return(1);
3622 case XML_CDATA_SECTION_NODE:
3623 case XML_ENTITY_REF_NODE:
3624 case XML_PI_NODE:
3625 case XML_COMMENT_NODE:
3626 return(1);
3627 case XML_ENTITY_NODE:
3628 VERROR(ctxt->userData,
3629 "Entity element not expected here\n");
3630 return(0);
3631 case XML_NOTATION_NODE:
3632 VERROR(ctxt->userData,
3633 "Notation element not expected here\n");
3634 return(0);
3635 case XML_DOCUMENT_NODE:
3636 case XML_DOCUMENT_TYPE_NODE:
3637 case XML_DOCUMENT_FRAG_NODE:
3638 VERROR(ctxt->userData,
3639 "Document element not expected here\n");
3640 return(0);
3641 case XML_HTML_DOCUMENT_NODE:
3642 VERROR(ctxt->userData,
3643 "\n");
3644 return(0);
3645 case XML_ELEMENT_NODE:
3646 break;
3647 default:
3648 VERROR(ctxt->userData,
3649 "unknown element type %d\n", elem->type);
3650 return(0);
3651 }
3652 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003653
Daniel Veillardbe803962000-06-28 23:40:59 +00003654 /*
3655 * Fetch the declaration for the qualified name
3656 */
3657 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3658 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3659 elem->name, elem->ns->prefix);
3660 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3661 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3662 elem->name, elem->ns->prefix);
3663 }
3664
3665 /*
3666 * Fetch the declaration for the non qualified name
3667 */
3668 if (elemDecl == NULL) {
3669 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3670 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3671 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3672 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003673 if (elemDecl == NULL) {
3674 VERROR(ctxt->userData, "No declaration for element %s\n",
3675 elem->name);
3676 return(0);
3677 }
3678
3679 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003680 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003681 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003682 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003683 VERROR(ctxt->userData,
3684 "Element %s was declared EMPTY this one has content\n",
3685 elem->name);
3686 ret = 0;
3687 }
3688 break;
3689 case XML_ELEMENT_TYPE_ANY:
3690 /* I don't think anything is required then */
3691 break;
3692 case XML_ELEMENT_TYPE_MIXED:
3693 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003694 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003695 while (child != NULL) {
3696 if (child->type == XML_ELEMENT_NODE) {
3697 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003698 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3699 xmlChar qname[500];
3700#ifdef HAVE_SNPRINTF
3701 snprintf((char *) qname, sizeof(qname), "%s:%s",
3702 child->ns->prefix, child->name);
3703#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003704 sprintf((char *) qname, "%s:%s",
3705 child->ns->prefix, child->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003706#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003707 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00003708 cont = elemDecl->content;
3709 while (cont != NULL) {
3710 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3711 if (!xmlStrcmp(cont->name, qname)) break;
3712 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3713 (cont->c1 != NULL) &&
3714 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
3715 if (!xmlStrcmp(cont->c1->name, qname)) break;
3716 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3717 (cont->c1 == NULL) ||
3718 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3719 /* Internal error !!! */
3720 fprintf(stderr, "Internal: MIXED struct bad\n");
3721 break;
3722 }
3723 cont = cont->c2;
3724 }
3725 if (cont != NULL)
3726 goto child_ok;
3727 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003728 cont = elemDecl->content;
3729 while (cont != NULL) {
3730 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3731 if (!xmlStrcmp(cont->name, name)) break;
3732 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3733 (cont->c1 != NULL) &&
3734 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3735 if (!xmlStrcmp(cont->c1->name, name)) break;
3736 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3737 (cont->c1 == NULL) ||
3738 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3739 /* Internal error !!! */
3740 fprintf(stderr, "Internal: MIXED struct bad\n");
3741 break;
3742 }
3743 cont = cont->c2;
3744 }
3745 if (cont == NULL) {
3746 VERROR(ctxt->userData,
3747 "Element %s is not declared in %s list of possible childs\n",
3748 name, elem->name);
3749 ret = 0;
3750 }
3751 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003752child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003753 child = child->next;
3754 }
3755 break;
3756 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003757 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003758 cont = elemDecl->content;
3759 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3760 if ((ret == 0) || (child != NULL)) {
3761 char expr[1000];
3762 char list[2000];
3763
3764 expr[0] = 0;
3765 xmlSprintfElementContent(expr, cont, 1);
3766 list[0] = 0;
3767 xmlSprintfElementChilds(list, elem, 1);
3768
3769 VERROR(ctxt->userData,
3770 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3771 elem->name, expr, list);
3772 ret = 0;
3773 }
3774 break;
3775 }
3776
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003777 /* [ VC: Required Attribute ] */
3778 attr = elemDecl->attributes;
3779 while (attr != NULL) {
3780 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3781 xmlAttrPtr attrib;
3782 int qualified = -1;
3783
3784 attrib = elem->properties;
3785 while (attrib != NULL) {
3786 if (!xmlStrcmp(attrib->name, attr->name)) {
3787 if (attr->prefix != NULL) {
3788 xmlNsPtr nameSpace = attrib->ns;
3789
3790 if (nameSpace == NULL)
3791 nameSpace = elem->ns;
3792 /*
3793 * qualified names handling is problematic, having a
3794 * different prefix should be possible but DTDs don't
3795 * allow to define the URI instead of the prefix :-(
3796 */
3797 if (nameSpace == NULL) {
3798 if (qualified < 0)
3799 qualified = 0;
3800 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3801 if (qualified < 1)
3802 qualified = 1;
3803 } else
3804 goto found;
3805 } else {
3806 /*
3807 * We should allow applications to define namespaces
3808 * for their application even if the DTD doesn't
3809 * carry one, otherwise, basically we would always
3810 * break.
3811 */
3812 goto found;
3813 }
3814 }
3815 attrib = attrib->next;
3816 }
3817 if (qualified == -1) {
3818 if (attr->prefix == NULL) {
3819 VERROR(ctxt->userData,
3820 "Element %s doesn't carry attribute %s\n",
3821 elem->name, attr->name);
3822 } else {
3823 VERROR(ctxt->userData,
3824 "Element %s doesn't carry attribute %s:%s\n",
3825 elem->name, attr->prefix,attr->name);
3826 }
3827 } else if (qualified == 0) {
3828 VWARNING(ctxt->userData,
3829 "Element %s required attribute %s:%s has no prefix\n",
3830 elem->name, attr->prefix,attr->name);
3831 } else if (qualified == 1) {
3832 VWARNING(ctxt->userData,
3833 "Element %s required attribute %s:%s has different prefix\n",
3834 elem->name, attr->prefix,attr->name);
3835 }
3836 }
3837found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003838 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003839 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003840 return(ret);
3841}
3842
3843/**
3844 * xmlValidateRoot:
3845 * @ctxt: the validation context
3846 * @doc: a document instance
3847 *
3848 * Try to validate a the root element
3849 * basically it does the following check as described by the
3850 * XML-1.0 recommendation:
3851 * - [ VC: Root Element Type ]
3852 * it doesn't try to recurse or apply other check to the element
3853 *
3854 * returns 1 if valid or 0 otherwise
3855 */
3856
3857int
3858xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003859 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003860 if (doc == NULL) return(0);
3861
3862 if ((doc->intSubset == NULL) ||
3863 (doc->intSubset->name == NULL)) {
3864 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3865 return(0);
3866 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003867 root = xmlDocGetRootElement(doc);
3868 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003869 VERROR(ctxt->userData, "Not valid: no root element\n");
3870 return(0);
3871 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003872
3873 /*
3874 * Check first the document root against the NQName
3875 */
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003876 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003877 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3878 xmlChar qname[500];
3879#ifdef HAVE_SNPRINTF
3880 snprintf((char *) qname, sizeof(qname), "%s:%s",
3881 root->ns->prefix, root->name);
3882#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003883 sprintf((char *) qname, "%s:%s", root->ns->prefix, root->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003884#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003885 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00003886 if (!xmlStrcmp(doc->intSubset->name, qname))
3887 goto name_ok;
3888 }
3889 if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
3890 (!xmlStrcmp(root->name, BAD_CAST "html")))
3891 goto name_ok;
3892 VERROR(ctxt->userData,
3893 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3894 root->name, doc->intSubset->name);
3895 return(0);
3896
Daniel Veillardb05deb71999-08-10 19:04:08 +00003897 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003898name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003899 return(1);
3900}
3901
3902
3903/**
3904 * xmlValidateElement:
3905 * @ctxt: the validation context
3906 * @doc: a document instance
3907 * @elem: an element instance
3908 *
3909 * Try to validate the subtree under an element
3910 *
3911 * returns 1 if valid or 0 otherwise
3912 */
3913
3914int
3915xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003916 xmlNodePtr child;
3917 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003918 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003919 int ret = 1;
3920
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003921 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003922 CHECK_DTD;
3923
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003924 ret &= xmlValidateOneElement(ctxt, doc, elem);
3925 attr = elem->properties;
3926 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003927 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003928 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3929 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003930 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003931 attr= attr->next;
3932 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003933 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003934 while (child != NULL) {
3935 ret &= xmlValidateElement(ctxt, doc, child);
3936 child = child->next;
3937 }
3938
3939 return(ret);
3940}
3941
3942/**
3943 * xmlValidateDocumentFinal:
3944 * @ctxt: the validation context
3945 * @doc: a document instance
3946 *
3947 * Does the final step for the document validation once all the
3948 * incremental validation steps have been completed
3949 *
3950 * basically it does the following checks described by the XML Rec
3951 *
3952 *
3953 * returns 1 if valid or 0 otherwise
3954 */
3955
3956int
3957xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3958 int ret = 1, i;
3959 xmlRefTablePtr table;
3960 xmlAttrPtr id;
3961
3962 if (doc == NULL) {
3963 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3964 return(0);
3965 }
3966
3967 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003968 * Check all the NOTATION/NOTATIONS attributes
3969 */
3970 /*
3971 * Check all the ENTITY/ENTITIES attributes definition for validity
3972 */
3973 /*
3974 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003975 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003976 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003977 if (table != NULL) {
3978 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003979 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3980 id = xmlGetID(doc, table->table[i]->value);
3981 if (id == NULL) {
3982 VERROR(ctxt->userData,
3983 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3984 table->table[i]->attr->name, table->table[i]->value);
3985 ret = 0;
3986 }
3987 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
3988 xmlChar *dup, *name = NULL, *cur, save;
3989
3990 dup = xmlStrdup(table->table[i]->value);
3991 if (dup == NULL)
3992 return(0);
3993 cur = dup;
3994 while (*cur != 0) {
3995 name = cur;
3996 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3997 save = *cur;
3998 *cur = 0;
3999 id = xmlGetID(doc, name);
4000 if (id == NULL) {
4001 VERROR(ctxt->userData,
4002 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
4003 table->table[i]->attr->name, name);
4004 ret = 0;
4005 }
4006 if (save == 0)
4007 break;
4008 *cur = save;
4009 while (IS_BLANK(*cur)) cur++;
4010 }
4011 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004012 }
4013 }
4014 }
4015 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004016}
4017
4018/**
4019 * xmlValidateDtd:
4020 * @ctxt: the validation context
4021 * @doc: a document instance
4022 * @dtd: a dtd instance
4023 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004024 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00004025 *
4026 * basically it does check all the definitions in the DtD.
4027 *
4028 * returns 1 if valid or 0 otherwise
4029 */
4030
4031int
4032xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004033 int ret;
4034 xmlDtdPtr oldExt;
4035 xmlNodePtr root;
4036
4037 if (dtd == NULL) return(0);
4038 if (doc == NULL) return(0);
4039 oldExt = doc->extSubset;
4040 doc->extSubset = dtd;
4041 ret = xmlValidateRoot(ctxt, doc);
4042 if (ret == 0) {
4043 doc->extSubset = oldExt;
4044 return(ret);
4045 }
4046 root = xmlDocGetRootElement(doc);
4047 ret = xmlValidateElement(ctxt, doc, root);
4048 ret &= xmlValidateDocumentFinal(ctxt, doc);
4049 doc->extSubset = oldExt;
4050 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004051}
4052
4053/**
Daniel Veillardcf461992000-03-14 18:30:20 +00004054 * xmlValidateDtdFinal:
4055 * @ctxt: the validation context
4056 * @doc: a document instance
4057 *
4058 * Does the final step for the dtds validation once all the
4059 * subsets have been parsed
4060 *
4061 * basically it does the following checks described by the XML Rec
4062 * - check that ENTITY and ENTITIES type attributes default or
4063 * possible values matches one of the defined entities.
4064 * - check that NOTATION type attributes default or
4065 * possible values matches one of the defined notations.
4066 *
4067 * returns 1 if valid or 0 otherwise
4068 */
4069
4070int
4071xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4072 int ret = 1, i;
4073 xmlDtdPtr dtd;
4074 xmlAttributeTablePtr table;
4075 xmlAttributePtr cur;
4076
4077 if (doc == NULL) return(0);
4078 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4079 return(0);
4080 dtd = doc->intSubset;
4081 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004082 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004083
4084 for (i = 0;i < table->nb_attributes;i++) {
4085 cur = table->table[i];
4086 switch (cur->atype) {
4087 case XML_ATTRIBUTE_CDATA:
4088 case XML_ATTRIBUTE_ID:
4089 case XML_ATTRIBUTE_IDREF :
4090 case XML_ATTRIBUTE_IDREFS:
4091 case XML_ATTRIBUTE_NMTOKEN:
4092 case XML_ATTRIBUTE_NMTOKENS:
4093 case XML_ATTRIBUTE_ENUMERATION:
4094 break;
4095 case XML_ATTRIBUTE_ENTITY:
4096 case XML_ATTRIBUTE_ENTITIES:
4097 case XML_ATTRIBUTE_NOTATION:
4098 if (cur->defaultValue != NULL) {
4099 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4100 cur->atype, cur->defaultValue);
4101 }
4102 if (cur->tree != NULL) {
4103 xmlEnumerationPtr tree = cur->tree;
4104 while (tree != NULL) {
4105 ret &= xmlValidateAttributeValue2(ctxt, doc,
4106 cur->name, cur->atype, tree->name);
4107 tree = tree->next;
4108 }
4109 }
4110 }
4111 }
4112 }
4113 dtd = doc->extSubset;
4114 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004115 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004116
4117 for (i = 0;i < table->nb_attributes;i++) {
4118 cur = table->table[i];
4119 switch (cur->atype) {
4120 case XML_ATTRIBUTE_CDATA:
4121 case XML_ATTRIBUTE_ID:
4122 case XML_ATTRIBUTE_IDREF :
4123 case XML_ATTRIBUTE_IDREFS:
4124 case XML_ATTRIBUTE_NMTOKEN:
4125 case XML_ATTRIBUTE_NMTOKENS:
4126 case XML_ATTRIBUTE_ENUMERATION:
4127 break;
4128 case XML_ATTRIBUTE_ENTITY:
4129 case XML_ATTRIBUTE_ENTITIES:
4130 case XML_ATTRIBUTE_NOTATION:
4131 if (cur->defaultValue != NULL) {
4132 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4133 cur->atype, cur->defaultValue);
4134 }
4135 if (cur->tree != NULL) {
4136 xmlEnumerationPtr tree = cur->tree;
4137 while (tree != NULL) {
4138 ret &= xmlValidateAttributeValue2(ctxt, doc,
4139 cur->name, cur->atype, tree->name);
4140 tree = tree->next;
4141 }
4142 }
4143 }
4144 }
4145 }
4146 return(ret);
4147}
4148
4149/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00004150 * xmlValidateDocument:
4151 * @ctxt: the validation context
4152 * @doc: a document instance
4153 *
4154 * Try to validate the document instance
4155 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004156 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00004157 * i.e. validates the internal and external subset (if present)
4158 * and validate the document tree.
4159 *
4160 * returns 1 if valid or 0 otherwise
4161 */
4162
4163int
4164xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004165 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004166 xmlNodePtr root;
4167
4168 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4169 return(0);
4170 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4171 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4172 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4173 doc->intSubset->SystemID);
4174 if (doc->extSubset == NULL) {
4175 if (doc->intSubset->SystemID != NULL) {
4176 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004177 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004178 doc->intSubset->SystemID);
4179 } else {
4180 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004181 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004182 doc->intSubset->ExternalID);
4183 }
4184 return(0);
4185 }
4186 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004187
Daniel Veillardcf461992000-03-14 18:30:20 +00004188 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004189 if (!xmlValidateRoot(ctxt, doc)) return(0);
4190
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004191 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00004192 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004193 ret &= xmlValidateDocumentFinal(ctxt, doc);
4194 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004195}
4196
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004197
4198/************************************************************************
4199 * *
4200 * Routines for dynamic validation editing *
4201 * *
4202 ************************************************************************/
4203
4204/**
4205 * xmlValidGetPotentialChildren:
4206 * @ctree: an element content tree
4207 * @list: an array to store the list of child names
4208 * @len: a pointer to the number of element in the list
4209 * @max: the size of the array
4210 *
4211 * Build/extend a list of potential children allowed by the content tree
4212 *
4213 * returns the number of element in the list, or -1 in case of error.
4214 */
4215
4216int
4217xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4218 int *len, int max) {
4219 int i;
4220
4221 if ((ctree == NULL) || (list == NULL) || (len == NULL))
4222 return(-1);
4223 if (*len >= max) return(*len);
4224
4225 switch (ctree->type) {
4226 case XML_ELEMENT_CONTENT_PCDATA:
4227 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00004228 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
4229 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004230 break;
4231 case XML_ELEMENT_CONTENT_ELEMENT:
4232 for (i = 0; i < *len;i++)
4233 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
4234 list[(*len)++] = ctree->name;
4235 break;
4236 case XML_ELEMENT_CONTENT_SEQ:
4237 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4238 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4239 break;
4240 case XML_ELEMENT_CONTENT_OR:
4241 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4242 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4243 break;
4244 }
4245
4246 return(*len);
4247}
4248
4249/**
4250 * xmlValidGetValidElements:
4251 * @prev: an element to insert after
4252 * @next: an element to insert next
4253 * @list: an array to store the list of child names
4254 * @max: the size of the array
4255 *
4256 * This function returns the list of authorized children to insert
4257 * within an existing tree while respecting the validity constraints
4258 * forced by the Dtd. The insertion point is defined using @prev and
4259 * @next in the following ways:
4260 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4261 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4262 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4263 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4264 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4265 *
4266 * pointers to the element names are inserted at the beginning of the array
4267 * and do not need to be freed.
4268 *
4269 * returns the number of element in the list, or -1 in case of error. If
4270 * the function returns the value @max the caller is invited to grow the
4271 * receiving array and retry.
4272 */
4273
4274int
4275xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4276 int max) {
4277 int nb_valid_elements = 0;
4278 const xmlChar *elements[256];
4279 int nb_elements = 0, i;
4280
4281 xmlNode *ref_node;
4282 xmlNode *parent;
4283 xmlNode *test_node;
4284
4285 xmlNode *prev_next;
4286 xmlNode *next_prev;
4287 xmlNode *parent_childs;
4288 xmlNode *parent_last;
4289
4290 xmlElement *element_desc;
4291
4292 if (prev == NULL && next == NULL)
4293 return(-1);
4294
4295 if (list == NULL) return(-1);
4296 if (max <= 0) return(-1);
4297
4298 nb_valid_elements = 0;
4299 ref_node = prev ? prev : next;
4300 parent = ref_node->parent;
4301
4302 /*
4303 * Retrieves the parent element declaration
4304 */
4305 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4306 parent->name);
4307 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4308 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4309 parent->name);
4310 if (element_desc == NULL) return(-1);
4311
4312 /*
4313 * Do a backup of the current tree structure
4314 */
4315 prev_next = prev ? prev->next : NULL;
4316 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004317 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004318 parent_last = parent->last;
4319
4320 /*
4321 * Creates a dummy node and insert it into the tree
4322 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004323 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004324 test_node->doc = ref_node->doc;
4325 test_node->parent = parent;
4326 test_node->prev = prev;
4327 test_node->next = next;
4328
4329 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00004330 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004331
4332 if (next) next->prev = test_node;
4333 else parent->last = test_node;
4334
4335 /*
4336 * Insert each potential child node and check if the parent is
4337 * still valid
4338 */
4339 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4340 elements, &nb_elements, 256);
4341
4342 for (i = 0;i < nb_elements;i++) {
4343 test_node->name = elements[i];
4344 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4345 int j;
4346
4347 for (j = 0; j < nb_valid_elements;j++)
4348 if (!xmlStrcmp(elements[i], list[j])) break;
4349 list[nb_valid_elements++] = elements[i];
4350 if (nb_valid_elements >= max) break;
4351 }
4352 }
4353
4354 /*
4355 * Restore the tree structure
4356 */
4357 if (prev) prev->next = prev_next;
4358 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004359 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004360 parent->last = parent_last;
4361
4362 return(nb_valid_elements);
4363}