blob: f5b40e2357b63ee7c0fdfdd2099f4529a5d67a55 [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;
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000570 if ((xmlStrEqual(cur->name, name)) &&
571 ((ns == NULL) || (xmlStrEqual(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++) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +0000930 if (xmlStrEqual(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 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001083 if ((xmlStrEqual(cur->name, name)) &&
1084 ((ns == NULL) || (xmlStrEqual(cur->prefix, ns)))) {
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001085 /*
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;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001104 if ((xmlStrEqual(cur->name, name)) &&
1105 (xmlStrEqual(cur->elem, elem)) &&
1106 ((ns == NULL) || (xmlStrEqual(cur->prefix, ns)))) {
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001107 /*
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 Veillard8b5dd832000-10-01 20:28:44 +00001464 if (xmlStrEqual(cur->name, name)) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001465 /*
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];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001733 if (xmlStrEqual(cur->value, value)) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001734 /*
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)) {
Daniel Veillarde8282ed2000-10-10 23:01:31 +00001826 return(0);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001827 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001828 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
1829 (xmlStrEqual(BAD_CAST "name", attr->name)))
Daniel Veillard71b656e2000-01-05 14:46:17 +00001830 return(1);
1831 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001832 } else {
1833 xmlAttributePtr attrDecl;
1834
Daniel Veillard71b656e2000-01-05 14:46:17 +00001835 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001836 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1837 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1838 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1839 attr->name);
1840
Daniel Veillardcf461992000-03-14 18:30:20 +00001841 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001842 return(1);
1843 }
1844 return(0);
1845}
1846
Daniel Veillardb96e6431999-08-29 21:02:19 +00001847/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001848 * xmlRemoveID
1849 * @doc: the document
1850 * @attr: the attribute
1851 *
1852 * Remove the given attribute from the ID table maintained internally.
1853 *
1854 * Returns -1 if the lookup failed and 0 otherwise
1855 */
1856int
1857xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1858 xmlIDPtr cur;
1859 xmlIDTablePtr table;
1860 int i;
1861
1862 if (doc == NULL) return(-1);
1863 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001864 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001865 if (table == NULL)
1866 return(-1);
1867
1868 /*
1869 * Search the ID list.
1870 */
1871 for (i = 0;i < table->nb_ids;i++) {
1872 cur = table->table[i];
1873 if (cur->attr == attr) {
1874 table->nb_ids--;
1875 memmove(&table->table[i], &table->table[i+1],
1876 (table->nb_ids - i) * sizeof(xmlIDPtr));
1877 return(0);
1878 }
1879 }
1880 return(-1);
1881}
1882
1883/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001884 * xmlGetID:
1885 * @doc: pointer to the document
1886 * @ID: the ID value
1887 *
1888 * Search the attribute declaring the given ID
1889 *
1890 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1891 */
1892xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001893xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001894 xmlIDPtr cur;
1895 xmlIDTablePtr table;
1896 int i;
1897
1898 if (doc == NULL) {
1899 fprintf(stderr, "xmlGetID: doc == NULL\n");
1900 return(NULL);
1901 }
1902
1903 if (ID == NULL) {
1904 fprintf(stderr, "xmlGetID: ID == NULL\n");
1905 return(NULL);
1906 }
1907
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001908 table = (xmlIDTablePtr) doc->ids;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001909 if (table == NULL)
1910 return(NULL);
1911
1912 /*
1913 * Search the ID list.
1914 */
1915 for (i = 0;i < table->nb_ids;i++) {
1916 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001917 if (xmlStrEqual(cur->value, ID)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001918 return(cur->attr);
1919 }
1920 }
1921 return(NULL);
1922}
1923
Daniel Veillard991e63d1999-08-15 23:32:28 +00001924/************************************************************************
1925 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001926 * Refs *
1927 * *
1928 ************************************************************************/
1929/**
1930 * xmlCreateRefTable:
1931 *
1932 * create and initialize an empty ref hash table.
1933 *
1934 * Returns the xmlRefTablePtr just created or NULL in case
1935 * of error.
1936 */
1937xmlRefTablePtr
1938xmlCreateRefTable(void) {
1939 xmlRefTablePtr ret;
1940
1941 ret = (xmlRefTablePtr)
1942 xmlMalloc(sizeof(xmlRefTable));
1943 if (ret == NULL) {
1944 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1945 (long)sizeof(xmlRefTable));
1946 return(NULL);
1947 }
1948 ret->max_refs = XML_MIN_NOTATION_TABLE;
1949 ret->nb_refs = 0;
1950 ret->table = (xmlRefPtr *)
1951 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001952 if (ret->table == NULL) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001953 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1954 ret->max_refs * (long)sizeof(xmlRef));
1955 xmlFree(ret);
1956 return(NULL);
1957 }
1958 return(ret);
1959}
1960
1961
1962/**
1963 * xmlAddRef:
1964 * @ctxt: the validation context
1965 * @doc: pointer to the document
1966 * @value: the value name
1967 * @attr: the attribute holding the Ref
1968 *
1969 * Register a new ref declaration
1970 *
1971 * Returns NULL if not, othervise the new xmlRefPtr
1972 */
1973xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001974xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001975 xmlAttrPtr attr) {
1976 xmlRefPtr ret;
1977 xmlRefTablePtr table;
1978
1979 if (doc == NULL) {
1980 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1981 return(NULL);
1982 }
1983 if (value == NULL) {
1984 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1985 return(NULL);
1986 }
1987 if (attr == NULL) {
1988 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1989 return(NULL);
1990 }
1991
1992 /*
1993 * Create the Ref table if needed.
1994 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001995 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001996 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001997 doc->refs = table = xmlCreateRefTable();
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001998 if (table == NULL) {
1999 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
2000 return(NULL);
2001 }
2002
2003 /*
2004 * Grow the table, if needed.
2005 */
2006 if (table->nb_refs >= table->max_refs) {
2007 /*
2008 * need more refs.
2009 */
2010 table->max_refs *= 2;
2011 table->table = (xmlRefPtr *)
2012 xmlRealloc(table->table, table->max_refs *
2013 sizeof(xmlRefPtr));
2014 if (table->table == NULL) {
2015 fprintf(stderr, "xmlAddRef: out of memory\n");
2016 return(NULL);
2017 }
2018 }
2019 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2020 if (ret == NULL) {
2021 fprintf(stderr, "xmlAddRef: out of memory\n");
2022 return(NULL);
2023 }
2024 table->table[table->nb_refs] = ret;
2025
2026 /*
2027 * fill the structure.
2028 */
2029 ret->value = xmlStrdup(value);
2030 ret->attr = attr;
2031 table->nb_refs++;
2032
2033 return(ret);
2034}
2035
2036/**
2037 * xmlFreeRef:
2038 * @not: A ref
2039 *
2040 * Deallocate the memory used by an ref definition
2041 */
2042void
2043xmlFreeRef(xmlRefPtr ref) {
2044 if (ref == NULL) return;
2045 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002046 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002047 memset(ref, -1, sizeof(xmlRef));
2048 xmlFree(ref);
2049}
2050
2051/**
2052 * xmlFreeRefTable:
2053 * @table: An ref table
2054 *
2055 * Deallocate the memory used by an Ref hash table.
2056 */
2057void
2058xmlFreeRefTable(xmlRefTablePtr table) {
2059 int i;
2060
2061 if (table == NULL) return;
2062
2063 for (i = 0;i < table->nb_refs;i++) {
2064 xmlFreeRef(table->table[i]);
2065 }
2066 xmlFree(table->table);
2067 xmlFree(table);
2068}
2069
2070/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002071 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002072 * @doc: the document
2073 * @elem: the element carrying the attribute
2074 * @attr: the attribute
2075 *
2076 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
2077 * then this is simple, otherwise we use an heuristic: name Ref (upper
2078 * or lowercase).
2079 *
2080 * Returns 0 or 1 depending on the lookup result
2081 */
2082int
2083xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2084 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2085 return(0);
2086 /*******************
2087 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
2088 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
2089 (attr->name[2] == 0)) return(1);
2090 *******************/
Daniel Veillardd83eb822000-06-30 18:39:56 +00002091 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2092 /* TODO @@@ */
2093 return(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002094 } else {
2095 xmlAttributePtr attrDecl;
2096
2097 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2098 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2099 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2100 attr->name);
2101
Daniel Veillardcf461992000-03-14 18:30:20 +00002102 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002103 return(1);
2104 }
2105 return(0);
2106}
2107
2108/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002109 * xmlRemoveRef
2110 * @doc: the document
2111 * @attr: the attribute
2112 *
2113 * Remove the given attribute from the Ref table maintained internally.
2114 *
2115 * Returns -1 if the lookup failed and 0 otherwise
2116 */
2117int
2118xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2119 xmlRefPtr cur;
2120 xmlRefTablePtr table;
2121 int i;
2122
2123 if (doc == NULL) return(-1);
2124 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002125 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard71b656e2000-01-05 14:46:17 +00002126 if (table == NULL)
2127 return(-1);
2128
2129 /*
2130 * Search the Ref list.
2131 */
2132 for (i = 0;i < table->nb_refs;i++) {
2133 cur = table->table[i];
2134 if (cur->attr == attr) {
2135 table->nb_refs--;
2136 memmove(&table->table[i], &table->table[i+1],
2137 (table->nb_refs - i) * sizeof(xmlRefPtr));
2138 return(0);
2139 }
2140 }
2141 return(-1);
2142}
2143
2144/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002145 * xmlGetRef:
2146 * @doc: pointer to the document
2147 * @Ref: the Ref value
2148 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00002149 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002150 *
2151 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
2152 */
2153xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002154xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002155 xmlRefPtr cur;
2156 xmlRefTablePtr table;
2157 int i;
2158
2159 if (doc == NULL) {
2160 fprintf(stderr, "xmlGetRef: doc == NULL\n");
2161 return(NULL);
2162 }
2163
2164 if (Ref == NULL) {
2165 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
2166 return(NULL);
2167 }
2168
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002169 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002170 if (table == NULL)
2171 return(NULL);
2172
2173 /*
2174 * Search the Ref list.
2175 */
2176 for (i = 0;i < table->nb_refs;i++) {
2177 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002178 if (xmlStrEqual(cur->value, Ref)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002179 return(cur->attr);
2180 }
2181 }
2182 return(NULL);
2183}
2184
2185/************************************************************************
2186 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002187 * Routines for validity checking *
2188 * *
2189 ************************************************************************/
2190
2191/**
2192 * xmlGetDtdElementDesc:
2193 * @dtd: a pointer to the DtD to search
2194 * @name: the element name
2195 *
2196 * Search the Dtd for the description of this element
2197 *
2198 * returns the xmlElementPtr if found or NULL
2199 */
2200
2201xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002202xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002203 xmlElementTablePtr table;
2204 xmlElementPtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002205 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002206 int i;
2207
2208 if (dtd == NULL) return(NULL);
2209 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002210 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002211
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00002212 if ((table->last >= 0) && (table->last < table->nb_elements)) {
2213 cur = table->table[table->last];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002214 if (xmlStrEqual(cur->name, name))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002215 return(cur);
2216 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00002217 for (i = 0;i < table->nb_elements;i++) {
2218 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002219 if (xmlStrEqual(cur->name, name)) {
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00002220 table->last = i;
2221 return(cur);
2222 }
2223 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002224
2225 /*
2226 * Specific case if name is a QName.
2227 */
2228 uqname = xmlSplitQName2(name, &prefix);
2229 if (uqname == NULL) return(NULL);
2230
2231 for (i = 0;i < table->nb_elements;i++) {
2232 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002233 if ((xmlStrEqual(cur->name, uqname)) &&
Daniel Veillardbe803962000-06-28 23:40:59 +00002234 ((prefix == cur->prefix) ||
2235 ((prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002236 (xmlStrEqual(cur->prefix, prefix))))) {
Daniel Veillardbe803962000-06-28 23:40:59 +00002237 if (prefix != NULL) xmlFree(prefix);
2238 if (uqname != NULL) xmlFree(uqname);
2239 return(cur);
2240 }
2241 }
2242 if (prefix != NULL) xmlFree(prefix);
2243 if (uqname != NULL) xmlFree(uqname);
2244 return(NULL);
2245}
2246
2247/**
2248 * xmlGetDtdQElementDesc:
2249 * @dtd: a pointer to the DtD to search
2250 * @name: the element name
2251 * @prefix: the element namespace prefix
2252 *
2253 * Search the Dtd for the description of this element
2254 *
2255 * returns the xmlElementPtr if found or NULL
2256 */
2257
2258xmlElementPtr
2259xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2260 const xmlChar *prefix) {
2261 xmlElementTablePtr table;
2262 xmlElementPtr cur;
2263 int i;
2264
2265 if (dtd == NULL) return(NULL);
2266 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002267 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardbe803962000-06-28 23:40:59 +00002268
2269 for (i = 0;i < table->nb_elements;i++) {
2270 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002271 if (xmlStrEqual(cur->name, name) &&
Daniel Veillardbe803962000-06-28 23:40:59 +00002272 ((prefix == cur->prefix) ||
2273 ((prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002274 (xmlStrEqual(cur->prefix, prefix)))))
Daniel Veillardbe803962000-06-28 23:40:59 +00002275 return(cur);
2276 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002277 return(NULL);
2278}
2279
2280/**
2281 * xmlGetDtdAttrDesc:
2282 * @dtd: a pointer to the DtD to search
2283 * @elem: the element name
2284 * @name: the attribute name
2285 *
2286 * Search the Dtd for the description of this attribute on
2287 * this element.
2288 *
2289 * returns the xmlAttributePtr if found or NULL
2290 */
2291
2292xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002293xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002294 xmlAttributeTablePtr table;
Daniel Veillardb1059e22000-09-16 14:02:43 +00002295 xmlElementTablePtr etable;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002296 xmlAttributePtr cur;
Daniel Veillardb1059e22000-09-16 14:02:43 +00002297 xmlElementPtr ecur;
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 Veillardb05deb71999-08-10 19:04:08 +00002303
Daniel Veillardb1059e22000-09-16 14:02:43 +00002304 /*
2305 * Faster lookup through the element table
2306 */
2307 etable = (xmlElementTablePtr) dtd->elements;
2308 if (etable != NULL) {
2309 for (i = 0;i < etable->nb_elements;i++) {
2310 ecur = etable->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002311 if (xmlStrEqual(ecur->name, elem)) {
Daniel Veillardb1059e22000-09-16 14:02:43 +00002312 cur = ecur->attributes;
2313 while (cur != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002314 if (xmlStrEqual(cur->name, name))
Daniel Veillardb1059e22000-09-16 14:02:43 +00002315 return(cur);
2316 cur = cur->nexth;
2317 }
2318 /* TODO: same accelerator for QNames !!! */
2319 break;
2320 }
2321 }
2322 }
2323 /*
2324 * Miss on the element table, retry on the attribute one
2325 */
2326
2327 table = (xmlAttributeTablePtr) dtd->attributes;
2328 if (table == NULL)
2329 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002330 for (i = 0;i < table->nb_attributes;i++) {
2331 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002332 if ((xmlStrEqual(cur->name, name)) &&
2333 (xmlStrEqual(cur->elem, elem)))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002334 return(cur);
2335 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002336
2337 /*
2338 * Specific case if name is a QName.
2339 */
2340 uqname = xmlSplitQName2(name, &prefix);
2341 if (uqname == NULL) return(NULL);
2342
2343 for (i = 0;i < table->nb_attributes;i++) {
2344 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002345 if ((xmlStrEqual(cur->name, uqname)) &&
2346 (xmlStrEqual(cur->elem, elem)) &&
Daniel Veillardbe803962000-06-28 23:40:59 +00002347 ((prefix == cur->prefix) ||
2348 ((prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002349 (xmlStrEqual(cur->prefix, prefix))))) {
Daniel Veillardbe803962000-06-28 23:40:59 +00002350 if (prefix != NULL) xmlFree(prefix);
2351 if (uqname != NULL) xmlFree(uqname);
2352 return(cur);
2353 }
2354 }
2355 if (prefix != NULL) xmlFree(prefix);
2356 if (uqname != NULL) xmlFree(uqname);
2357 return(NULL);
2358}
2359
2360/**
2361 * xmlGetDtdQAttrDesc:
2362 * @dtd: a pointer to the DtD to search
2363 * @elem: the element name
2364 * @name: the attribute name
2365 * @prefix: the attribute namespace prefix
2366 *
2367 * Search the Dtd for the description of this qualified attribute on
2368 * this element.
2369 *
2370 * returns the xmlAttributePtr if found or NULL
2371 */
2372
2373xmlAttributePtr
2374xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2375 const xmlChar *prefix) {
2376 xmlAttributeTablePtr table;
2377 xmlAttributePtr cur;
2378 int i;
2379
2380 if (dtd == NULL) return(NULL);
2381 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002382 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardbe803962000-06-28 23:40:59 +00002383
2384 for (i = 0;i < table->nb_attributes;i++) {
2385 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002386 if ((xmlStrEqual(cur->name, name)) &&
2387 (xmlStrEqual(cur->elem, elem)) &&
Daniel Veillardbe803962000-06-28 23:40:59 +00002388 ((prefix == cur->prefix) ||
2389 ((prefix != NULL) && (cur->prefix != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002390 (xmlStrEqual(cur->prefix, prefix)))))
Daniel Veillardbe803962000-06-28 23:40:59 +00002391 return(cur);
2392 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002393 return(NULL);
2394}
2395
2396/**
2397 * xmlGetDtdNotationDesc:
2398 * @dtd: a pointer to the DtD to search
2399 * @name: the notation name
2400 *
2401 * Search the Dtd for the description of this notation
2402 *
2403 * returns the xmlNotationPtr if found or NULL
2404 */
2405
2406xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002407xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002408 xmlNotationTablePtr table;
2409 xmlNotationPtr cur;
2410 int i;
2411
2412 if (dtd == NULL) return(NULL);
2413 if (dtd->notations == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002414 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002415
2416 for (i = 0;i < table->nb_notations;i++) {
2417 cur = table->table[i];
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002418 if (xmlStrEqual(cur->name, name))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002419 return(cur);
2420 }
2421 return(NULL);
2422}
2423
2424/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002425 * xmlValidateNotationUse:
2426 * @ctxt: the validation context
2427 * @doc: the document
2428 * @notationName: the notation name to check
2429 *
2430 * Validate that the given mame match a notation declaration.
2431 * - [ VC: Notation Declared ]
2432 *
2433 * returns 1 if valid or 0 otherwise
2434 */
2435
2436int
2437xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002438 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002439 xmlNotationPtr notaDecl;
2440 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2441
2442 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2443 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2444 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2445
2446 if (notaDecl == NULL) {
2447 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2448 notationName);
2449 return(0);
2450 }
2451 return(1);
2452}
2453
2454/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002455 * xmlIsMixedElement
2456 * @doc: the document
2457 * @name: the element name
2458 *
2459 * Search in the DtDs whether an element accept Mixed content (or ANY)
2460 * basically if it is supposed to accept text childs
2461 *
2462 * returns 0 if no, 1 if yes, and -1 if no element description is available
2463 */
2464
2465int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002466xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002467 xmlElementPtr elemDecl;
2468
2469 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2470
2471 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2472 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2473 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2474 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002475 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002476 case XML_ELEMENT_TYPE_ELEMENT:
2477 return(0);
2478 case XML_ELEMENT_TYPE_EMPTY:
2479 /*
2480 * return 1 for EMPTY since we want VC error to pop up
2481 * on <empty> </empty> for example
2482 */
2483 case XML_ELEMENT_TYPE_ANY:
2484 case XML_ELEMENT_TYPE_MIXED:
2485 return(1);
2486 }
2487 return(1);
2488}
2489
2490/**
2491 * xmlValidateNameValue:
2492 * @value: an Name value
2493 *
2494 * Validate that the given value match Name production
2495 *
2496 * returns 1 if valid or 0 otherwise
2497 */
2498
2499int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002500xmlValidateNameValue(const xmlChar *value) {
2501 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002502
2503 if (value == NULL) return(0);
2504 cur = value;
2505
2506 if (!IS_LETTER(*cur) && (*cur != '_') &&
2507 (*cur != ':')) {
2508 return(0);
2509 }
2510
2511 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2512 (*cur == '.') || (*cur == '-') ||
2513 (*cur == '_') || (*cur == ':') ||
2514 (IS_COMBINING(*cur)) ||
2515 (IS_EXTENDER(*cur)))
2516 cur++;
2517
2518 if (*cur != 0) return(0);
2519
2520 return(1);
2521}
2522
2523/**
2524 * xmlValidateNamesValue:
2525 * @value: an Names value
2526 *
2527 * Validate that the given value match Names production
2528 *
2529 * returns 1 if valid or 0 otherwise
2530 */
2531
2532int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002533xmlValidateNamesValue(const xmlChar *value) {
2534 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002535
2536 if (value == NULL) return(0);
2537 cur = value;
2538
2539 if (!IS_LETTER(*cur) && (*cur != '_') &&
2540 (*cur != ':')) {
2541 return(0);
2542 }
2543
2544 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2545 (*cur == '.') || (*cur == '-') ||
2546 (*cur == '_') || (*cur == ':') ||
2547 (IS_COMBINING(*cur)) ||
2548 (IS_EXTENDER(*cur)))
2549 cur++;
2550
2551 while (IS_BLANK(*cur)) {
2552 while (IS_BLANK(*cur)) cur++;
2553
2554 if (!IS_LETTER(*cur) && (*cur != '_') &&
2555 (*cur != ':')) {
2556 return(0);
2557 }
2558
2559 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2560 (*cur == '.') || (*cur == '-') ||
2561 (*cur == '_') || (*cur == ':') ||
2562 (IS_COMBINING(*cur)) ||
2563 (IS_EXTENDER(*cur)))
2564 cur++;
2565 }
2566
2567 if (*cur != 0) return(0);
2568
2569 return(1);
2570}
2571
2572/**
2573 * xmlValidateNmtokenValue:
2574 * @value: an Mntoken value
2575 *
2576 * Validate that the given value match Nmtoken production
2577 *
2578 * [ VC: Name Token ]
2579 *
2580 * returns 1 if valid or 0 otherwise
2581 */
2582
2583int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002584xmlValidateNmtokenValue(const xmlChar *value) {
2585 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002586
2587 if (value == NULL) return(0);
2588 cur = value;
2589
2590 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2591 (*cur != '.') && (*cur != '-') &&
2592 (*cur != '_') && (*cur != ':') &&
2593 (!IS_COMBINING(*cur)) &&
2594 (!IS_EXTENDER(*cur)))
2595 return(0);
2596
2597 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2598 (*cur == '.') || (*cur == '-') ||
2599 (*cur == '_') || (*cur == ':') ||
2600 (IS_COMBINING(*cur)) ||
2601 (IS_EXTENDER(*cur)))
2602 cur++;
2603
2604 if (*cur != 0) return(0);
2605
2606 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002607}
2608
2609/**
2610 * xmlValidateNmtokensValue:
2611 * @value: an Mntokens value
2612 *
2613 * Validate that the given value match Nmtokens production
2614 *
2615 * [ VC: Name Token ]
2616 *
2617 * returns 1 if valid or 0 otherwise
2618 */
2619
2620int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002621xmlValidateNmtokensValue(const xmlChar *value) {
2622 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002623
2624 if (value == NULL) return(0);
2625 cur = value;
2626
Daniel Veillardcf461992000-03-14 18:30:20 +00002627 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002628 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2629 (*cur != '.') && (*cur != '-') &&
2630 (*cur != '_') && (*cur != ':') &&
2631 (!IS_COMBINING(*cur)) &&
2632 (!IS_EXTENDER(*cur)))
2633 return(0);
2634
2635 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2636 (*cur == '.') || (*cur == '-') ||
2637 (*cur == '_') || (*cur == ':') ||
2638 (IS_COMBINING(*cur)) ||
2639 (IS_EXTENDER(*cur)))
2640 cur++;
2641
2642 while (IS_BLANK(*cur)) {
2643 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002644 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002645
2646 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2647 (*cur != '.') && (*cur != '-') &&
2648 (*cur != '_') && (*cur != ':') &&
2649 (!IS_COMBINING(*cur)) &&
2650 (!IS_EXTENDER(*cur)))
2651 return(0);
2652
2653 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2654 (*cur == '.') || (*cur == '-') ||
2655 (*cur == '_') || (*cur == ':') ||
2656 (IS_COMBINING(*cur)) ||
2657 (IS_EXTENDER(*cur)))
2658 cur++;
2659 }
2660
2661 if (*cur != 0) return(0);
2662
2663 return(1);
2664}
2665
2666/**
2667 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002668 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002669 * @doc: a document instance
2670 * @nota: a notation definition
2671 *
2672 * Try to validate a single notation definition
2673 * basically it does the following checks as described by the
2674 * XML-1.0 recommendation:
2675 * - it seems that no validity constraing exist on notation declarations
2676 * But this function get called anyway ...
2677 *
2678 * returns 1 if valid or 0 otherwise
2679 */
2680
2681int
2682xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2683 xmlNotationPtr nota) {
2684 int ret = 1;
2685
2686 return(ret);
2687}
2688
2689/**
2690 * xmlValidateAttributeValue:
2691 * @type: an attribute type
2692 * @value: an attribute value
2693 *
2694 * Validate that the given attribute value match the proper production
2695 *
2696 * [ VC: ID ]
2697 * Values of type ID must match the Name production....
2698 *
2699 * [ VC: IDREF ]
2700 * Values of type IDREF must match the Name production, and values
2701 * of type IDREFS must match Names ...
2702 *
2703 * [ VC: Entity Name ]
2704 * Values of type ENTITY must match the Name production, values
2705 * of type ENTITIES must match Names ...
2706 *
2707 * [ VC: Name Token ]
2708 * Values of type NMTOKEN must match the Nmtoken production; values
2709 * of type NMTOKENS must match Nmtokens.
2710 *
2711 * returns 1 if valid or 0 otherwise
2712 */
2713
2714int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002715xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002716 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002717 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002718 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002719 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002720 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002721 case XML_ATTRIBUTE_IDREF:
2722 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002723 case XML_ATTRIBUTE_NOTATION:
2724 return(xmlValidateNameValue(value));
2725 case XML_ATTRIBUTE_NMTOKENS:
2726 case XML_ATTRIBUTE_ENUMERATION:
2727 return(xmlValidateNmtokensValue(value));
2728 case XML_ATTRIBUTE_NMTOKEN:
2729 return(xmlValidateNmtokenValue(value));
2730 case XML_ATTRIBUTE_CDATA:
2731 break;
2732 }
2733 return(1);
2734}
2735
2736/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002737 * xmlValidateAttributeValue2:
2738 * @ctxt: the validation context
2739 * @doc: the document
2740 * @name: the attribute name (used for error reporting only)
2741 * @type: the attribute type
2742 * @value: the attribute value
2743 *
2744 * Validate that the given attribute value match a given type.
2745 * This typically cannot be done before having finished parsing
2746 * the subsets.
2747 *
2748 * [ VC: IDREF ]
2749 * Values of type IDREF must match one of the declared IDs
2750 * Values of type IDREFS must match a sequence of the declared IDs
2751 * each Name must match the value of an ID attribute on some element
2752 * in the XML document; i.e. IDREF values must match the value of
2753 * some ID attribute
2754 *
2755 * [ VC: Entity Name ]
2756 * Values of type ENTITY must match one declared entity
2757 * Values of type ENTITIES must match a sequence of declared entities
2758 *
2759 * [ VC: Notation Attributes ]
2760 * all notation names in the declaration must be declared.
2761 *
2762 * returns 1 if valid or 0 otherwise
2763 */
2764
2765int
2766xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2767 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2768 int ret = 1;
2769 switch (type) {
2770 case XML_ATTRIBUTE_IDREFS:
2771 case XML_ATTRIBUTE_IDREF:
2772 case XML_ATTRIBUTE_ID:
2773 case XML_ATTRIBUTE_NMTOKENS:
2774 case XML_ATTRIBUTE_ENUMERATION:
2775 case XML_ATTRIBUTE_NMTOKEN:
2776 case XML_ATTRIBUTE_CDATA:
2777 break;
2778 case XML_ATTRIBUTE_ENTITY: {
2779 xmlEntityPtr ent;
2780
2781 ent = xmlGetDocEntity(doc, value);
2782 if (ent == NULL) {
2783 VERROR(ctxt->userData,
2784 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2785 name, value);
2786 ret = 0;
2787 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2788 VERROR(ctxt->userData,
2789 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2790 name, value);
2791 ret = 0;
2792 }
2793 break;
2794 }
2795 case XML_ATTRIBUTE_ENTITIES: {
2796 xmlChar *dup, *nam = NULL, *cur, save;
2797 xmlEntityPtr ent;
2798
2799 dup = xmlStrdup(value);
2800 if (dup == NULL)
2801 return(0);
2802 cur = dup;
2803 while (*cur != 0) {
2804 nam = cur;
2805 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2806 save = *cur;
2807 *cur = 0;
2808 ent = xmlGetDocEntity(doc, nam);
2809 if (ent == NULL) {
2810 VERROR(ctxt->userData,
2811 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2812 name, nam);
2813 ret = 0;
2814 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2815 VERROR(ctxt->userData,
2816 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2817 name, nam);
2818 ret = 0;
2819 }
2820 if (save == 0)
2821 break;
2822 *cur = save;
2823 while (IS_BLANK(*cur)) cur++;
2824 }
2825 xmlFree(dup);
2826 break;
2827 }
2828 case XML_ATTRIBUTE_NOTATION: {
2829 xmlNotationPtr nota;
2830
2831 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2832 if ((nota == NULL) && (doc->extSubset != NULL))
2833 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2834
2835 if (nota == NULL) {
2836 VERROR(ctxt->userData,
2837 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2838 name, value);
2839 ret = 0;
2840 }
2841 break;
2842 }
2843 }
2844 return(ret);
2845}
2846
2847/**
2848 * xmlValidNormalizeAttributeValue:
2849 * @doc: the document
2850 * @elem: the parent
2851 * @name: the attribute name
2852 * @value: the attribute value
2853 *
2854 * Does the validation related extra step of the normalization of attribute
2855 * values:
2856 *
2857 * If the declared value is not CDATA, then the XML processor must further
2858 * process the normalized attribute value by discarding any leading and
2859 * trailing space (#x20) characters, and by replacing sequences of space
2860 * (#x20) characters by single space (#x20) character.
2861 *
2862 * returns a new normalized string if normalization is needed, NULL otherwise
2863 * the caller must free the returned value.
2864 */
2865
2866xmlChar *
2867xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2868 const xmlChar *name, const xmlChar *value) {
2869 xmlChar *ret, *dst;
2870 const xmlChar *src;
Daniel Veillardbe803962000-06-28 23:40:59 +00002871 xmlAttributePtr attrDecl = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002872
2873 if (doc == NULL) return(NULL);
2874 if (elem == NULL) return(NULL);
2875 if (name == NULL) return(NULL);
2876 if (value == NULL) return(NULL);
2877
Daniel Veillardbe803962000-06-28 23:40:59 +00002878 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2879 xmlChar qname[500];
2880#ifdef HAVE_SNPRINTF
2881 snprintf((char *) qname, sizeof(qname), "%s:%s",
2882 elem->ns->prefix, elem->name);
2883#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00002884 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00002885#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00002886 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00002887 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2888 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2889 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2890 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002891 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2892 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2893 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2894
2895 if (attrDecl == NULL)
2896 return(NULL);
2897 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2898 return(NULL);
2899
2900 ret = xmlStrdup(value);
2901 if (ret == NULL)
2902 return(NULL);
2903 src = value;
2904 dst = ret;
2905 while (*src == 0x20) src++;
2906 while (*src != 0) {
2907 if (*src == 0x20) {
2908 while (*src == 0x20) src++;
2909 if (*src != 0)
2910 *dst++ = 0x20;
2911 } else {
2912 *dst++ = *src++;
2913 }
2914 }
2915 *dst = 0;
2916 return(ret);
2917}
2918
2919/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002920 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002921 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002922 * @doc: a document instance
2923 * @attr: an attribute definition
2924 *
2925 * Try to validate a single attribute definition
2926 * basically it does the following checks as described by the
2927 * XML-1.0 recommendation:
2928 * - [ VC: Attribute Default Legal ]
2929 * - [ VC: Enumeration ]
2930 * - [ VC: ID Attribute Default ]
2931 *
2932 * The ID/IDREF uniqueness and matching are done separately
2933 *
2934 * returns 1 if valid or 0 otherwise
2935 */
2936
2937int
2938xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2939 xmlAttributePtr attr) {
2940 int ret = 1;
2941 int val;
2942 CHECK_DTD;
2943 if(attr == NULL) return(1);
2944
2945 /* Attribute Default Legal */
2946 /* Enumeration */
2947 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002948 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002949 if (val == 0) {
2950 VERROR(ctxt->userData,
2951 "Syntax of default value for attribute %s on %s is not valid\n",
2952 attr->name, attr->elem);
2953 }
2954 ret &= val;
2955 }
2956
2957 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002958 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002959 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2960 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2961 VERROR(ctxt->userData,
2962 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2963 attr->name, attr->elem);
2964 ret = 0;
2965 }
2966
Daniel Veillardb96e6431999-08-29 21:02:19 +00002967 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002968 if (attr->atype == XML_ATTRIBUTE_ID) {
2969 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002970
2971 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002972 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002973 attr->elem);
2974 if (elem != NULL) {
2975 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002976 } else {
2977 xmlAttributeTablePtr table;
2978 int i;
2979
2980 /*
2981 * The attribute may be declared in the internal subset and the
2982 * element in the external subset.
2983 */
2984 nbId = 0;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002985 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00002986 if (table != NULL) {
2987 for (i = 0;i < table->nb_attributes;i++) {
2988 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002989 (xmlStrEqual(table->table[i]->elem, attr->elem))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002990 nbId++;
2991 }
2992 }
2993 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002994 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002995 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002996 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002997 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2998 attr->elem, nbId, attr->name);
2999 } else if (doc->extSubset != NULL) {
3000 int extId = 0;
3001 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3002 if (elem != NULL) {
3003 extId = xmlScanIDAttributeDecl(NULL, elem);
3004 }
3005 if (extId > 1) {
3006 VERROR(ctxt->userData,
3007 "Element %s has %d ID attribute defined in the external subset : %s\n",
3008 attr->elem, extId, attr->name);
3009 } else if (extId + nbId > 1) {
3010 VERROR(ctxt->userData,
3011"Element %s has ID attributes defined in the internal and external subset : %s\n",
3012 attr->elem, attr->name);
3013 }
3014 }
3015 }
3016
3017 /* Validity Constraint: Enumeration */
3018 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3019 xmlEnumerationPtr tree = attr->tree;
3020 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003021 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
Daniel Veillardcf461992000-03-14 18:30:20 +00003022 tree = tree->next;
3023 }
3024 if (tree == NULL) {
3025 VERROR(ctxt->userData,
3026"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
3027 attr->defaultValue, attr->name, attr->elem);
3028 ret = 0;
3029 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003030 }
3031
3032 return(ret);
3033}
3034
3035/**
3036 * xmlValidateElementDecl:
3037 * @ctxt: the validation context
3038 * @doc: a document instance
3039 * @elem: an element definition
3040 *
3041 * Try to validate a single element definition
3042 * basically it does the following checks as described by the
3043 * XML-1.0 recommendation:
3044 * - [ VC: One ID per Element Type ]
3045 * - [ VC: No Duplicate Types ]
3046 * - [ VC: Unique Element Type Declaration ]
3047 *
3048 * returns 1 if valid or 0 otherwise
3049 */
3050
3051int
3052xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3053 xmlElementPtr elem) {
3054 int ret = 1;
3055 xmlElementPtr tst;
3056
3057 CHECK_DTD;
3058
3059 if (elem == NULL) return(1);
3060
3061 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00003062 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003063 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003064 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003065
3066 cur = elem->content;
3067 while (cur != NULL) {
3068 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3069 if (cur->c1 == NULL) break;
3070 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3071 name = cur->c1->name;
3072 next = cur->c2;
3073 while (next != NULL) {
3074 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003075 if (xmlStrEqual(next->name, name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003076 VERROR(ctxt->userData,
3077 "Definition of %s has duplicate references of %s\n",
3078 elem->name, name);
3079 ret = 0;
3080 }
3081 break;
3082 }
3083 if (next->c1 == NULL) break;
3084 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003085 if (xmlStrEqual(next->c1->name, name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003086 VERROR(ctxt->userData,
3087 "Definition of %s has duplicate references of %s\n",
3088 elem->name, name);
3089 ret = 0;
3090 }
3091 next = next->c2;
3092 }
3093 }
3094 cur = cur->c2;
3095 }
3096 }
3097
3098 /* VC: Unique Element Type Declaration */
3099 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3100 if ((tst != NULL ) && (tst != elem)) {
3101 VERROR(ctxt->userData, "Redefinition of element %s\n",
3102 elem->name);
3103 ret = 0;
3104 }
3105 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3106 if ((tst != NULL ) && (tst != elem)) {
3107 VERROR(ctxt->userData, "Redefinition of element %s\n",
3108 elem->name);
3109 ret = 0;
3110 }
3111
3112 /* One ID per Element Type */
3113 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3114 ret = 0;
3115 }
3116 return(ret);
3117}
3118
3119/**
3120 * xmlValidateOneAttribute:
3121 * @ctxt: the validation context
3122 * @doc: a document instance
3123 * @elem: an element instance
3124 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00003125 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003126 *
3127 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00003128 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00003129 * XML-1.0 recommendation:
3130 * - [ VC: Attribute Value Type ]
3131 * - [ VC: Fixed Attribute Default ]
3132 * - [ VC: Entity Name ]
3133 * - [ VC: Name Token ]
3134 * - [ VC: ID ]
3135 * - [ VC: IDREF ]
3136 * - [ VC: Entity Name ]
3137 * - [ VC: Notation Attributes ]
3138 *
3139 * The ID/IDREF uniqueness and matching are done separately
3140 *
3141 * returns 1 if valid or 0 otherwise
3142 */
3143
3144int
3145xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003146 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003147 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00003148 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003149 int val;
3150 int ret = 1;
3151
3152 CHECK_DTD;
3153 if ((elem == NULL) || (elem->name == NULL)) return(0);
3154 if ((attr == NULL) || (attr->name == NULL)) return(0);
3155
Daniel Veillardbe803962000-06-28 23:40:59 +00003156 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3157 xmlChar qname[500];
3158#ifdef HAVE_SNPRINTF
3159 snprintf((char *) qname, sizeof(qname), "%s:%s",
3160 elem->ns->prefix, elem->name);
3161#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003162 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003163#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003164 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00003165 if (attr->ns != NULL) {
3166 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3167 attr->name, attr->ns->prefix);
3168 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3169 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3170 attr->name, attr->ns->prefix);
3171 } else {
3172 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3173 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3174 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3175 qname, attr->name);
3176 }
3177 }
3178 if (attrDecl == NULL) {
3179 if (attr->ns != NULL) {
3180 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3181 attr->name, attr->ns->prefix);
3182 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3183 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3184 attr->name, attr->ns->prefix);
3185 } else {
3186 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3187 elem->name, attr->name);
3188 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3189 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3190 elem->name, attr->name);
3191 }
3192 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003193
3194
3195 /* Validity Constraint: Attribute Value Type */
3196 if (attrDecl == NULL) {
3197 VERROR(ctxt->userData,
3198 "No declaration for attribute %s on element %s\n",
3199 attr->name, elem->name);
3200 return(0);
3201 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003202 attr->atype = attrDecl->atype;
3203
3204 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003205 if (val == 0) {
3206 VERROR(ctxt->userData,
3207 "Syntax of value for attribute %s on %s is not valid\n",
3208 attr->name, elem->name);
3209 ret = 0;
3210 }
3211
Daniel Veillardcf461992000-03-14 18:30:20 +00003212 /* Validity constraint: Fixed Attribute Default */
3213 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003214 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003215 VERROR(ctxt->userData,
3216 "Value for attribute %s on %s is differnt from default \"%s\"\n",
3217 attr->name, elem->name, attrDecl->defaultValue);
3218 ret = 0;
3219 }
3220 }
3221
Daniel Veillardb96e6431999-08-29 21:02:19 +00003222 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00003223 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003224 xmlAddID(ctxt, doc, value, attr);
3225 }
3226
Daniel Veillardcf461992000-03-14 18:30:20 +00003227 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3228 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003229 xmlAddRef(ctxt, doc, value, attr);
3230 }
3231
Daniel Veillardb05deb71999-08-10 19:04:08 +00003232 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00003233 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003234 xmlEnumerationPtr tree = attrDecl->tree;
3235 xmlNotationPtr nota;
3236
3237 /* First check that the given NOTATION was declared */
3238 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3239 if (nota == NULL)
3240 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3241
3242 if (nota == NULL) {
3243 VERROR(ctxt->userData,
3244 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3245 value, attr->name, elem->name);
3246 ret = 0;
3247 }
3248
3249 /* Second, verify that it's among the list */
3250 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003251 if (xmlStrEqual(tree->name, value)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003252 tree = tree->next;
3253 }
3254 if (tree == NULL) {
3255 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003256"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003257 value, attr->name, elem->name);
3258 ret = 0;
3259 }
3260 }
3261
3262 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00003263 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003264 xmlEnumerationPtr tree = attrDecl->tree;
3265 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003266 if (xmlStrEqual(tree->name, value)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003267 tree = tree->next;
3268 }
3269 if (tree == NULL) {
3270 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003271 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003272 value, attr->name, elem->name);
3273 ret = 0;
3274 }
3275 }
3276
3277 /* Fixed Attribute Default */
3278 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003279 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003280 VERROR(ctxt->userData,
3281 "Value for attribute %s on %s must be \"%s\"\n",
3282 attr->name, elem->name, attrDecl->defaultValue);
3283 ret = 0;
3284 }
3285
Daniel Veillardcf461992000-03-14 18:30:20 +00003286 /* Extra check for the attribute value */
3287 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3288 attrDecl->atype, value);
3289
Daniel Veillardb05deb71999-08-10 19:04:08 +00003290 return(ret);
3291}
3292
3293int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3294 xmlElementContentPtr cont);
3295
3296/**
3297 * xmlValidateElementTypeExpr:
3298 * @ctxt: the validation context
3299 * @child: pointer to the child list
3300 * @cont: pointer to the content declaration
3301 *
3302 * Try to validate the content of an element of type element
3303 * but don't handle the occurence factor
3304 *
3305 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3306 * also update child value in-situ.
3307 */
3308
3309int
3310xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3311 xmlElementContentPtr cont) {
3312 xmlNodePtr cur;
3313 int ret = 1;
3314
3315 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003316 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003317 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003318 if ((*child)->type == XML_ENTITY_REF_NODE) {
3319 /*
3320 * If there is an entity declared an it's not empty
3321 * Push the current node on the stack and process with the
3322 * entity content.
3323 */
3324 if (((*child)->children != NULL) &&
3325 ((*child)->children->children != NULL)) {
3326 nodeVPush(ctxt, *child);
3327 *child = (*child)->children->children;
3328 } else
3329 *child = (*child)->next;
3330 continue;
3331 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003332 if ((*child)->type == XML_PI_NODE) {
3333 *child = (*child)->next;
3334 continue;
3335 }
3336 if ((*child)->type == XML_COMMENT_NODE) {
3337 *child = (*child)->next;
3338 continue;
3339 }
3340 else if ((*child)->type != XML_ELEMENT_NODE) {
3341 return(-1);
3342 }
3343 break;
3344 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003345 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003346 switch (cont->type) {
3347 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003348 if (*child == NULL) return(0);
3349 if ((*child)->type == XML_TEXT_NODE) return(1);
3350 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003351 case XML_ELEMENT_CONTENT_ELEMENT:
3352 if (*child == NULL) return(0);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003353 ret = (xmlStrEqual((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003354 if (ret == 1) {
3355 while ((*child)->next == NULL) {
3356 if (((*child)->parent != NULL) &&
3357 ((*child)->parent->type == XML_ENTITY_DECL)) {
3358 *child = nodeVPop(ctxt);
3359 } else
3360 break;
3361 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003362 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003363 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003364 return(ret);
3365 case XML_ELEMENT_CONTENT_OR:
3366 cur = *child;
3367 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3368 if (ret == -1) return(-1);
3369 if (ret == 1) {
3370 return(1);
3371 }
3372 /* rollback and retry the other path */
3373 *child = cur;
3374 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3375 if (ret == -1) return(-1);
3376 if (ret == 0) {
3377 *child = cur;
3378 return(0);
3379 }
3380 return(1);
3381 case XML_ELEMENT_CONTENT_SEQ:
3382 cur = *child;
3383 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3384 if (ret == -1) return(-1);
3385 if (ret == 0) {
3386 *child = cur;
3387 return(0);
3388 }
3389 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3390 if (ret == -1) return(-1);
3391 if (ret == 0) {
3392 *child = cur;
3393 return(0);
3394 }
3395 return(1);
3396 }
3397 return(ret);
3398}
3399
3400/**
3401 * xmlValidateElementTypeElement:
3402 * @ctxt: the validation context
3403 * @child: pointer to the child list
3404 * @cont: pointer to the content declaration
3405 *
3406 * Try to validate the content of an element of type element
3407 * yeah, Yet Another Regexp Implementation, and recursive
3408 *
3409 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3410 * also update child and content values in-situ.
3411 */
3412
3413int
3414xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3415 xmlElementContentPtr cont) {
3416 xmlNodePtr cur;
3417 int ret = 1;
3418
3419 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003420
3421 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003422 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003423 if ((*child)->type == XML_ENTITY_REF_NODE) {
3424 /*
3425 * If there is an entity declared an it's not empty
3426 * Push the current node on the stack and process with the
3427 * entity content.
3428 */
3429 if (((*child)->children != NULL) &&
3430 ((*child)->children->children != NULL)) {
3431 nodeVPush(ctxt, *child);
3432 *child = (*child)->children->children;
3433 } else
3434 *child = (*child)->next;
3435 continue;
3436 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003437 if ((*child)->type == XML_PI_NODE) {
3438 *child = (*child)->next;
3439 continue;
3440 }
3441 if ((*child)->type == XML_COMMENT_NODE) {
3442 *child = (*child)->next;
3443 continue;
3444 }
3445 else if ((*child)->type != XML_ELEMENT_NODE) {
3446 return(-1);
3447 }
3448 break;
3449 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003450 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003451 cur = *child;
3452 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3453 if (ret == -1) return(-1);
3454 switch (cont->ocur) {
3455 case XML_ELEMENT_CONTENT_ONCE:
3456 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003457 /* skip ignorable elems */
3458 while ((*child != NULL) &&
3459 (((*child)->type == XML_PI_NODE) ||
3460 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003461 while ((*child)->next == NULL) {
3462 if (((*child)->parent != NULL) &&
3463 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3464 *child = (*child)->parent;
3465 } else
3466 break;
3467 }
3468 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003469 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003470 return(1);
3471 }
3472 *child = cur;
3473 return(0);
3474 case XML_ELEMENT_CONTENT_OPT:
3475 if (ret == 0) {
3476 *child = cur;
3477 return(1);
3478 }
3479 break;
3480 case XML_ELEMENT_CONTENT_MULT:
3481 if (ret == 0) {
3482 *child = cur;
3483 break;
3484 }
3485 /* no break on purpose */
3486 case XML_ELEMENT_CONTENT_PLUS:
3487 if (ret == 0) {
3488 *child = cur;
3489 return(0);
3490 }
3491 do {
3492 cur = *child;
3493 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3494 } while (ret == 1);
3495 if (ret == -1) return(-1);
3496 *child = cur;
3497 break;
3498 }
3499 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003500 if ((*child)->type == XML_ENTITY_REF_NODE) {
3501 /*
3502 * If there is an entity declared an it's not empty
3503 * Push the current node on the stack and process with the
3504 * entity content.
3505 */
3506 if (((*child)->children != NULL) &&
3507 ((*child)->children->children != NULL)) {
3508 nodeVPush(ctxt, *child);
3509 *child = (*child)->children->children;
3510 } else
3511 *child = (*child)->next;
3512 continue;
3513 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003514 if ((*child)->type == XML_PI_NODE) {
3515 *child = (*child)->next;
3516 continue;
3517 }
3518 if ((*child)->type == XML_COMMENT_NODE) {
3519 *child = (*child)->next;
3520 continue;
3521 }
3522 else if ((*child)->type != XML_ELEMENT_NODE) {
3523 return(-1);
3524 }
3525 break;
3526 }
3527 return(1);
3528}
3529
3530/**
3531 * xmlSprintfElementChilds:
3532 * @buf: an output buffer
3533 * @content: An element
3534 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3535 *
3536 * This will dump the list of childs to the buffer
3537 * Intended just for the debug routine
3538 */
3539void
3540xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3541 xmlNodePtr cur;
3542
3543 if (node == NULL) return;
3544 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003545 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003546 while (cur != NULL) {
3547 switch (cur->type) {
3548 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003549 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003550 if (cur->next != NULL)
3551 strcat(buf, " ");
3552 break;
3553 case XML_TEXT_NODE:
3554 case XML_CDATA_SECTION_NODE:
3555 case XML_ENTITY_REF_NODE:
3556 strcat(buf, "CDATA");
3557 if (cur->next != NULL)
3558 strcat(buf, " ");
3559 break;
3560 case XML_ATTRIBUTE_NODE:
3561 case XML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00003562#ifdef LIBXML_SGML_ENABLED
3563 case XML_SGML_DOCUMENT_NODE:
3564#endif
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003565 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003566 case XML_DOCUMENT_TYPE_NODE:
3567 case XML_DOCUMENT_FRAG_NODE:
3568 case XML_NOTATION_NODE:
3569 strcat(buf, "???");
3570 if (cur->next != NULL)
3571 strcat(buf, " ");
3572 break;
3573 case XML_ENTITY_NODE:
3574 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003575 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003576 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003577 case XML_ELEMENT_DECL:
3578 case XML_ATTRIBUTE_DECL:
3579 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003580 break;
3581 }
3582 cur = cur->next;
3583 }
3584 if (glob) strcat(buf, ")");
3585}
3586
3587
3588/**
3589 * xmlValidateOneElement:
3590 * @ctxt: the validation context
3591 * @doc: a document instance
3592 * @elem: an element instance
3593 *
3594 * Try to validate a single element and it's attributes,
3595 * basically it does the following checks as described by the
3596 * XML-1.0 recommendation:
3597 * - [ VC: Element Valid ]
3598 * - [ VC: Required Attribute ]
3599 * Then call xmlValidateOneAttribute() for each attribute present.
3600 *
3601 * The ID/IDREF checkings are done separately
3602 *
3603 * returns 1 if valid or 0 otherwise
3604 */
3605
3606int
3607xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3608 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003609 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003610 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003611 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003612 xmlNodePtr child;
3613 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003614 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003615
3616 CHECK_DTD;
3617
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003618 if (elem == NULL) return(0);
3619 if (elem->type == XML_TEXT_NODE) {
3620 }
3621 switch (elem->type) {
3622 case XML_ATTRIBUTE_NODE:
3623 VERROR(ctxt->userData,
3624 "Attribute element not expected here\n");
3625 return(0);
3626 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003627 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003628 VERROR(ctxt->userData, "Text element has childs !\n");
3629 return(0);
3630 }
3631 if (elem->properties != NULL) {
3632 VERROR(ctxt->userData, "Text element has attributes !\n");
3633 return(0);
3634 }
3635 if (elem->ns != NULL) {
3636 VERROR(ctxt->userData, "Text element has namespace !\n");
3637 return(0);
3638 }
Daniel Veillard87b95392000-08-12 21:12:04 +00003639 if (elem->nsDef != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003640 VERROR(ctxt->userData,
3641 "Text element carries namespace definitions !\n");
3642 return(0);
3643 }
3644 if (elem->content == NULL) {
3645 VERROR(ctxt->userData,
3646 "Text element has no content !\n");
3647 return(0);
3648 }
3649 return(1);
3650 case XML_CDATA_SECTION_NODE:
3651 case XML_ENTITY_REF_NODE:
3652 case XML_PI_NODE:
3653 case XML_COMMENT_NODE:
3654 return(1);
3655 case XML_ENTITY_NODE:
3656 VERROR(ctxt->userData,
3657 "Entity element not expected here\n");
3658 return(0);
3659 case XML_NOTATION_NODE:
3660 VERROR(ctxt->userData,
3661 "Notation element not expected here\n");
3662 return(0);
3663 case XML_DOCUMENT_NODE:
3664 case XML_DOCUMENT_TYPE_NODE:
3665 case XML_DOCUMENT_FRAG_NODE:
3666 VERROR(ctxt->userData,
3667 "Document element not expected here\n");
3668 return(0);
3669 case XML_HTML_DOCUMENT_NODE:
3670 VERROR(ctxt->userData,
3671 "\n");
3672 return(0);
3673 case XML_ELEMENT_NODE:
3674 break;
3675 default:
3676 VERROR(ctxt->userData,
3677 "unknown element type %d\n", elem->type);
3678 return(0);
3679 }
3680 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003681
Daniel Veillardbe803962000-06-28 23:40:59 +00003682 /*
3683 * Fetch the declaration for the qualified name
3684 */
3685 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3686 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3687 elem->name, elem->ns->prefix);
3688 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3689 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3690 elem->name, elem->ns->prefix);
3691 }
3692
3693 /*
3694 * Fetch the declaration for the non qualified name
3695 */
3696 if (elemDecl == NULL) {
3697 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3698 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3699 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3700 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003701 if (elemDecl == NULL) {
3702 VERROR(ctxt->userData, "No declaration for element %s\n",
3703 elem->name);
3704 return(0);
3705 }
3706
3707 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003708 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003709 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003710 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003711 VERROR(ctxt->userData,
3712 "Element %s was declared EMPTY this one has content\n",
3713 elem->name);
3714 ret = 0;
3715 }
3716 break;
3717 case XML_ELEMENT_TYPE_ANY:
3718 /* I don't think anything is required then */
3719 break;
3720 case XML_ELEMENT_TYPE_MIXED:
3721 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003722 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003723 while (child != NULL) {
3724 if (child->type == XML_ELEMENT_NODE) {
3725 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003726 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3727 xmlChar qname[500];
3728#ifdef HAVE_SNPRINTF
3729 snprintf((char *) qname, sizeof(qname), "%s:%s",
3730 child->ns->prefix, child->name);
3731#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003732 sprintf((char *) qname, "%s:%s",
3733 child->ns->prefix, child->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003734#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003735 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00003736 cont = elemDecl->content;
3737 while (cont != NULL) {
3738 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003739 if (xmlStrEqual(cont->name, qname)) break;
Daniel Veillardbe803962000-06-28 23:40:59 +00003740 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3741 (cont->c1 != NULL) &&
3742 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003743 if (xmlStrEqual(cont->c1->name, qname)) break;
Daniel Veillardbe803962000-06-28 23:40:59 +00003744 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3745 (cont->c1 == NULL) ||
3746 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3747 /* Internal error !!! */
3748 fprintf(stderr, "Internal: MIXED struct bad\n");
3749 break;
3750 }
3751 cont = cont->c2;
3752 }
3753 if (cont != NULL)
3754 goto child_ok;
3755 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003756 cont = elemDecl->content;
3757 while (cont != NULL) {
3758 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003759 if (xmlStrEqual(cont->name, name)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003760 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3761 (cont->c1 != NULL) &&
3762 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003763 if (xmlStrEqual(cont->c1->name, name)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003764 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3765 (cont->c1 == NULL) ||
3766 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3767 /* Internal error !!! */
3768 fprintf(stderr, "Internal: MIXED struct bad\n");
3769 break;
3770 }
3771 cont = cont->c2;
3772 }
3773 if (cont == NULL) {
3774 VERROR(ctxt->userData,
3775 "Element %s is not declared in %s list of possible childs\n",
3776 name, elem->name);
3777 ret = 0;
3778 }
3779 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003780child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003781 child = child->next;
3782 }
3783 break;
3784 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003785 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003786 cont = elemDecl->content;
3787 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3788 if ((ret == 0) || (child != NULL)) {
3789 char expr[1000];
3790 char list[2000];
3791
3792 expr[0] = 0;
3793 xmlSprintfElementContent(expr, cont, 1);
3794 list[0] = 0;
3795 xmlSprintfElementChilds(list, elem, 1);
3796
3797 VERROR(ctxt->userData,
3798 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3799 elem->name, expr, list);
3800 ret = 0;
3801 }
3802 break;
3803 }
3804
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003805 /* [ VC: Required Attribute ] */
3806 attr = elemDecl->attributes;
3807 while (attr != NULL) {
3808 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3809 xmlAttrPtr attrib;
3810 int qualified = -1;
3811
3812 attrib = elem->properties;
3813 while (attrib != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003814 if (xmlStrEqual(attrib->name, attr->name)) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003815 if (attr->prefix != NULL) {
3816 xmlNsPtr nameSpace = attrib->ns;
3817
3818 if (nameSpace == NULL)
3819 nameSpace = elem->ns;
3820 /*
3821 * qualified names handling is problematic, having a
3822 * different prefix should be possible but DTDs don't
3823 * allow to define the URI instead of the prefix :-(
3824 */
3825 if (nameSpace == NULL) {
3826 if (qualified < 0)
3827 qualified = 0;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003828 } else if (!xmlStrEqual(nameSpace->prefix, attr->prefix)) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003829 if (qualified < 1)
3830 qualified = 1;
3831 } else
3832 goto found;
3833 } else {
3834 /*
3835 * We should allow applications to define namespaces
3836 * for their application even if the DTD doesn't
3837 * carry one, otherwise, basically we would always
3838 * break.
3839 */
3840 goto found;
3841 }
3842 }
3843 attrib = attrib->next;
3844 }
3845 if (qualified == -1) {
3846 if (attr->prefix == NULL) {
3847 VERROR(ctxt->userData,
3848 "Element %s doesn't carry attribute %s\n",
3849 elem->name, attr->name);
3850 } else {
3851 VERROR(ctxt->userData,
3852 "Element %s doesn't carry attribute %s:%s\n",
3853 elem->name, attr->prefix,attr->name);
3854 }
3855 } else if (qualified == 0) {
3856 VWARNING(ctxt->userData,
3857 "Element %s required attribute %s:%s has no prefix\n",
3858 elem->name, attr->prefix,attr->name);
3859 } else if (qualified == 1) {
3860 VWARNING(ctxt->userData,
3861 "Element %s required attribute %s:%s has different prefix\n",
3862 elem->name, attr->prefix,attr->name);
3863 }
3864 }
3865found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003866 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003867 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003868 return(ret);
3869}
3870
3871/**
3872 * xmlValidateRoot:
3873 * @ctxt: the validation context
3874 * @doc: a document instance
3875 *
3876 * Try to validate a the root element
3877 * basically it does the following check as described by the
3878 * XML-1.0 recommendation:
3879 * - [ VC: Root Element Type ]
3880 * it doesn't try to recurse or apply other check to the element
3881 *
3882 * returns 1 if valid or 0 otherwise
3883 */
3884
3885int
3886xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003887 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003888 if (doc == NULL) return(0);
3889
3890 if ((doc->intSubset == NULL) ||
3891 (doc->intSubset->name == NULL)) {
3892 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3893 return(0);
3894 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003895 root = xmlDocGetRootElement(doc);
3896 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003897 VERROR(ctxt->userData, "Not valid: no root element\n");
3898 return(0);
3899 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003900
3901 /*
3902 * Check first the document root against the NQName
3903 */
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003904 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003905 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3906 xmlChar qname[500];
3907#ifdef HAVE_SNPRINTF
3908 snprintf((char *) qname, sizeof(qname), "%s:%s",
3909 root->ns->prefix, root->name);
3910#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003911 sprintf((char *) qname, "%s:%s", root->ns->prefix, root->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003912#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003913 qname[sizeof(qname) - 1] = 0;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003914 if (xmlStrEqual(doc->intSubset->name, qname))
Daniel Veillardbe803962000-06-28 23:40:59 +00003915 goto name_ok;
3916 }
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003917 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
3918 (xmlStrEqual(root->name, BAD_CAST "html")))
Daniel Veillardbe803962000-06-28 23:40:59 +00003919 goto name_ok;
3920 VERROR(ctxt->userData,
3921 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3922 root->name, doc->intSubset->name);
3923 return(0);
3924
Daniel Veillardb05deb71999-08-10 19:04:08 +00003925 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003926name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003927 return(1);
3928}
3929
3930
3931/**
3932 * xmlValidateElement:
3933 * @ctxt: the validation context
3934 * @doc: a document instance
3935 * @elem: an element instance
3936 *
3937 * Try to validate the subtree under an element
3938 *
3939 * returns 1 if valid or 0 otherwise
3940 */
3941
3942int
3943xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003944 xmlNodePtr child;
3945 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003946 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003947 int ret = 1;
3948
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003949 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003950 CHECK_DTD;
3951
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003952 ret &= xmlValidateOneElement(ctxt, doc, elem);
3953 attr = elem->properties;
3954 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003955 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003956 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3957 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003958 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003959 attr= attr->next;
3960 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003961 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003962 while (child != NULL) {
3963 ret &= xmlValidateElement(ctxt, doc, child);
3964 child = child->next;
3965 }
3966
3967 return(ret);
3968}
3969
3970/**
3971 * xmlValidateDocumentFinal:
3972 * @ctxt: the validation context
3973 * @doc: a document instance
3974 *
3975 * Does the final step for the document validation once all the
3976 * incremental validation steps have been completed
3977 *
3978 * basically it does the following checks described by the XML Rec
3979 *
3980 *
3981 * returns 1 if valid or 0 otherwise
3982 */
3983
3984int
3985xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3986 int ret = 1, i;
3987 xmlRefTablePtr table;
3988 xmlAttrPtr id;
3989
3990 if (doc == NULL) {
3991 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3992 return(0);
3993 }
3994
3995 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003996 * Check all the NOTATION/NOTATIONS attributes
3997 */
3998 /*
3999 * Check all the ENTITY/ENTITIES attributes definition for validity
4000 */
4001 /*
4002 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004003 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004004 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004005 if (table != NULL) {
4006 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00004007 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
4008 id = xmlGetID(doc, table->table[i]->value);
4009 if (id == NULL) {
4010 VERROR(ctxt->userData,
4011 "IDREF attribute %s reference an unknown ID \"%s\"\n",
4012 table->table[i]->attr->name, table->table[i]->value);
4013 ret = 0;
4014 }
4015 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
4016 xmlChar *dup, *name = NULL, *cur, save;
4017
4018 dup = xmlStrdup(table->table[i]->value);
4019 if (dup == NULL)
4020 return(0);
4021 cur = dup;
4022 while (*cur != 0) {
4023 name = cur;
4024 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
4025 save = *cur;
4026 *cur = 0;
4027 id = xmlGetID(doc, name);
4028 if (id == NULL) {
4029 VERROR(ctxt->userData,
4030 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
4031 table->table[i]->attr->name, name);
4032 ret = 0;
4033 }
4034 if (save == 0)
4035 break;
4036 *cur = save;
4037 while (IS_BLANK(*cur)) cur++;
4038 }
4039 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004040 }
4041 }
4042 }
4043 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004044}
4045
4046/**
4047 * xmlValidateDtd:
4048 * @ctxt: the validation context
4049 * @doc: a document instance
4050 * @dtd: a dtd instance
4051 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004052 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00004053 *
4054 * basically it does check all the definitions in the DtD.
4055 *
4056 * returns 1 if valid or 0 otherwise
4057 */
4058
4059int
4060xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004061 int ret;
4062 xmlDtdPtr oldExt;
4063 xmlNodePtr root;
4064
4065 if (dtd == NULL) return(0);
4066 if (doc == NULL) return(0);
4067 oldExt = doc->extSubset;
4068 doc->extSubset = dtd;
4069 ret = xmlValidateRoot(ctxt, doc);
4070 if (ret == 0) {
4071 doc->extSubset = oldExt;
4072 return(ret);
4073 }
4074 root = xmlDocGetRootElement(doc);
4075 ret = xmlValidateElement(ctxt, doc, root);
4076 ret &= xmlValidateDocumentFinal(ctxt, doc);
4077 doc->extSubset = oldExt;
4078 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004079}
4080
4081/**
Daniel Veillardcf461992000-03-14 18:30:20 +00004082 * xmlValidateDtdFinal:
4083 * @ctxt: the validation context
4084 * @doc: a document instance
4085 *
4086 * Does the final step for the dtds validation once all the
4087 * subsets have been parsed
4088 *
4089 * basically it does the following checks described by the XML Rec
4090 * - check that ENTITY and ENTITIES type attributes default or
4091 * possible values matches one of the defined entities.
4092 * - check that NOTATION type attributes default or
4093 * possible values matches one of the defined notations.
4094 *
4095 * returns 1 if valid or 0 otherwise
4096 */
4097
4098int
4099xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4100 int ret = 1, i;
4101 xmlDtdPtr dtd;
4102 xmlAttributeTablePtr table;
4103 xmlAttributePtr cur;
4104
4105 if (doc == NULL) return(0);
4106 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4107 return(0);
4108 dtd = doc->intSubset;
4109 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004110 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004111
4112 for (i = 0;i < table->nb_attributes;i++) {
4113 cur = table->table[i];
4114 switch (cur->atype) {
4115 case XML_ATTRIBUTE_CDATA:
4116 case XML_ATTRIBUTE_ID:
4117 case XML_ATTRIBUTE_IDREF :
4118 case XML_ATTRIBUTE_IDREFS:
4119 case XML_ATTRIBUTE_NMTOKEN:
4120 case XML_ATTRIBUTE_NMTOKENS:
4121 case XML_ATTRIBUTE_ENUMERATION:
4122 break;
4123 case XML_ATTRIBUTE_ENTITY:
4124 case XML_ATTRIBUTE_ENTITIES:
4125 case XML_ATTRIBUTE_NOTATION:
4126 if (cur->defaultValue != NULL) {
4127 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4128 cur->atype, cur->defaultValue);
4129 }
4130 if (cur->tree != NULL) {
4131 xmlEnumerationPtr tree = cur->tree;
4132 while (tree != NULL) {
4133 ret &= xmlValidateAttributeValue2(ctxt, doc,
4134 cur->name, cur->atype, tree->name);
4135 tree = tree->next;
4136 }
4137 }
4138 }
4139 }
4140 }
4141 dtd = doc->extSubset;
4142 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004143 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004144
4145 for (i = 0;i < table->nb_attributes;i++) {
4146 cur = table->table[i];
4147 switch (cur->atype) {
4148 case XML_ATTRIBUTE_CDATA:
4149 case XML_ATTRIBUTE_ID:
4150 case XML_ATTRIBUTE_IDREF :
4151 case XML_ATTRIBUTE_IDREFS:
4152 case XML_ATTRIBUTE_NMTOKEN:
4153 case XML_ATTRIBUTE_NMTOKENS:
4154 case XML_ATTRIBUTE_ENUMERATION:
4155 break;
4156 case XML_ATTRIBUTE_ENTITY:
4157 case XML_ATTRIBUTE_ENTITIES:
4158 case XML_ATTRIBUTE_NOTATION:
4159 if (cur->defaultValue != NULL) {
4160 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4161 cur->atype, cur->defaultValue);
4162 }
4163 if (cur->tree != NULL) {
4164 xmlEnumerationPtr tree = cur->tree;
4165 while (tree != NULL) {
4166 ret &= xmlValidateAttributeValue2(ctxt, doc,
4167 cur->name, cur->atype, tree->name);
4168 tree = tree->next;
4169 }
4170 }
4171 }
4172 }
4173 }
4174 return(ret);
4175}
4176
4177/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00004178 * xmlValidateDocument:
4179 * @ctxt: the validation context
4180 * @doc: a document instance
4181 *
4182 * Try to validate the document instance
4183 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004184 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00004185 * i.e. validates the internal and external subset (if present)
4186 * and validate the document tree.
4187 *
4188 * returns 1 if valid or 0 otherwise
4189 */
4190
4191int
4192xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004193 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004194 xmlNodePtr root;
4195
4196 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4197 return(0);
4198 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4199 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4200 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4201 doc->intSubset->SystemID);
4202 if (doc->extSubset == NULL) {
4203 if (doc->intSubset->SystemID != NULL) {
4204 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004205 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004206 doc->intSubset->SystemID);
4207 } else {
4208 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004209 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004210 doc->intSubset->ExternalID);
4211 }
4212 return(0);
4213 }
4214 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004215
Daniel Veillardcf461992000-03-14 18:30:20 +00004216 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004217 if (!xmlValidateRoot(ctxt, doc)) return(0);
4218
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004219 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00004220 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004221 ret &= xmlValidateDocumentFinal(ctxt, doc);
4222 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004223}
4224
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004225
4226/************************************************************************
4227 * *
4228 * Routines for dynamic validation editing *
4229 * *
4230 ************************************************************************/
4231
4232/**
4233 * xmlValidGetPotentialChildren:
4234 * @ctree: an element content tree
4235 * @list: an array to store the list of child names
4236 * @len: a pointer to the number of element in the list
4237 * @max: the size of the array
4238 *
4239 * Build/extend a list of potential children allowed by the content tree
4240 *
4241 * returns the number of element in the list, or -1 in case of error.
4242 */
4243
4244int
4245xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4246 int *len, int max) {
4247 int i;
4248
4249 if ((ctree == NULL) || (list == NULL) || (len == NULL))
4250 return(-1);
4251 if (*len >= max) return(*len);
4252
4253 switch (ctree->type) {
4254 case XML_ELEMENT_CONTENT_PCDATA:
4255 for (i = 0; i < *len;i++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004256 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
Daniel Veillarda819dac1999-11-24 18:04:22 +00004257 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004258 break;
4259 case XML_ELEMENT_CONTENT_ELEMENT:
4260 for (i = 0; i < *len;i++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004261 if (xmlStrEqual(ctree->name, list[i])) return(*len);
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004262 list[(*len)++] = ctree->name;
4263 break;
4264 case XML_ELEMENT_CONTENT_SEQ:
4265 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4266 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4267 break;
4268 case XML_ELEMENT_CONTENT_OR:
4269 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4270 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4271 break;
4272 }
4273
4274 return(*len);
4275}
4276
4277/**
4278 * xmlValidGetValidElements:
4279 * @prev: an element to insert after
4280 * @next: an element to insert next
4281 * @list: an array to store the list of child names
4282 * @max: the size of the array
4283 *
4284 * This function returns the list of authorized children to insert
4285 * within an existing tree while respecting the validity constraints
4286 * forced by the Dtd. The insertion point is defined using @prev and
4287 * @next in the following ways:
4288 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4289 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4290 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4291 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4292 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4293 *
4294 * pointers to the element names are inserted at the beginning of the array
4295 * and do not need to be freed.
4296 *
4297 * returns the number of element in the list, or -1 in case of error. If
4298 * the function returns the value @max the caller is invited to grow the
4299 * receiving array and retry.
4300 */
4301
4302int
4303xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4304 int max) {
4305 int nb_valid_elements = 0;
4306 const xmlChar *elements[256];
4307 int nb_elements = 0, i;
4308
4309 xmlNode *ref_node;
4310 xmlNode *parent;
4311 xmlNode *test_node;
4312
4313 xmlNode *prev_next;
4314 xmlNode *next_prev;
4315 xmlNode *parent_childs;
4316 xmlNode *parent_last;
4317
4318 xmlElement *element_desc;
4319
4320 if (prev == NULL && next == NULL)
4321 return(-1);
4322
4323 if (list == NULL) return(-1);
4324 if (max <= 0) return(-1);
4325
4326 nb_valid_elements = 0;
4327 ref_node = prev ? prev : next;
4328 parent = ref_node->parent;
4329
4330 /*
4331 * Retrieves the parent element declaration
4332 */
4333 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4334 parent->name);
4335 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4336 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4337 parent->name);
4338 if (element_desc == NULL) return(-1);
4339
4340 /*
4341 * Do a backup of the current tree structure
4342 */
4343 prev_next = prev ? prev->next : NULL;
4344 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004345 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004346 parent_last = parent->last;
4347
4348 /*
4349 * Creates a dummy node and insert it into the tree
4350 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004351 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004352 test_node->doc = ref_node->doc;
4353 test_node->parent = parent;
4354 test_node->prev = prev;
4355 test_node->next = next;
4356
4357 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00004358 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004359
4360 if (next) next->prev = test_node;
4361 else parent->last = test_node;
4362
4363 /*
4364 * Insert each potential child node and check if the parent is
4365 * still valid
4366 */
4367 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4368 elements, &nb_elements, 256);
4369
4370 for (i = 0;i < nb_elements;i++) {
4371 test_node->name = elements[i];
4372 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4373 int j;
4374
4375 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004376 if (xmlStrEqual(elements[i], list[j])) break;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004377 list[nb_valid_elements++] = elements[i];
4378 if (nb_valid_elements >= max) break;
4379 }
4380 }
4381
4382 /*
4383 * Restore the tree structure
4384 */
4385 if (prev) prev->next = prev_next;
4386 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004387 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004388 parent->last = parent_last;
4389
4390 return(nb_valid_elements);
4391}