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