blob: 41c04d1c09875fb0497302fbcba6370f14522c42 [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 Veillardb05deb71999-08-10 19:04:08 +0000466 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000467 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +0000468 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000469 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000470 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000471 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000472 return(NULL);
473 }
474 return(ret);
475}
476
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000477
478/**
479 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000480 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000481 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000482 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000483 * @type: the element type
484 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000485 *
486 * Register a new element declaration
487 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000488 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000489 */
490xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000491xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillardcf461992000-03-14 18:30:20 +0000492 xmlElementTypeVal type,
493 xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000494 xmlElementPtr ret, cur;
495 xmlElementTablePtr table;
Daniel Veillardbe803962000-06-28 23:40:59 +0000496 xmlChar *ns, *uqname;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000497 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000498
499 if (dtd == NULL) {
500 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
501 return(NULL);
502 }
503 if (name == NULL) {
504 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
505 return(NULL);
506 }
507 switch (type) {
508 case XML_ELEMENT_TYPE_EMPTY:
509 if (content != NULL) {
510 fprintf(stderr,
511 "xmlAddElementDecl: content != NULL for EMPTY\n");
512 return(NULL);
513 }
514 break;
515 case XML_ELEMENT_TYPE_ANY:
516 if (content != NULL) {
517 fprintf(stderr,
518 "xmlAddElementDecl: content != NULL for ANY\n");
519 return(NULL);
520 }
521 break;
522 case XML_ELEMENT_TYPE_MIXED:
523 if (content == NULL) {
524 fprintf(stderr,
525 "xmlAddElementDecl: content == NULL for MIXED\n");
526 return(NULL);
527 }
528 break;
529 case XML_ELEMENT_TYPE_ELEMENT:
530 if (content == NULL) {
531 fprintf(stderr,
532 "xmlAddElementDecl: content == NULL for ELEMENT\n");
533 return(NULL);
534 }
535 break;
536 default:
537 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
538 return(NULL);
539 }
540
541 /*
Daniel Veillardbe803962000-06-28 23:40:59 +0000542 * check if name is a QName
543 */
544 uqname = xmlSplitQName2(name, &ns);
545 if (uqname != NULL)
546 name = uqname;
547
548 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000549 * Create the Element table if needed.
550 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000551 table = (xmlElementTablePtr) dtd->elements;
552 if (table == NULL) {
553 table = xmlCreateElementTable();
554 dtd->elements = (void *) table;
555 }
Daniel Veillard3b9def11999-01-31 22:15:06 +0000556 if (table == NULL) {
557 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
558 return(NULL);
559 }
560
561 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000562 * Validity Check:
563 * Search the DTD for previous declarations of the ELEMENT
564 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000565 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000566 cur = table->table[i];
Daniel Veillardbe803962000-06-28 23:40:59 +0000567 if ((ns != NULL) && (cur->prefix == NULL)) continue;
568 if ((ns == NULL) && (cur->prefix != NULL)) continue;
569 if ((!xmlStrcmp(cur->name, name)) &&
570 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000571 /*
572 * The element is already defined in this Dtd.
573 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000574 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000575 return(NULL);
576 }
577 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000578
579 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000580 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000581 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000582 if (table->nb_elements >= table->max_elements) {
583 /*
584 * need more elements.
585 */
586 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000587 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000588 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000589 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000590 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
591 return(NULL);
592 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000593 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000594 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000595 if (ret == NULL) {
596 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
597 return(NULL);
598 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000599 memset(ret, 0, sizeof(xmlElement));
600 ret->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000601 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000602
603 /*
604 * fill the structure.
605 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000606 ret->etype = type;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000607 ret->name = xmlStrdup(name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000608 ret->prefix = ns;
Daniel Veillard14fff061999-06-22 21:49:07 +0000609 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000610 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000611 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000612
Daniel Veillardcf461992000-03-14 18:30:20 +0000613 /*
614 * Link it to the Dtd
615 */
616 ret->parent = dtd;
617 ret->doc = dtd->doc;
618 if (dtd->last == NULL) {
619 dtd->children = dtd->last = (xmlNodePtr) ret;
620 } else {
621 dtd->last->next = (xmlNodePtr) ret;
622 ret->prev = dtd->last;
623 dtd->last = (xmlNodePtr) ret;
624 }
Daniel Veillardbe803962000-06-28 23:40:59 +0000625 if (uqname != NULL)
626 xmlFree(uqname);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000627 return(ret);
628}
629
Daniel Veillard3b9def11999-01-31 22:15:06 +0000630/**
631 * xmlFreeElement:
632 * @elem: An element
633 *
634 * Deallocate the memory used by an element definition
635 */
636void
637xmlFreeElement(xmlElementPtr elem) {
638 if (elem == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +0000639 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000640 xmlFreeElementContent(elem->content);
641 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000642 xmlFree((xmlChar *) elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000643 if (elem->prefix != NULL)
644 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000645 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000646 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000647}
648
649/**
650 * xmlFreeElementTable:
651 * @table: An element table
652 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000653 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000654 */
655void
656xmlFreeElementTable(xmlElementTablePtr table) {
657 int i;
658
659 if (table == NULL) return;
660
661 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000662 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000663 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000664 xmlFree(table->table);
665 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000666}
667
668/**
669 * xmlCopyElementTable:
670 * @table: An element table
671 *
672 * Build a copy of an element table.
673 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000674 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000675 */
676xmlElementTablePtr
677xmlCopyElementTable(xmlElementTablePtr table) {
678 xmlElementTablePtr ret;
679 xmlElementPtr cur, ent;
680 int i;
681
Daniel Veillard6454aec1999-09-02 22:04:43 +0000682 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000683 if (ret == NULL) {
684 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
685 return(NULL);
686 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000687 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000688 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000689 if (ret->table == NULL) {
690 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000691 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000692 return(NULL);
693 }
694 ret->max_elements = table->max_elements;
695 ret->nb_elements = table->nb_elements;
696 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000697 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000698 if (cur == NULL) {
699 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000700 xmlFree(ret);
701 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000702 return(NULL);
703 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000704 memset(cur, 0, sizeof(xmlElement));
705 cur->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000706 ret->table[i] = cur;
707 ent = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000708 cur->etype = ent->etype;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000709 if (ent->name != NULL)
710 cur->name = xmlStrdup(ent->name);
711 else
712 cur->name = NULL;
713 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000714 /* TODO : rebuild the attribute list on the copy */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000715 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000716 }
717 return(ret);
718}
719
720/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000721 * xmlDumpElementDecl:
722 * @buf: the XML buffer output
723 * @elem: An element table
724 *
725 * This will dump the content of the element declaration as an XML
726 * DTD definition
727 */
728void
729xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
730 switch (elem->etype) {
731 case XML_ELEMENT_TYPE_EMPTY:
732 xmlBufferWriteChar(buf, "<!ELEMENT ");
733 xmlBufferWriteCHAR(buf, elem->name);
734 xmlBufferWriteChar(buf, " EMPTY>\n");
735 break;
736 case XML_ELEMENT_TYPE_ANY:
737 xmlBufferWriteChar(buf, "<!ELEMENT ");
738 xmlBufferWriteCHAR(buf, elem->name);
739 xmlBufferWriteChar(buf, " ANY>\n");
740 break;
741 case XML_ELEMENT_TYPE_MIXED:
742 xmlBufferWriteChar(buf, "<!ELEMENT ");
743 xmlBufferWriteCHAR(buf, elem->name);
744 xmlBufferWriteChar(buf, " ");
745 xmlDumpElementContent(buf, elem->content, 1);
746 xmlBufferWriteChar(buf, ">\n");
747 break;
748 case XML_ELEMENT_TYPE_ELEMENT:
749 xmlBufferWriteChar(buf, "<!ELEMENT ");
750 xmlBufferWriteCHAR(buf, elem->name);
751 xmlBufferWriteChar(buf, " ");
752 xmlDumpElementContent(buf, elem->content, 1);
753 xmlBufferWriteChar(buf, ">\n");
754 break;
755 default:
756 fprintf(stderr,
757 "xmlDumpElementDecl: internal: unknown type %d\n",
758 elem->etype);
759 }
760}
761
762/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000763 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000764 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000765 * @table: An element table
766 *
767 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000768 */
769void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000770xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000771 int i;
772 xmlElementPtr cur;
773
774 if (table == NULL) return;
775
776 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000777 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000778 xmlDumpElementDecl(buf, cur);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000779 }
780}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000781
782/**
783 * xmlCreateEnumeration:
784 * @name: the enumeration name or NULL
785 *
786 * create and initialize an enumeration attribute node.
787 *
788 * Returns the xmlEnumerationPtr just created or NULL in case
789 * of error.
790 */
791xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000792xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000793 xmlEnumerationPtr ret;
794
Daniel Veillard6454aec1999-09-02 22:04:43 +0000795 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000796 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000797 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000798 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000799 return(NULL);
800 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000801 memset(ret, 0, sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000802
803 if (name != NULL)
804 ret->name = xmlStrdup(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000805 return(ret);
806}
807
808/**
809 * xmlFreeEnumeration:
810 * @cur: the tree to free.
811 *
812 * free an enumeration attribute node (recursive).
813 */
814void
815xmlFreeEnumeration(xmlEnumerationPtr cur) {
816 if (cur == NULL) return;
817
818 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
819
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000820 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000821 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000822 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000823}
824
825/**
826 * xmlCopyEnumeration:
827 * @cur: the tree to copy.
828 *
829 * Copy an enumeration attribute node (recursive).
830 *
831 * Returns the xmlEnumerationPtr just created or NULL in case
832 * of error.
833 */
834xmlEnumerationPtr
835xmlCopyEnumeration(xmlEnumerationPtr cur) {
836 xmlEnumerationPtr ret;
837
838 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000839 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000840
841 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
842 else ret->next = NULL;
843
844 return(ret);
845}
846
847/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000848 * xmlDumpEnumeration:
849 * @buf: the XML buffer output
850 * @enum: An enumeration
851 *
852 * This will dump the content of the enumeration
853 */
854void
855xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
856 if (cur == NULL) return;
857
858 xmlBufferWriteCHAR(buf, cur->name);
859 if (cur->next == NULL)
860 xmlBufferWriteChar(buf, ")");
861 else {
862 xmlBufferWriteChar(buf, " | ");
863 xmlDumpEnumeration(buf, cur->next);
864 }
865}
866
867/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000868 * xmlCreateAttributeTable:
869 *
870 * create and initialize an empty attribute hash table.
871 *
872 * Returns the xmlAttributeTablePtr just created or NULL in case
873 * of error.
874 */
875xmlAttributeTablePtr
876xmlCreateAttributeTable(void) {
877 xmlAttributeTablePtr ret;
878
879 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000880 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000881 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000882 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000883 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000884 return(NULL);
885 }
886 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
887 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000888 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000889 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard87b95392000-08-12 21:12:04 +0000890 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000891 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000892 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000893 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000894 return(NULL);
895 }
896 return(ret);
897}
898
Daniel Veillardb05deb71999-08-10 19:04:08 +0000899/**
900 * xmlScanAttributeDecl:
901 * @dtd: pointer to the DTD
902 * @elem: the element name
903 *
904 * When inserting a new element scan the DtD for existing attributes
905 * for taht element and initialize the Attribute chain
906 *
907 * Returns the pointer to the first attribute decl in the chain,
908 * possibly NULL.
909 */
910xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000911xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000912 xmlAttributePtr ret = NULL;
913 xmlAttributeTablePtr table;
914 int i;
915
916 if (dtd == NULL) {
917 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
918 return(NULL);
919 }
920 if (elem == NULL) {
921 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
922 return(NULL);
923 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000924 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000925 if (table == NULL)
926 return(NULL);
927
928 for (i = 0;i < table->nb_attributes;i++) {
929 if (!xmlStrcmp(table->table[i]->elem, elem)) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000930 table->table[i]->nexth = ret;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000931 ret = table->table[i];
932 }
933 }
934 return(ret);
935}
936
937/**
938 * xmlScanIDAttributeDecl:
939 * @ctxt: the validation context
940 * @elem: the element name
941 *
Daniel Veillard71b656e2000-01-05 14:46:17 +0000942 * Verify that the element don't have too many ID attributes
Daniel Veillardb05deb71999-08-10 19:04:08 +0000943 * declared.
944 *
945 * Returns the number of ID attributes found.
946 */
947int
948xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
949 xmlAttributePtr cur;
950 int ret = 0;
951
952 if (elem == NULL) return(0);
953 cur = elem->attributes;
954 while (cur != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000955 if (cur->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000956 ret ++;
957 if (ret > 1)
958 VERROR(ctxt->userData,
959 "Element %s has too may ID attributes defined : %s\n",
960 elem->name, cur->name);
961 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000962 cur = cur->nexth;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000963 }
964 return(ret);
965}
966
Daniel Veillard1e346af1999-02-22 10:33:01 +0000967
968/**
969 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000970 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000971 * @dtd: pointer to the DTD
972 * @elem: the element name
973 * @name: the attribute name
Daniel Veillardcf461992000-03-14 18:30:20 +0000974 * @ns: the attribute namespace prefix
Daniel Veillard1e346af1999-02-22 10:33:01 +0000975 * @type: the attribute type
976 * @def: the attribute default type
977 * @defaultValue: the attribute default value
978 * @tree: if it's an enumeration, the associated list
979 *
980 * Register a new attribute declaration
981 *
Daniel Veillardbe803962000-06-28 23:40:59 +0000982 * Returns NULL if not new, othervise the attribute decl
Daniel Veillard1e346af1999-02-22 10:33:01 +0000983 */
984xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000985xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
Daniel Veillardcf461992000-03-14 18:30:20 +0000986 const xmlChar *name, const xmlChar *ns,
987 xmlAttributeType type, xmlAttributeDefault def,
988 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000989 xmlAttributePtr ret, cur;
990 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000991 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000992 int i;
993
994 if (dtd == NULL) {
995 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
996 return(NULL);
997 }
998 if (name == NULL) {
999 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
1000 return(NULL);
1001 }
1002 if (elem == NULL) {
1003 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
1004 return(NULL);
1005 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001006 /*
1007 * Check the type and possibly the default value.
1008 */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001009 switch (type) {
1010 case XML_ATTRIBUTE_CDATA:
1011 break;
1012 case XML_ATTRIBUTE_ID:
1013 break;
1014 case XML_ATTRIBUTE_IDREF:
1015 break;
1016 case XML_ATTRIBUTE_IDREFS:
1017 break;
1018 case XML_ATTRIBUTE_ENTITY:
1019 break;
1020 case XML_ATTRIBUTE_ENTITIES:
1021 break;
1022 case XML_ATTRIBUTE_NMTOKEN:
1023 break;
1024 case XML_ATTRIBUTE_NMTOKENS:
1025 break;
1026 case XML_ATTRIBUTE_ENUMERATION:
1027 break;
1028 case XML_ATTRIBUTE_NOTATION:
1029 break;
1030 default:
1031 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
1032 return(NULL);
1033 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001034 if ((defaultValue != NULL) &&
1035 (!xmlValidateAttributeValue(type, defaultValue))) {
1036 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
1037 elem, name, defaultValue);
1038 defaultValue = NULL;
1039 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001040
1041 /*
1042 * Create the Attribute table if needed.
1043 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001044 table = (xmlAttributeTablePtr) dtd->attributes;
1045 if (table == NULL) {
1046 table = xmlCreateAttributeTable();
1047 dtd->attributes = (void *) table;
1048 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001049 if (table == NULL) {
1050 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
1051 return(NULL);
1052 }
1053
1054 /*
1055 * Validity Check:
1056 * Search the DTD for previous declarations of the ATTLIST
1057 */
1058 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001059 cur = table->table[i];
Daniel Veillard10a2c651999-12-12 13:03:50 +00001060 if ((ns != NULL) && (cur->prefix == NULL)) continue;
1061 if ((ns == NULL) && (cur->prefix != NULL)) continue;
Daniel Veillardcf461992000-03-14 18:30:20 +00001062 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem)) &&
Daniel Veillard10a2c651999-12-12 13:03:50 +00001063 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001064 /*
1065 * The attribute is already defined in this Dtd.
1066 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001067 VWARNING(ctxt->userData, "Attribute %s on %s: already defined\n",
Daniel Veillardb96e6431999-08-29 21:02:19 +00001068 elem, name);
Daniel Veillardbe803962000-06-28 23:40:59 +00001069 return(NULL);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001070 }
1071 }
1072
1073 /*
1074 * Grow the table, if needed.
1075 */
1076 if (table->nb_attributes >= table->max_attributes) {
1077 /*
1078 * need more attributes.
1079 */
1080 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001081 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001082 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001083 sizeof(xmlAttributePtr));
1084 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001085 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1086 return(NULL);
1087 }
1088 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001089 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001090 if (ret == NULL) {
1091 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1092 return(NULL);
1093 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001094 memset(ret, 0, sizeof(xmlAttribute));
1095 ret->type = XML_ATTRIBUTE_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001096 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001097
1098 /*
1099 * fill the structure.
1100 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001101 ret->atype = type;
1102 ret->name = xmlStrdup(name);
1103 ret->prefix = xmlStrdup(ns);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001104 ret->elem = xmlStrdup(elem);
1105 ret->def = def;
1106 ret->tree = tree;
1107 if (defaultValue != NULL)
1108 ret->defaultValue = xmlStrdup(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001109 elemDef = xmlGetDtdElementDesc(dtd, elem);
1110 if (elemDef != NULL) {
1111 if ((type == XML_ATTRIBUTE_ID) &&
1112 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
1113 VERROR(ctxt->userData,
1114 "Element %s has too may ID attributes defined : %s\n",
1115 elem, name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001116 ret->nexth = elemDef->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001117 elemDef->attributes = ret;
1118 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001119 table->nb_attributes++;
1120
Daniel Veillardcf461992000-03-14 18:30:20 +00001121 /*
1122 * Link it to the Dtd
1123 */
1124 ret->parent = dtd;
1125 ret->doc = dtd->doc;
1126 if (dtd->last == NULL) {
1127 dtd->children = dtd->last = (xmlNodePtr) ret;
1128 } else {
1129 dtd->last->next = (xmlNodePtr) ret;
1130 ret->prev = dtd->last;
1131 dtd->last = (xmlNodePtr) ret;
1132 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001133 return(ret);
1134}
1135
1136/**
1137 * xmlFreeAttribute:
1138 * @elem: An attribute
1139 *
1140 * Deallocate the memory used by an attribute definition
1141 */
1142void
1143xmlFreeAttribute(xmlAttributePtr attr) {
1144 if (attr == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +00001145 xmlUnlinkNode((xmlNodePtr) attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001146 if (attr->tree != NULL)
1147 xmlFreeEnumeration(attr->tree);
1148 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001149 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001150 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001151 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001152 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001153 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +00001154 if (attr->prefix != NULL)
1155 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001156 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001157 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001158}
1159
1160/**
1161 * xmlFreeAttributeTable:
1162 * @table: An attribute table
1163 *
1164 * Deallocate the memory used by an entities hash table.
1165 */
1166void
1167xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1168 int i;
1169
1170 if (table == NULL) return;
1171
1172 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001173 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001174 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001175 xmlFree(table->table);
1176 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001177}
1178
1179/**
1180 * xmlCopyAttributeTable:
1181 * @table: An attribute table
1182 *
1183 * Build a copy of an attribute table.
1184 *
1185 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1186 */
1187xmlAttributeTablePtr
1188xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1189 xmlAttributeTablePtr ret;
1190 xmlAttributePtr cur, attr;
1191 int i;
1192
Daniel Veillard6454aec1999-09-02 22:04:43 +00001193 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001194 if (ret == NULL) {
1195 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1196 return(NULL);
1197 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001198 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001199 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001200 if (ret->table == NULL) {
1201 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001202 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001203 return(NULL);
1204 }
1205 ret->max_attributes = table->max_attributes;
1206 ret->nb_attributes = table->nb_attributes;
1207 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001208 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001209 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001210 if (cur == NULL) {
1211 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001212 xmlFree(ret);
1213 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001214 return(NULL);
1215 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001216 memset(cur, 0, sizeof(xmlAttribute));
1217 /* !!! cur->type = XML_ATTRIBUTE_DECL; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001218 ret->table[i] = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001219 cur->atype = attr->atype;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001220 cur->def = attr->def;
1221 cur->tree = xmlCopyEnumeration(attr->tree);
1222 if (attr->elem != NULL)
1223 cur->elem = xmlStrdup(attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001224 if (attr->name != NULL)
1225 cur->name = xmlStrdup(attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001226 if (attr->defaultValue != NULL)
1227 cur->defaultValue = xmlStrdup(attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001228 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001229 }
1230 return(ret);
1231}
1232
1233/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001234 * xmlDumpAttributeDecl:
1235 * @buf: the XML buffer output
1236 * @attr: An attribute declaration
1237 *
1238 * This will dump the content of the attribute declaration as an XML
1239 * DTD definition
1240 */
1241void
1242xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1243 xmlBufferWriteChar(buf, "<!ATTLIST ");
1244 xmlBufferWriteCHAR(buf, attr->elem);
1245 xmlBufferWriteChar(buf, " ");
Daniel Veillardbe803962000-06-28 23:40:59 +00001246 if (attr->prefix != NULL) {
1247 xmlBufferWriteCHAR(buf, attr->prefix);
1248 xmlBufferWriteChar(buf, ":");
1249 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001250 xmlBufferWriteCHAR(buf, attr->name);
1251 switch (attr->atype) {
1252 case XML_ATTRIBUTE_CDATA:
1253 xmlBufferWriteChar(buf, " CDATA");
1254 break;
1255 case XML_ATTRIBUTE_ID:
1256 xmlBufferWriteChar(buf, " ID");
1257 break;
1258 case XML_ATTRIBUTE_IDREF:
1259 xmlBufferWriteChar(buf, " IDREF");
1260 break;
1261 case XML_ATTRIBUTE_IDREFS:
1262 xmlBufferWriteChar(buf, " IDREFS");
1263 break;
1264 case XML_ATTRIBUTE_ENTITY:
1265 xmlBufferWriteChar(buf, " ENTITY");
1266 break;
1267 case XML_ATTRIBUTE_ENTITIES:
1268 xmlBufferWriteChar(buf, " ENTITIES");
1269 break;
1270 case XML_ATTRIBUTE_NMTOKEN:
1271 xmlBufferWriteChar(buf, " NMTOKEN");
1272 break;
1273 case XML_ATTRIBUTE_NMTOKENS:
1274 xmlBufferWriteChar(buf, " NMTOKENS");
1275 break;
1276 case XML_ATTRIBUTE_ENUMERATION:
1277 xmlBufferWriteChar(buf, " (");
1278 xmlDumpEnumeration(buf, attr->tree);
1279 break;
1280 case XML_ATTRIBUTE_NOTATION:
1281 xmlBufferWriteChar(buf, " NOTATION (");
1282 xmlDumpEnumeration(buf, attr->tree);
1283 break;
1284 default:
1285 fprintf(stderr,
1286 "xmlDumpAttributeTable: internal: unknown type %d\n",
1287 attr->atype);
1288 }
1289 switch (attr->def) {
1290 case XML_ATTRIBUTE_NONE:
1291 break;
1292 case XML_ATTRIBUTE_REQUIRED:
1293 xmlBufferWriteChar(buf, " #REQUIRED");
1294 break;
1295 case XML_ATTRIBUTE_IMPLIED:
1296 xmlBufferWriteChar(buf, " #IMPLIED");
1297 break;
1298 case XML_ATTRIBUTE_FIXED:
1299 xmlBufferWriteChar(buf, " #FIXED");
1300 break;
1301 default:
1302 fprintf(stderr,
1303 "xmlDumpAttributeTable: internal: unknown default %d\n",
1304 attr->def);
1305 }
1306 if (attr->defaultValue != NULL) {
1307 xmlBufferWriteChar(buf, " ");
1308 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1309 }
1310 xmlBufferWriteChar(buf, ">\n");
1311}
1312
1313/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001314 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001315 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001316 * @table: An attribute table
1317 *
1318 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001319 */
1320void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001321xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001322 int i;
1323 xmlAttributePtr cur;
1324
1325 if (table == NULL) return;
1326
1327 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001328 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001329 xmlDumpAttributeDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001330 }
1331}
1332
1333/************************************************************************
1334 * *
1335 * NOTATIONs *
1336 * *
1337 ************************************************************************/
1338/**
1339 * xmlCreateNotationTable:
1340 *
1341 * create and initialize an empty notation hash table.
1342 *
1343 * Returns the xmlNotationTablePtr just created or NULL in case
1344 * of error.
1345 */
1346xmlNotationTablePtr
1347xmlCreateNotationTable(void) {
1348 xmlNotationTablePtr ret;
1349
1350 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001351 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001352 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001353 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001354 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001355 return(NULL);
1356 }
1357 ret->max_notations = XML_MIN_NOTATION_TABLE;
1358 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001359 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001360 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001361 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001362 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001363 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001364 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001365 return(NULL);
1366 }
1367 return(ret);
1368}
1369
1370
1371/**
1372 * xmlAddNotationDecl:
1373 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001374 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001375 * @name: the entity name
1376 * @PublicID: the public identifier or NULL
1377 * @SystemID: the system identifier or NULL
1378 *
1379 * Register a new notation declaration
1380 *
1381 * Returns NULL if not, othervise the entity
1382 */
1383xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001384xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1385 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001386 xmlNotationPtr ret, cur;
1387 xmlNotationTablePtr table;
1388 int i;
1389
1390 if (dtd == NULL) {
1391 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1392 return(NULL);
1393 }
1394 if (name == NULL) {
1395 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1396 return(NULL);
1397 }
1398 if ((PublicID == NULL) && (SystemID == NULL)) {
1399 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1400 }
1401
1402 /*
1403 * Create the Notation table if needed.
1404 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001405 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001406 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001407 dtd->notations = table = xmlCreateNotationTable();
Daniel Veillard1e346af1999-02-22 10:33:01 +00001408 if (table == NULL) {
1409 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1410 return(NULL);
1411 }
1412
1413 /*
1414 * Validity Check:
1415 * Search the DTD for previous declarations of the ATTLIST
1416 */
1417 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001418 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001419 if (!xmlStrcmp(cur->name, name)) {
1420 /*
1421 * The notation is already defined in this Dtd.
1422 */
1423 fprintf(stderr,
1424 "xmlAddNotationDecl: %s already defined\n", name);
1425 }
1426 }
1427
1428 /*
1429 * Grow the table, if needed.
1430 */
1431 if (table->nb_notations >= table->max_notations) {
1432 /*
1433 * need more notations.
1434 */
1435 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001436 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001437 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001438 sizeof(xmlNotationPtr));
1439 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001440 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1441 return(NULL);
1442 }
1443 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001444 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001445 if (ret == NULL) {
1446 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1447 return(NULL);
1448 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001449 memset(ret, 0, sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001450 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001451
1452 /*
1453 * fill the structure.
1454 */
1455 ret->name = xmlStrdup(name);
1456 if (SystemID != NULL)
1457 ret->SystemID = xmlStrdup(SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001458 if (PublicID != NULL)
1459 ret->PublicID = xmlStrdup(PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001460 table->nb_notations++;
1461
1462 return(ret);
1463}
1464
1465/**
1466 * xmlFreeNotation:
1467 * @not: A notation
1468 *
1469 * Deallocate the memory used by an notation definition
1470 */
1471void
1472xmlFreeNotation(xmlNotationPtr nota) {
1473 if (nota == NULL) return;
1474 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001475 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001476 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001477 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001478 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001479 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001480 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001481 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001482}
1483
1484/**
1485 * xmlFreeNotationTable:
1486 * @table: An notation table
1487 *
1488 * Deallocate the memory used by an entities hash table.
1489 */
1490void
1491xmlFreeNotationTable(xmlNotationTablePtr table) {
1492 int i;
1493
1494 if (table == NULL) return;
1495
1496 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001497 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001498 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001499 xmlFree(table->table);
1500 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001501}
1502
1503/**
1504 * xmlCopyNotationTable:
1505 * @table: A notation table
1506 *
1507 * Build a copy of a notation table.
1508 *
1509 * Returns the new xmlNotationTablePtr or NULL in case of error.
1510 */
1511xmlNotationTablePtr
1512xmlCopyNotationTable(xmlNotationTablePtr table) {
1513 xmlNotationTablePtr ret;
1514 xmlNotationPtr cur, nota;
1515 int i;
1516
Daniel Veillard6454aec1999-09-02 22:04:43 +00001517 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001518 if (ret == NULL) {
1519 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1520 return(NULL);
1521 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001522 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001523 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001524 if (ret->table == NULL) {
1525 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001526 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001527 return(NULL);
1528 }
1529 ret->max_notations = table->max_notations;
1530 ret->nb_notations = table->nb_notations;
1531 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001532 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001533 if (cur == NULL) {
1534 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001535 xmlFree(ret);
1536 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001537 return(NULL);
1538 }
1539 ret->table[i] = cur;
1540 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001541 if (nota->name != NULL)
1542 cur->name = xmlStrdup(nota->name);
1543 else
1544 cur->name = NULL;
1545 if (nota->PublicID != NULL)
1546 cur->PublicID = xmlStrdup(nota->PublicID);
1547 else
1548 cur->PublicID = NULL;
1549 if (nota->SystemID != NULL)
1550 cur->SystemID = xmlStrdup(nota->SystemID);
1551 else
1552 cur->SystemID = NULL;
1553 }
1554 return(ret);
1555}
1556
1557/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001558 * xmlDumpNotationDecl:
1559 * @buf: the XML buffer output
1560 * @nota: A notation declaration
1561 *
1562 * This will dump the content the notation declaration as an XML DTD definition
1563 */
1564void
1565xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
1566 xmlBufferWriteChar(buf, "<!NOTATION ");
1567 xmlBufferWriteCHAR(buf, nota->name);
1568 if (nota->PublicID != NULL) {
1569 xmlBufferWriteChar(buf, " PUBLIC ");
1570 xmlBufferWriteQuotedString(buf, nota->PublicID);
1571 if (nota->SystemID != NULL) {
1572 xmlBufferWriteChar(buf, " ");
1573 xmlBufferWriteCHAR(buf, nota->SystemID);
1574 }
1575 } else {
1576 xmlBufferWriteChar(buf, " SYSTEM ");
1577 xmlBufferWriteCHAR(buf, nota->SystemID);
1578 }
1579 xmlBufferWriteChar(buf, " >\n");
1580}
1581
1582/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001583 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001584 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001585 * @table: A notation table
1586 *
1587 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001588 */
1589void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001590xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001591 int i;
1592 xmlNotationPtr cur;
1593
1594 if (table == NULL) return;
1595
1596 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001597 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001598 xmlDumpNotationDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001599 }
1600}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001601
1602/************************************************************************
1603 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001604 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001605 * *
1606 ************************************************************************/
1607/**
1608 * xmlCreateIDTable:
1609 *
1610 * create and initialize an empty id hash table.
1611 *
1612 * Returns the xmlIDTablePtr just created or NULL in case
1613 * of error.
1614 */
1615xmlIDTablePtr
1616xmlCreateIDTable(void) {
1617 xmlIDTablePtr ret;
1618
1619 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001620 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001621 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001622 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001623 (long)sizeof(xmlIDTable));
1624 return(NULL);
1625 }
1626 ret->max_ids = XML_MIN_NOTATION_TABLE;
1627 ret->nb_ids = 0;
1628 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001629 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001630 if (ret->table == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001631 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001632 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001633 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001634 return(NULL);
1635 }
1636 return(ret);
1637}
1638
1639
1640/**
1641 * xmlAddID:
1642 * @ctxt: the validation context
1643 * @doc: pointer to the document
1644 * @value: the value name
1645 * @attr: the attribute holding the ID
1646 *
1647 * Register a new id declaration
1648 *
1649 * Returns NULL if not, othervise the new xmlIDPtr
1650 */
1651xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001652xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001653 xmlAttrPtr attr) {
1654 xmlIDPtr ret, cur;
1655 xmlIDTablePtr table;
1656 int i;
1657
1658 if (doc == NULL) {
1659 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1660 return(NULL);
1661 }
1662 if (value == NULL) {
1663 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1664 return(NULL);
1665 }
1666 if (attr == NULL) {
1667 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1668 return(NULL);
1669 }
1670
1671 /*
1672 * Create the ID table if needed.
1673 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001674 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001675 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001676 doc->ids = table = xmlCreateIDTable();
Daniel Veillard991e63d1999-08-15 23:32:28 +00001677 if (table == NULL) {
1678 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1679 return(NULL);
1680 }
1681
1682 /*
1683 * Validity Check:
1684 * Search the DTD for previous declarations of the ATTLIST
1685 */
1686 for (i = 0;i < table->nb_ids;i++) {
1687 cur = table->table[i];
1688 if (!xmlStrcmp(cur->value, value)) {
1689 /*
1690 * The id is already defined in this Dtd.
1691 */
1692 VERROR(ctxt->userData, "ID %s already defined\n", value);
1693 return(NULL);
1694 }
1695 }
1696
1697 /*
1698 * Grow the table, if needed.
1699 */
1700 if (table->nb_ids >= table->max_ids) {
1701 /*
1702 * need more ids.
1703 */
1704 table->max_ids *= 2;
1705 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001706 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001707 sizeof(xmlIDPtr));
1708 if (table->table == NULL) {
1709 fprintf(stderr, "xmlAddID: out of memory\n");
1710 return(NULL);
1711 }
1712 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001713 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001714 if (ret == NULL) {
1715 fprintf(stderr, "xmlAddID: out of memory\n");
1716 return(NULL);
1717 }
1718 table->table[table->nb_ids] = ret;
1719
1720 /*
1721 * fill the structure.
1722 */
1723 ret->value = xmlStrdup(value);
1724 ret->attr = attr;
1725 table->nb_ids++;
1726
1727 return(ret);
1728}
1729
1730/**
1731 * xmlFreeID:
1732 * @not: A id
1733 *
1734 * Deallocate the memory used by an id definition
1735 */
1736void
1737xmlFreeID(xmlIDPtr id) {
1738 if (id == NULL) return;
1739 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001740 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001741 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001742 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001743}
1744
1745/**
1746 * xmlFreeIDTable:
1747 * @table: An id table
1748 *
1749 * Deallocate the memory used by an ID hash table.
1750 */
1751void
1752xmlFreeIDTable(xmlIDTablePtr table) {
1753 int i;
1754
1755 if (table == NULL) return;
1756
1757 for (i = 0;i < table->nb_ids;i++) {
1758 xmlFreeID(table->table[i]);
1759 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001760 xmlFree(table->table);
1761 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001762}
1763
1764/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001765 * xmlIsID:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001766 * @doc: the document
1767 * @elem: the element carrying the attribute
1768 * @attr: the attribute
1769 *
1770 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1771 * then this is simple, otherwise we use an heuristic: name ID (upper
1772 * or lowercase).
1773 *
1774 * Returns 0 or 1 depending on the lookup result
1775 */
1776int
1777xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00001778 if (doc == NULL) return(0);
1779 if (attr == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001780 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1781 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1782 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1783 (attr->name[2] == 0)) return(1);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001784 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1785 if ((!xmlStrcmp(BAD_CAST "id", attr->name)) ||
1786 (!xmlStrcmp(BAD_CAST "name", attr->name)))
1787 return(1);
1788 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001789 } else {
1790 xmlAttributePtr attrDecl;
1791
Daniel Veillard71b656e2000-01-05 14:46:17 +00001792 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001793 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1794 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1795 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1796 attr->name);
1797
Daniel Veillardcf461992000-03-14 18:30:20 +00001798 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001799 return(1);
1800 }
1801 return(0);
1802}
1803
Daniel Veillardb96e6431999-08-29 21:02:19 +00001804/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001805 * xmlRemoveID
1806 * @doc: the document
1807 * @attr: the attribute
1808 *
1809 * Remove the given attribute from the ID table maintained internally.
1810 *
1811 * Returns -1 if the lookup failed and 0 otherwise
1812 */
1813int
1814xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1815 xmlIDPtr cur;
1816 xmlIDTablePtr table;
1817 int i;
1818
1819 if (doc == NULL) return(-1);
1820 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001821 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001822 if (table == NULL)
1823 return(-1);
1824
1825 /*
1826 * Search the ID list.
1827 */
1828 for (i = 0;i < table->nb_ids;i++) {
1829 cur = table->table[i];
1830 if (cur->attr == attr) {
1831 table->nb_ids--;
1832 memmove(&table->table[i], &table->table[i+1],
1833 (table->nb_ids - i) * sizeof(xmlIDPtr));
1834 return(0);
1835 }
1836 }
1837 return(-1);
1838}
1839
1840/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001841 * xmlGetID:
1842 * @doc: pointer to the document
1843 * @ID: the ID value
1844 *
1845 * Search the attribute declaring the given ID
1846 *
1847 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1848 */
1849xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001850xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001851 xmlIDPtr cur;
1852 xmlIDTablePtr table;
1853 int i;
1854
1855 if (doc == NULL) {
1856 fprintf(stderr, "xmlGetID: doc == NULL\n");
1857 return(NULL);
1858 }
1859
1860 if (ID == NULL) {
1861 fprintf(stderr, "xmlGetID: ID == NULL\n");
1862 return(NULL);
1863 }
1864
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001865 table = (xmlIDTablePtr) doc->ids;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001866 if (table == NULL)
1867 return(NULL);
1868
1869 /*
1870 * Search the ID list.
1871 */
1872 for (i = 0;i < table->nb_ids;i++) {
1873 cur = table->table[i];
1874 if (!xmlStrcmp(cur->value, ID)) {
1875 return(cur->attr);
1876 }
1877 }
1878 return(NULL);
1879}
1880
Daniel Veillard991e63d1999-08-15 23:32:28 +00001881/************************************************************************
1882 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001883 * Refs *
1884 * *
1885 ************************************************************************/
1886/**
1887 * xmlCreateRefTable:
1888 *
1889 * create and initialize an empty ref hash table.
1890 *
1891 * Returns the xmlRefTablePtr just created or NULL in case
1892 * of error.
1893 */
1894xmlRefTablePtr
1895xmlCreateRefTable(void) {
1896 xmlRefTablePtr ret;
1897
1898 ret = (xmlRefTablePtr)
1899 xmlMalloc(sizeof(xmlRefTable));
1900 if (ret == NULL) {
1901 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1902 (long)sizeof(xmlRefTable));
1903 return(NULL);
1904 }
1905 ret->max_refs = XML_MIN_NOTATION_TABLE;
1906 ret->nb_refs = 0;
1907 ret->table = (xmlRefPtr *)
1908 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
Daniel Veillard87b95392000-08-12 21:12:04 +00001909 if (ret->table == NULL) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001910 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1911 ret->max_refs * (long)sizeof(xmlRef));
1912 xmlFree(ret);
1913 return(NULL);
1914 }
1915 return(ret);
1916}
1917
1918
1919/**
1920 * xmlAddRef:
1921 * @ctxt: the validation context
1922 * @doc: pointer to the document
1923 * @value: the value name
1924 * @attr: the attribute holding the Ref
1925 *
1926 * Register a new ref declaration
1927 *
1928 * Returns NULL if not, othervise the new xmlRefPtr
1929 */
1930xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001931xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001932 xmlAttrPtr attr) {
1933 xmlRefPtr ret;
1934 xmlRefTablePtr table;
1935
1936 if (doc == NULL) {
1937 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1938 return(NULL);
1939 }
1940 if (value == NULL) {
1941 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1942 return(NULL);
1943 }
1944 if (attr == NULL) {
1945 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1946 return(NULL);
1947 }
1948
1949 /*
1950 * Create the Ref table if needed.
1951 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001952 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001953 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001954 doc->refs = table = xmlCreateRefTable();
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001955 if (table == NULL) {
1956 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1957 return(NULL);
1958 }
1959
1960 /*
1961 * Grow the table, if needed.
1962 */
1963 if (table->nb_refs >= table->max_refs) {
1964 /*
1965 * need more refs.
1966 */
1967 table->max_refs *= 2;
1968 table->table = (xmlRefPtr *)
1969 xmlRealloc(table->table, table->max_refs *
1970 sizeof(xmlRefPtr));
1971 if (table->table == NULL) {
1972 fprintf(stderr, "xmlAddRef: out of memory\n");
1973 return(NULL);
1974 }
1975 }
1976 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1977 if (ret == NULL) {
1978 fprintf(stderr, "xmlAddRef: out of memory\n");
1979 return(NULL);
1980 }
1981 table->table[table->nb_refs] = ret;
1982
1983 /*
1984 * fill the structure.
1985 */
1986 ret->value = xmlStrdup(value);
1987 ret->attr = attr;
1988 table->nb_refs++;
1989
1990 return(ret);
1991}
1992
1993/**
1994 * xmlFreeRef:
1995 * @not: A ref
1996 *
1997 * Deallocate the memory used by an ref definition
1998 */
1999void
2000xmlFreeRef(xmlRefPtr ref) {
2001 if (ref == NULL) return;
2002 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002003 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002004 memset(ref, -1, sizeof(xmlRef));
2005 xmlFree(ref);
2006}
2007
2008/**
2009 * xmlFreeRefTable:
2010 * @table: An ref table
2011 *
2012 * Deallocate the memory used by an Ref hash table.
2013 */
2014void
2015xmlFreeRefTable(xmlRefTablePtr table) {
2016 int i;
2017
2018 if (table == NULL) return;
2019
2020 for (i = 0;i < table->nb_refs;i++) {
2021 xmlFreeRef(table->table[i]);
2022 }
2023 xmlFree(table->table);
2024 xmlFree(table);
2025}
2026
2027/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002028 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002029 * @doc: the document
2030 * @elem: the element carrying the attribute
2031 * @attr: the attribute
2032 *
2033 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
2034 * then this is simple, otherwise we use an heuristic: name Ref (upper
2035 * or lowercase).
2036 *
2037 * Returns 0 or 1 depending on the lookup result
2038 */
2039int
2040xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2041 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2042 return(0);
2043 /*******************
2044 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
2045 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
2046 (attr->name[2] == 0)) return(1);
2047 *******************/
Daniel Veillardd83eb822000-06-30 18:39:56 +00002048 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2049 /* TODO @@@ */
2050 return(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002051 } else {
2052 xmlAttributePtr attrDecl;
2053
2054 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2055 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2056 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2057 attr->name);
2058
Daniel Veillardcf461992000-03-14 18:30:20 +00002059 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002060 return(1);
2061 }
2062 return(0);
2063}
2064
2065/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002066 * xmlRemoveRef
2067 * @doc: the document
2068 * @attr: the attribute
2069 *
2070 * Remove the given attribute from the Ref table maintained internally.
2071 *
2072 * Returns -1 if the lookup failed and 0 otherwise
2073 */
2074int
2075xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2076 xmlRefPtr cur;
2077 xmlRefTablePtr table;
2078 int i;
2079
2080 if (doc == NULL) return(-1);
2081 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002082 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard71b656e2000-01-05 14:46:17 +00002083 if (table == NULL)
2084 return(-1);
2085
2086 /*
2087 * Search the Ref list.
2088 */
2089 for (i = 0;i < table->nb_refs;i++) {
2090 cur = table->table[i];
2091 if (cur->attr == attr) {
2092 table->nb_refs--;
2093 memmove(&table->table[i], &table->table[i+1],
2094 (table->nb_refs - i) * sizeof(xmlRefPtr));
2095 return(0);
2096 }
2097 }
2098 return(-1);
2099}
2100
2101/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002102 * xmlGetRef:
2103 * @doc: pointer to the document
2104 * @Ref: the Ref value
2105 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00002106 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002107 *
2108 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
2109 */
2110xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002111xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002112 xmlRefPtr cur;
2113 xmlRefTablePtr table;
2114 int i;
2115
2116 if (doc == NULL) {
2117 fprintf(stderr, "xmlGetRef: doc == NULL\n");
2118 return(NULL);
2119 }
2120
2121 if (Ref == NULL) {
2122 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
2123 return(NULL);
2124 }
2125
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002126 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002127 if (table == NULL)
2128 return(NULL);
2129
2130 /*
2131 * Search the Ref list.
2132 */
2133 for (i = 0;i < table->nb_refs;i++) {
2134 cur = table->table[i];
2135 if (!xmlStrcmp(cur->value, Ref)) {
2136 return(cur->attr);
2137 }
2138 }
2139 return(NULL);
2140}
2141
2142/************************************************************************
2143 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002144 * Routines for validity checking *
2145 * *
2146 ************************************************************************/
2147
2148/**
2149 * xmlGetDtdElementDesc:
2150 * @dtd: a pointer to the DtD to search
2151 * @name: the element name
2152 *
2153 * Search the Dtd for the description of this element
2154 *
2155 * returns the xmlElementPtr if found or NULL
2156 */
2157
2158xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002159xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002160 xmlElementTablePtr table;
2161 xmlElementPtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002162 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002163 int i;
2164
2165 if (dtd == NULL) return(NULL);
2166 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002167 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002168
2169 for (i = 0;i < table->nb_elements;i++) {
2170 cur = table->table[i];
2171 if (!xmlStrcmp(cur->name, name))
2172 return(cur);
2173 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002174
2175 /*
2176 * Specific case if name is a QName.
2177 */
2178 uqname = xmlSplitQName2(name, &prefix);
2179 if (uqname == NULL) return(NULL);
2180
2181 for (i = 0;i < table->nb_elements;i++) {
2182 cur = table->table[i];
2183 if ((!xmlStrcmp(cur->name, uqname)) &&
2184 ((prefix == cur->prefix) ||
2185 ((prefix != NULL) && (cur->prefix != NULL) &&
2186 (!xmlStrcmp(cur->prefix, prefix))))) {
2187 if (prefix != NULL) xmlFree(prefix);
2188 if (uqname != NULL) xmlFree(uqname);
2189 return(cur);
2190 }
2191 }
2192 if (prefix != NULL) xmlFree(prefix);
2193 if (uqname != NULL) xmlFree(uqname);
2194 return(NULL);
2195}
2196
2197/**
2198 * xmlGetDtdQElementDesc:
2199 * @dtd: a pointer to the DtD to search
2200 * @name: the element name
2201 * @prefix: the element namespace prefix
2202 *
2203 * Search the Dtd for the description of this element
2204 *
2205 * returns the xmlElementPtr if found or NULL
2206 */
2207
2208xmlElementPtr
2209xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2210 const xmlChar *prefix) {
2211 xmlElementTablePtr table;
2212 xmlElementPtr cur;
2213 int i;
2214
2215 if (dtd == NULL) return(NULL);
2216 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002217 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardbe803962000-06-28 23:40:59 +00002218
2219 for (i = 0;i < table->nb_elements;i++) {
2220 cur = table->table[i];
2221 if (!xmlStrcmp(cur->name, name) &&
2222 ((prefix == cur->prefix) ||
2223 ((prefix != NULL) && (cur->prefix != NULL) &&
2224 (!xmlStrcmp(cur->prefix, prefix)))))
2225 return(cur);
2226 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002227 return(NULL);
2228}
2229
2230/**
2231 * xmlGetDtdAttrDesc:
2232 * @dtd: a pointer to the DtD to search
2233 * @elem: the element name
2234 * @name: the attribute name
2235 *
2236 * Search the Dtd for the description of this attribute on
2237 * this element.
2238 *
2239 * returns the xmlAttributePtr if found or NULL
2240 */
2241
2242xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002243xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002244 xmlAttributeTablePtr table;
2245 xmlAttributePtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002246 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002247 int i;
2248
2249 if (dtd == NULL) return(NULL);
2250 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002251 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002252
2253 for (i = 0;i < table->nb_attributes;i++) {
2254 cur = table->table[i];
2255 if ((!xmlStrcmp(cur->name, name)) &&
2256 (!xmlStrcmp(cur->elem, elem)))
2257 return(cur);
2258 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002259
2260 /*
2261 * Specific case if name is a QName.
2262 */
2263 uqname = xmlSplitQName2(name, &prefix);
2264 if (uqname == NULL) return(NULL);
2265
2266 for (i = 0;i < table->nb_attributes;i++) {
2267 cur = table->table[i];
2268 if ((!xmlStrcmp(cur->name, uqname)) &&
2269 (!xmlStrcmp(cur->elem, elem)) &&
2270 ((prefix == cur->prefix) ||
2271 ((prefix != NULL) && (cur->prefix != NULL) &&
2272 (!xmlStrcmp(cur->prefix, prefix))))) {
2273 if (prefix != NULL) xmlFree(prefix);
2274 if (uqname != NULL) xmlFree(uqname);
2275 return(cur);
2276 }
2277 }
2278 if (prefix != NULL) xmlFree(prefix);
2279 if (uqname != NULL) xmlFree(uqname);
2280 return(NULL);
2281}
2282
2283/**
2284 * xmlGetDtdQAttrDesc:
2285 * @dtd: a pointer to the DtD to search
2286 * @elem: the element name
2287 * @name: the attribute name
2288 * @prefix: the attribute namespace prefix
2289 *
2290 * Search the Dtd for the description of this qualified attribute on
2291 * this element.
2292 *
2293 * returns the xmlAttributePtr if found or NULL
2294 */
2295
2296xmlAttributePtr
2297xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2298 const xmlChar *prefix) {
2299 xmlAttributeTablePtr table;
2300 xmlAttributePtr cur;
2301 int i;
2302
2303 if (dtd == NULL) return(NULL);
2304 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002305 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardbe803962000-06-28 23:40:59 +00002306
2307 for (i = 0;i < table->nb_attributes;i++) {
2308 cur = table->table[i];
2309 if ((!xmlStrcmp(cur->name, name)) &&
2310 (!xmlStrcmp(cur->elem, elem)) &&
2311 ((prefix == cur->prefix) ||
2312 ((prefix != NULL) && (cur->prefix != NULL) &&
2313 (!xmlStrcmp(cur->prefix, prefix)))))
2314 return(cur);
2315 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002316 return(NULL);
2317}
2318
2319/**
2320 * xmlGetDtdNotationDesc:
2321 * @dtd: a pointer to the DtD to search
2322 * @name: the notation name
2323 *
2324 * Search the Dtd for the description of this notation
2325 *
2326 * returns the xmlNotationPtr if found or NULL
2327 */
2328
2329xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002330xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002331 xmlNotationTablePtr table;
2332 xmlNotationPtr cur;
2333 int i;
2334
2335 if (dtd == NULL) return(NULL);
2336 if (dtd->notations == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002337 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002338
2339 for (i = 0;i < table->nb_notations;i++) {
2340 cur = table->table[i];
2341 if (!xmlStrcmp(cur->name, name))
2342 return(cur);
2343 }
2344 return(NULL);
2345}
2346
2347/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002348 * xmlValidateNotationUse:
2349 * @ctxt: the validation context
2350 * @doc: the document
2351 * @notationName: the notation name to check
2352 *
2353 * Validate that the given mame match a notation declaration.
2354 * - [ VC: Notation Declared ]
2355 *
2356 * returns 1 if valid or 0 otherwise
2357 */
2358
2359int
2360xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002361 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002362 xmlNotationPtr notaDecl;
2363 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2364
2365 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2366 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2367 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2368
2369 if (notaDecl == NULL) {
2370 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2371 notationName);
2372 return(0);
2373 }
2374 return(1);
2375}
2376
2377/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002378 * xmlIsMixedElement
2379 * @doc: the document
2380 * @name: the element name
2381 *
2382 * Search in the DtDs whether an element accept Mixed content (or ANY)
2383 * basically if it is supposed to accept text childs
2384 *
2385 * returns 0 if no, 1 if yes, and -1 if no element description is available
2386 */
2387
2388int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002389xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002390 xmlElementPtr elemDecl;
2391
2392 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2393
2394 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2395 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2396 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2397 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002398 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002399 case XML_ELEMENT_TYPE_ELEMENT:
2400 return(0);
2401 case XML_ELEMENT_TYPE_EMPTY:
2402 /*
2403 * return 1 for EMPTY since we want VC error to pop up
2404 * on <empty> </empty> for example
2405 */
2406 case XML_ELEMENT_TYPE_ANY:
2407 case XML_ELEMENT_TYPE_MIXED:
2408 return(1);
2409 }
2410 return(1);
2411}
2412
2413/**
2414 * xmlValidateNameValue:
2415 * @value: an Name value
2416 *
2417 * Validate that the given value match Name production
2418 *
2419 * returns 1 if valid or 0 otherwise
2420 */
2421
2422int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002423xmlValidateNameValue(const xmlChar *value) {
2424 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002425
2426 if (value == NULL) return(0);
2427 cur = value;
2428
2429 if (!IS_LETTER(*cur) && (*cur != '_') &&
2430 (*cur != ':')) {
2431 return(0);
2432 }
2433
2434 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2435 (*cur == '.') || (*cur == '-') ||
2436 (*cur == '_') || (*cur == ':') ||
2437 (IS_COMBINING(*cur)) ||
2438 (IS_EXTENDER(*cur)))
2439 cur++;
2440
2441 if (*cur != 0) return(0);
2442
2443 return(1);
2444}
2445
2446/**
2447 * xmlValidateNamesValue:
2448 * @value: an Names value
2449 *
2450 * Validate that the given value match Names production
2451 *
2452 * returns 1 if valid or 0 otherwise
2453 */
2454
2455int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002456xmlValidateNamesValue(const xmlChar *value) {
2457 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002458
2459 if (value == NULL) return(0);
2460 cur = value;
2461
2462 if (!IS_LETTER(*cur) && (*cur != '_') &&
2463 (*cur != ':')) {
2464 return(0);
2465 }
2466
2467 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2468 (*cur == '.') || (*cur == '-') ||
2469 (*cur == '_') || (*cur == ':') ||
2470 (IS_COMBINING(*cur)) ||
2471 (IS_EXTENDER(*cur)))
2472 cur++;
2473
2474 while (IS_BLANK(*cur)) {
2475 while (IS_BLANK(*cur)) cur++;
2476
2477 if (!IS_LETTER(*cur) && (*cur != '_') &&
2478 (*cur != ':')) {
2479 return(0);
2480 }
2481
2482 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2483 (*cur == '.') || (*cur == '-') ||
2484 (*cur == '_') || (*cur == ':') ||
2485 (IS_COMBINING(*cur)) ||
2486 (IS_EXTENDER(*cur)))
2487 cur++;
2488 }
2489
2490 if (*cur != 0) return(0);
2491
2492 return(1);
2493}
2494
2495/**
2496 * xmlValidateNmtokenValue:
2497 * @value: an Mntoken value
2498 *
2499 * Validate that the given value match Nmtoken production
2500 *
2501 * [ VC: Name Token ]
2502 *
2503 * returns 1 if valid or 0 otherwise
2504 */
2505
2506int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002507xmlValidateNmtokenValue(const xmlChar *value) {
2508 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002509
2510 if (value == NULL) return(0);
2511 cur = value;
2512
2513 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2514 (*cur != '.') && (*cur != '-') &&
2515 (*cur != '_') && (*cur != ':') &&
2516 (!IS_COMBINING(*cur)) &&
2517 (!IS_EXTENDER(*cur)))
2518 return(0);
2519
2520 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2521 (*cur == '.') || (*cur == '-') ||
2522 (*cur == '_') || (*cur == ':') ||
2523 (IS_COMBINING(*cur)) ||
2524 (IS_EXTENDER(*cur)))
2525 cur++;
2526
2527 if (*cur != 0) return(0);
2528
2529 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002530}
2531
2532/**
2533 * xmlValidateNmtokensValue:
2534 * @value: an Mntokens value
2535 *
2536 * Validate that the given value match Nmtokens production
2537 *
2538 * [ VC: Name Token ]
2539 *
2540 * returns 1 if valid or 0 otherwise
2541 */
2542
2543int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002544xmlValidateNmtokensValue(const xmlChar *value) {
2545 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002546
2547 if (value == NULL) return(0);
2548 cur = value;
2549
Daniel Veillardcf461992000-03-14 18:30:20 +00002550 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002551 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2552 (*cur != '.') && (*cur != '-') &&
2553 (*cur != '_') && (*cur != ':') &&
2554 (!IS_COMBINING(*cur)) &&
2555 (!IS_EXTENDER(*cur)))
2556 return(0);
2557
2558 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2559 (*cur == '.') || (*cur == '-') ||
2560 (*cur == '_') || (*cur == ':') ||
2561 (IS_COMBINING(*cur)) ||
2562 (IS_EXTENDER(*cur)))
2563 cur++;
2564
2565 while (IS_BLANK(*cur)) {
2566 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002567 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002568
2569 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2570 (*cur != '.') && (*cur != '-') &&
2571 (*cur != '_') && (*cur != ':') &&
2572 (!IS_COMBINING(*cur)) &&
2573 (!IS_EXTENDER(*cur)))
2574 return(0);
2575
2576 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2577 (*cur == '.') || (*cur == '-') ||
2578 (*cur == '_') || (*cur == ':') ||
2579 (IS_COMBINING(*cur)) ||
2580 (IS_EXTENDER(*cur)))
2581 cur++;
2582 }
2583
2584 if (*cur != 0) return(0);
2585
2586 return(1);
2587}
2588
2589/**
2590 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002591 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002592 * @doc: a document instance
2593 * @nota: a notation definition
2594 *
2595 * Try to validate a single notation definition
2596 * basically it does the following checks as described by the
2597 * XML-1.0 recommendation:
2598 * - it seems that no validity constraing exist on notation declarations
2599 * But this function get called anyway ...
2600 *
2601 * returns 1 if valid or 0 otherwise
2602 */
2603
2604int
2605xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2606 xmlNotationPtr nota) {
2607 int ret = 1;
2608
2609 return(ret);
2610}
2611
2612/**
2613 * xmlValidateAttributeValue:
2614 * @type: an attribute type
2615 * @value: an attribute value
2616 *
2617 * Validate that the given attribute value match the proper production
2618 *
2619 * [ VC: ID ]
2620 * Values of type ID must match the Name production....
2621 *
2622 * [ VC: IDREF ]
2623 * Values of type IDREF must match the Name production, and values
2624 * of type IDREFS must match Names ...
2625 *
2626 * [ VC: Entity Name ]
2627 * Values of type ENTITY must match the Name production, values
2628 * of type ENTITIES must match Names ...
2629 *
2630 * [ VC: Name Token ]
2631 * Values of type NMTOKEN must match the Nmtoken production; values
2632 * of type NMTOKENS must match Nmtokens.
2633 *
2634 * returns 1 if valid or 0 otherwise
2635 */
2636
2637int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002638xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002639 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002640 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002641 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002642 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002643 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002644 case XML_ATTRIBUTE_IDREF:
2645 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002646 case XML_ATTRIBUTE_NOTATION:
2647 return(xmlValidateNameValue(value));
2648 case XML_ATTRIBUTE_NMTOKENS:
2649 case XML_ATTRIBUTE_ENUMERATION:
2650 return(xmlValidateNmtokensValue(value));
2651 case XML_ATTRIBUTE_NMTOKEN:
2652 return(xmlValidateNmtokenValue(value));
2653 case XML_ATTRIBUTE_CDATA:
2654 break;
2655 }
2656 return(1);
2657}
2658
2659/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002660 * xmlValidateAttributeValue2:
2661 * @ctxt: the validation context
2662 * @doc: the document
2663 * @name: the attribute name (used for error reporting only)
2664 * @type: the attribute type
2665 * @value: the attribute value
2666 *
2667 * Validate that the given attribute value match a given type.
2668 * This typically cannot be done before having finished parsing
2669 * the subsets.
2670 *
2671 * [ VC: IDREF ]
2672 * Values of type IDREF must match one of the declared IDs
2673 * Values of type IDREFS must match a sequence of the declared IDs
2674 * each Name must match the value of an ID attribute on some element
2675 * in the XML document; i.e. IDREF values must match the value of
2676 * some ID attribute
2677 *
2678 * [ VC: Entity Name ]
2679 * Values of type ENTITY must match one declared entity
2680 * Values of type ENTITIES must match a sequence of declared entities
2681 *
2682 * [ VC: Notation Attributes ]
2683 * all notation names in the declaration must be declared.
2684 *
2685 * returns 1 if valid or 0 otherwise
2686 */
2687
2688int
2689xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2690 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2691 int ret = 1;
2692 switch (type) {
2693 case XML_ATTRIBUTE_IDREFS:
2694 case XML_ATTRIBUTE_IDREF:
2695 case XML_ATTRIBUTE_ID:
2696 case XML_ATTRIBUTE_NMTOKENS:
2697 case XML_ATTRIBUTE_ENUMERATION:
2698 case XML_ATTRIBUTE_NMTOKEN:
2699 case XML_ATTRIBUTE_CDATA:
2700 break;
2701 case XML_ATTRIBUTE_ENTITY: {
2702 xmlEntityPtr ent;
2703
2704 ent = xmlGetDocEntity(doc, value);
2705 if (ent == NULL) {
2706 VERROR(ctxt->userData,
2707 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2708 name, value);
2709 ret = 0;
2710 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2711 VERROR(ctxt->userData,
2712 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2713 name, value);
2714 ret = 0;
2715 }
2716 break;
2717 }
2718 case XML_ATTRIBUTE_ENTITIES: {
2719 xmlChar *dup, *nam = NULL, *cur, save;
2720 xmlEntityPtr ent;
2721
2722 dup = xmlStrdup(value);
2723 if (dup == NULL)
2724 return(0);
2725 cur = dup;
2726 while (*cur != 0) {
2727 nam = cur;
2728 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2729 save = *cur;
2730 *cur = 0;
2731 ent = xmlGetDocEntity(doc, nam);
2732 if (ent == NULL) {
2733 VERROR(ctxt->userData,
2734 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2735 name, nam);
2736 ret = 0;
2737 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2738 VERROR(ctxt->userData,
2739 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2740 name, nam);
2741 ret = 0;
2742 }
2743 if (save == 0)
2744 break;
2745 *cur = save;
2746 while (IS_BLANK(*cur)) cur++;
2747 }
2748 xmlFree(dup);
2749 break;
2750 }
2751 case XML_ATTRIBUTE_NOTATION: {
2752 xmlNotationPtr nota;
2753
2754 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2755 if ((nota == NULL) && (doc->extSubset != NULL))
2756 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2757
2758 if (nota == NULL) {
2759 VERROR(ctxt->userData,
2760 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2761 name, value);
2762 ret = 0;
2763 }
2764 break;
2765 }
2766 }
2767 return(ret);
2768}
2769
2770/**
2771 * xmlValidNormalizeAttributeValue:
2772 * @doc: the document
2773 * @elem: the parent
2774 * @name: the attribute name
2775 * @value: the attribute value
2776 *
2777 * Does the validation related extra step of the normalization of attribute
2778 * values:
2779 *
2780 * If the declared value is not CDATA, then the XML processor must further
2781 * process the normalized attribute value by discarding any leading and
2782 * trailing space (#x20) characters, and by replacing sequences of space
2783 * (#x20) characters by single space (#x20) character.
2784 *
2785 * returns a new normalized string if normalization is needed, NULL otherwise
2786 * the caller must free the returned value.
2787 */
2788
2789xmlChar *
2790xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2791 const xmlChar *name, const xmlChar *value) {
2792 xmlChar *ret, *dst;
2793 const xmlChar *src;
Daniel Veillardbe803962000-06-28 23:40:59 +00002794 xmlAttributePtr attrDecl = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002795
2796 if (doc == NULL) return(NULL);
2797 if (elem == NULL) return(NULL);
2798 if (name == NULL) return(NULL);
2799 if (value == NULL) return(NULL);
2800
Daniel Veillardbe803962000-06-28 23:40:59 +00002801 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2802 xmlChar qname[500];
2803#ifdef HAVE_SNPRINTF
2804 snprintf((char *) qname, sizeof(qname), "%s:%s",
2805 elem->ns->prefix, elem->name);
2806#else
2807 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
2808#endif
2809 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2810 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2811 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2812 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002813 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2814 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2815 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2816
2817 if (attrDecl == NULL)
2818 return(NULL);
2819 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2820 return(NULL);
2821
2822 ret = xmlStrdup(value);
2823 if (ret == NULL)
2824 return(NULL);
2825 src = value;
2826 dst = ret;
2827 while (*src == 0x20) src++;
2828 while (*src != 0) {
2829 if (*src == 0x20) {
2830 while (*src == 0x20) src++;
2831 if (*src != 0)
2832 *dst++ = 0x20;
2833 } else {
2834 *dst++ = *src++;
2835 }
2836 }
2837 *dst = 0;
2838 return(ret);
2839}
2840
2841/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002842 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002843 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002844 * @doc: a document instance
2845 * @attr: an attribute definition
2846 *
2847 * Try to validate a single attribute definition
2848 * basically it does the following checks as described by the
2849 * XML-1.0 recommendation:
2850 * - [ VC: Attribute Default Legal ]
2851 * - [ VC: Enumeration ]
2852 * - [ VC: ID Attribute Default ]
2853 *
2854 * The ID/IDREF uniqueness and matching are done separately
2855 *
2856 * returns 1 if valid or 0 otherwise
2857 */
2858
2859int
2860xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2861 xmlAttributePtr attr) {
2862 int ret = 1;
2863 int val;
2864 CHECK_DTD;
2865 if(attr == NULL) return(1);
2866
2867 /* Attribute Default Legal */
2868 /* Enumeration */
2869 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002870 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002871 if (val == 0) {
2872 VERROR(ctxt->userData,
2873 "Syntax of default value for attribute %s on %s is not valid\n",
2874 attr->name, attr->elem);
2875 }
2876 ret &= val;
2877 }
2878
2879 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002880 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002881 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2882 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2883 VERROR(ctxt->userData,
2884 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2885 attr->name, attr->elem);
2886 ret = 0;
2887 }
2888
Daniel Veillardb96e6431999-08-29 21:02:19 +00002889 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002890 if (attr->atype == XML_ATTRIBUTE_ID) {
2891 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002892
2893 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002894 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002895 attr->elem);
2896 if (elem != NULL) {
2897 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002898 } else {
2899 xmlAttributeTablePtr table;
2900 int i;
2901
2902 /*
2903 * The attribute may be declared in the internal subset and the
2904 * element in the external subset.
2905 */
2906 nbId = 0;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002907 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00002908 if (table != NULL) {
2909 for (i = 0;i < table->nb_attributes;i++) {
2910 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2911 (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2912 nbId++;
2913 }
2914 }
2915 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002916 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002917 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002918 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002919 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2920 attr->elem, nbId, attr->name);
2921 } else if (doc->extSubset != NULL) {
2922 int extId = 0;
2923 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2924 if (elem != NULL) {
2925 extId = xmlScanIDAttributeDecl(NULL, elem);
2926 }
2927 if (extId > 1) {
2928 VERROR(ctxt->userData,
2929 "Element %s has %d ID attribute defined in the external subset : %s\n",
2930 attr->elem, extId, attr->name);
2931 } else if (extId + nbId > 1) {
2932 VERROR(ctxt->userData,
2933"Element %s has ID attributes defined in the internal and external subset : %s\n",
2934 attr->elem, attr->name);
2935 }
2936 }
2937 }
2938
2939 /* Validity Constraint: Enumeration */
2940 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2941 xmlEnumerationPtr tree = attr->tree;
2942 while (tree != NULL) {
2943 if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2944 tree = tree->next;
2945 }
2946 if (tree == NULL) {
2947 VERROR(ctxt->userData,
2948"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2949 attr->defaultValue, attr->name, attr->elem);
2950 ret = 0;
2951 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002952 }
2953
2954 return(ret);
2955}
2956
2957/**
2958 * xmlValidateElementDecl:
2959 * @ctxt: the validation context
2960 * @doc: a document instance
2961 * @elem: an element definition
2962 *
2963 * Try to validate a single element definition
2964 * basically it does the following checks as described by the
2965 * XML-1.0 recommendation:
2966 * - [ VC: One ID per Element Type ]
2967 * - [ VC: No Duplicate Types ]
2968 * - [ VC: Unique Element Type Declaration ]
2969 *
2970 * returns 1 if valid or 0 otherwise
2971 */
2972
2973int
2974xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2975 xmlElementPtr elem) {
2976 int ret = 1;
2977 xmlElementPtr tst;
2978
2979 CHECK_DTD;
2980
2981 if (elem == NULL) return(1);
2982
2983 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00002984 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002985 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002986 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002987
2988 cur = elem->content;
2989 while (cur != NULL) {
2990 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2991 if (cur->c1 == NULL) break;
2992 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2993 name = cur->c1->name;
2994 next = cur->c2;
2995 while (next != NULL) {
2996 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2997 if (!xmlStrcmp(next->name, name)) {
2998 VERROR(ctxt->userData,
2999 "Definition of %s has duplicate references of %s\n",
3000 elem->name, name);
3001 ret = 0;
3002 }
3003 break;
3004 }
3005 if (next->c1 == NULL) break;
3006 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
3007 if (!xmlStrcmp(next->c1->name, name)) {
3008 VERROR(ctxt->userData,
3009 "Definition of %s has duplicate references of %s\n",
3010 elem->name, name);
3011 ret = 0;
3012 }
3013 next = next->c2;
3014 }
3015 }
3016 cur = cur->c2;
3017 }
3018 }
3019
3020 /* VC: Unique Element Type Declaration */
3021 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3022 if ((tst != NULL ) && (tst != elem)) {
3023 VERROR(ctxt->userData, "Redefinition of element %s\n",
3024 elem->name);
3025 ret = 0;
3026 }
3027 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3028 if ((tst != NULL ) && (tst != elem)) {
3029 VERROR(ctxt->userData, "Redefinition of element %s\n",
3030 elem->name);
3031 ret = 0;
3032 }
3033
3034 /* One ID per Element Type */
3035 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3036 ret = 0;
3037 }
3038 return(ret);
3039}
3040
3041/**
3042 * xmlValidateOneAttribute:
3043 * @ctxt: the validation context
3044 * @doc: a document instance
3045 * @elem: an element instance
3046 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00003047 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003048 *
3049 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00003050 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00003051 * XML-1.0 recommendation:
3052 * - [ VC: Attribute Value Type ]
3053 * - [ VC: Fixed Attribute Default ]
3054 * - [ VC: Entity Name ]
3055 * - [ VC: Name Token ]
3056 * - [ VC: ID ]
3057 * - [ VC: IDREF ]
3058 * - [ VC: Entity Name ]
3059 * - [ VC: Notation Attributes ]
3060 *
3061 * The ID/IDREF uniqueness and matching are done separately
3062 *
3063 * returns 1 if valid or 0 otherwise
3064 */
3065
3066int
3067xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003068 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003069 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00003070 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003071 int val;
3072 int ret = 1;
3073
3074 CHECK_DTD;
3075 if ((elem == NULL) || (elem->name == NULL)) return(0);
3076 if ((attr == NULL) || (attr->name == NULL)) return(0);
3077
Daniel Veillardbe803962000-06-28 23:40:59 +00003078 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3079 xmlChar qname[500];
3080#ifdef HAVE_SNPRINTF
3081 snprintf((char *) qname, sizeof(qname), "%s:%s",
3082 elem->ns->prefix, elem->name);
3083#else
3084 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
3085#endif
3086 if (attr->ns != NULL) {
3087 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3088 attr->name, attr->ns->prefix);
3089 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3090 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3091 attr->name, attr->ns->prefix);
3092 } else {
3093 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3094 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3095 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3096 qname, attr->name);
3097 }
3098 }
3099 if (attrDecl == NULL) {
3100 if (attr->ns != NULL) {
3101 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3102 attr->name, attr->ns->prefix);
3103 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3104 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3105 attr->name, attr->ns->prefix);
3106 } else {
3107 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3108 elem->name, attr->name);
3109 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3110 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3111 elem->name, attr->name);
3112 }
3113 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003114
3115
3116 /* Validity Constraint: Attribute Value Type */
3117 if (attrDecl == NULL) {
3118 VERROR(ctxt->userData,
3119 "No declaration for attribute %s on element %s\n",
3120 attr->name, elem->name);
3121 return(0);
3122 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003123 attr->atype = attrDecl->atype;
3124
3125 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003126 if (val == 0) {
3127 VERROR(ctxt->userData,
3128 "Syntax of value for attribute %s on %s is not valid\n",
3129 attr->name, elem->name);
3130 ret = 0;
3131 }
3132
Daniel Veillardcf461992000-03-14 18:30:20 +00003133 /* Validity constraint: Fixed Attribute Default */
3134 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3135 if (xmlStrcmp(value, attrDecl->defaultValue)) {
3136 VERROR(ctxt->userData,
3137 "Value for attribute %s on %s is differnt from default \"%s\"\n",
3138 attr->name, elem->name, attrDecl->defaultValue);
3139 ret = 0;
3140 }
3141 }
3142
Daniel Veillardb96e6431999-08-29 21:02:19 +00003143 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00003144 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003145 xmlAddID(ctxt, doc, value, attr);
3146 }
3147
Daniel Veillardcf461992000-03-14 18:30:20 +00003148 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3149 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003150 xmlAddRef(ctxt, doc, value, attr);
3151 }
3152
Daniel Veillardb05deb71999-08-10 19:04:08 +00003153 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00003154 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003155 xmlEnumerationPtr tree = attrDecl->tree;
3156 xmlNotationPtr nota;
3157
3158 /* First check that the given NOTATION was declared */
3159 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3160 if (nota == NULL)
3161 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3162
3163 if (nota == NULL) {
3164 VERROR(ctxt->userData,
3165 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3166 value, attr->name, elem->name);
3167 ret = 0;
3168 }
3169
3170 /* Second, verify that it's among the list */
3171 while (tree != NULL) {
3172 if (!xmlStrcmp(tree->name, value)) break;
3173 tree = tree->next;
3174 }
3175 if (tree == NULL) {
3176 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003177"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003178 value, attr->name, elem->name);
3179 ret = 0;
3180 }
3181 }
3182
3183 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00003184 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003185 xmlEnumerationPtr tree = attrDecl->tree;
3186 while (tree != NULL) {
3187 if (!xmlStrcmp(tree->name, value)) break;
3188 tree = tree->next;
3189 }
3190 if (tree == NULL) {
3191 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003192 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003193 value, attr->name, elem->name);
3194 ret = 0;
3195 }
3196 }
3197
3198 /* Fixed Attribute Default */
3199 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3200 (xmlStrcmp(attrDecl->defaultValue, value))) {
3201 VERROR(ctxt->userData,
3202 "Value for attribute %s on %s must be \"%s\"\n",
3203 attr->name, elem->name, attrDecl->defaultValue);
3204 ret = 0;
3205 }
3206
Daniel Veillardcf461992000-03-14 18:30:20 +00003207 /* Extra check for the attribute value */
3208 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3209 attrDecl->atype, value);
3210
Daniel Veillardb05deb71999-08-10 19:04:08 +00003211 return(ret);
3212}
3213
3214int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3215 xmlElementContentPtr cont);
3216
3217/**
3218 * xmlValidateElementTypeExpr:
3219 * @ctxt: the validation context
3220 * @child: pointer to the child list
3221 * @cont: pointer to the content declaration
3222 *
3223 * Try to validate the content of an element of type element
3224 * but don't handle the occurence factor
3225 *
3226 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3227 * also update child value in-situ.
3228 */
3229
3230int
3231xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3232 xmlElementContentPtr cont) {
3233 xmlNodePtr cur;
3234 int ret = 1;
3235
3236 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003237 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003238 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003239 if ((*child)->type == XML_ENTITY_REF_NODE) {
3240 /*
3241 * If there is an entity declared an it's not empty
3242 * Push the current node on the stack and process with the
3243 * entity content.
3244 */
3245 if (((*child)->children != NULL) &&
3246 ((*child)->children->children != NULL)) {
3247 nodeVPush(ctxt, *child);
3248 *child = (*child)->children->children;
3249 } else
3250 *child = (*child)->next;
3251 continue;
3252 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003253 if ((*child)->type == XML_PI_NODE) {
3254 *child = (*child)->next;
3255 continue;
3256 }
3257 if ((*child)->type == XML_COMMENT_NODE) {
3258 *child = (*child)->next;
3259 continue;
3260 }
3261 else if ((*child)->type != XML_ELEMENT_NODE) {
3262 return(-1);
3263 }
3264 break;
3265 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003266 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003267 switch (cont->type) {
3268 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003269 if (*child == NULL) return(0);
3270 if ((*child)->type == XML_TEXT_NODE) return(1);
3271 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003272 case XML_ELEMENT_CONTENT_ELEMENT:
3273 if (*child == NULL) return(0);
3274 ret = (!xmlStrcmp((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003275 if (ret == 1) {
3276 while ((*child)->next == NULL) {
3277 if (((*child)->parent != NULL) &&
3278 ((*child)->parent->type == XML_ENTITY_DECL)) {
3279 *child = nodeVPop(ctxt);
3280 } else
3281 break;
3282 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003283 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003284 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003285 return(ret);
3286 case XML_ELEMENT_CONTENT_OR:
3287 cur = *child;
3288 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3289 if (ret == -1) return(-1);
3290 if (ret == 1) {
3291 return(1);
3292 }
3293 /* rollback and retry the other path */
3294 *child = cur;
3295 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3296 if (ret == -1) return(-1);
3297 if (ret == 0) {
3298 *child = cur;
3299 return(0);
3300 }
3301 return(1);
3302 case XML_ELEMENT_CONTENT_SEQ:
3303 cur = *child;
3304 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3305 if (ret == -1) return(-1);
3306 if (ret == 0) {
3307 *child = cur;
3308 return(0);
3309 }
3310 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3311 if (ret == -1) return(-1);
3312 if (ret == 0) {
3313 *child = cur;
3314 return(0);
3315 }
3316 return(1);
3317 }
3318 return(ret);
3319}
3320
3321/**
3322 * xmlValidateElementTypeElement:
3323 * @ctxt: the validation context
3324 * @child: pointer to the child list
3325 * @cont: pointer to the content declaration
3326 *
3327 * Try to validate the content of an element of type element
3328 * yeah, Yet Another Regexp Implementation, and recursive
3329 *
3330 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3331 * also update child and content values in-situ.
3332 */
3333
3334int
3335xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3336 xmlElementContentPtr cont) {
3337 xmlNodePtr cur;
3338 int ret = 1;
3339
3340 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003341
3342 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003343 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003344 if ((*child)->type == XML_ENTITY_REF_NODE) {
3345 /*
3346 * If there is an entity declared an it's not empty
3347 * Push the current node on the stack and process with the
3348 * entity content.
3349 */
3350 if (((*child)->children != NULL) &&
3351 ((*child)->children->children != NULL)) {
3352 nodeVPush(ctxt, *child);
3353 *child = (*child)->children->children;
3354 } else
3355 *child = (*child)->next;
3356 continue;
3357 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003358 if ((*child)->type == XML_PI_NODE) {
3359 *child = (*child)->next;
3360 continue;
3361 }
3362 if ((*child)->type == XML_COMMENT_NODE) {
3363 *child = (*child)->next;
3364 continue;
3365 }
3366 else if ((*child)->type != XML_ELEMENT_NODE) {
3367 return(-1);
3368 }
3369 break;
3370 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003371 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003372 cur = *child;
3373 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3374 if (ret == -1) return(-1);
3375 switch (cont->ocur) {
3376 case XML_ELEMENT_CONTENT_ONCE:
3377 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003378 /* skip ignorable elems */
3379 while ((*child != NULL) &&
3380 (((*child)->type == XML_PI_NODE) ||
3381 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003382 while ((*child)->next == NULL) {
3383 if (((*child)->parent != NULL) &&
3384 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3385 *child = (*child)->parent;
3386 } else
3387 break;
3388 }
3389 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003390 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003391 return(1);
3392 }
3393 *child = cur;
3394 return(0);
3395 case XML_ELEMENT_CONTENT_OPT:
3396 if (ret == 0) {
3397 *child = cur;
3398 return(1);
3399 }
3400 break;
3401 case XML_ELEMENT_CONTENT_MULT:
3402 if (ret == 0) {
3403 *child = cur;
3404 break;
3405 }
3406 /* no break on purpose */
3407 case XML_ELEMENT_CONTENT_PLUS:
3408 if (ret == 0) {
3409 *child = cur;
3410 return(0);
3411 }
3412 do {
3413 cur = *child;
3414 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3415 } while (ret == 1);
3416 if (ret == -1) return(-1);
3417 *child = cur;
3418 break;
3419 }
3420 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003421 if ((*child)->type == XML_ENTITY_REF_NODE) {
3422 /*
3423 * If there is an entity declared an it's not empty
3424 * Push the current node on the stack and process with the
3425 * entity content.
3426 */
3427 if (((*child)->children != NULL) &&
3428 ((*child)->children->children != NULL)) {
3429 nodeVPush(ctxt, *child);
3430 *child = (*child)->children->children;
3431 } else
3432 *child = (*child)->next;
3433 continue;
3434 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003435 if ((*child)->type == XML_PI_NODE) {
3436 *child = (*child)->next;
3437 continue;
3438 }
3439 if ((*child)->type == XML_COMMENT_NODE) {
3440 *child = (*child)->next;
3441 continue;
3442 }
3443 else if ((*child)->type != XML_ELEMENT_NODE) {
3444 return(-1);
3445 }
3446 break;
3447 }
3448 return(1);
3449}
3450
3451/**
3452 * xmlSprintfElementChilds:
3453 * @buf: an output buffer
3454 * @content: An element
3455 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3456 *
3457 * This will dump the list of childs to the buffer
3458 * Intended just for the debug routine
3459 */
3460void
3461xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3462 xmlNodePtr cur;
3463
3464 if (node == NULL) return;
3465 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003466 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003467 while (cur != NULL) {
3468 switch (cur->type) {
3469 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003470 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003471 if (cur->next != NULL)
3472 strcat(buf, " ");
3473 break;
3474 case XML_TEXT_NODE:
3475 case XML_CDATA_SECTION_NODE:
3476 case XML_ENTITY_REF_NODE:
3477 strcat(buf, "CDATA");
3478 if (cur->next != NULL)
3479 strcat(buf, " ");
3480 break;
3481 case XML_ATTRIBUTE_NODE:
3482 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003483 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003484 case XML_DOCUMENT_TYPE_NODE:
3485 case XML_DOCUMENT_FRAG_NODE:
3486 case XML_NOTATION_NODE:
3487 strcat(buf, "???");
3488 if (cur->next != NULL)
3489 strcat(buf, " ");
3490 break;
3491 case XML_ENTITY_NODE:
3492 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003493 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003494 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003495 case XML_ELEMENT_DECL:
3496 case XML_ATTRIBUTE_DECL:
3497 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003498 break;
3499 }
3500 cur = cur->next;
3501 }
3502 if (glob) strcat(buf, ")");
3503}
3504
3505
3506/**
3507 * xmlValidateOneElement:
3508 * @ctxt: the validation context
3509 * @doc: a document instance
3510 * @elem: an element instance
3511 *
3512 * Try to validate a single element and it's attributes,
3513 * basically it does the following checks as described by the
3514 * XML-1.0 recommendation:
3515 * - [ VC: Element Valid ]
3516 * - [ VC: Required Attribute ]
3517 * Then call xmlValidateOneAttribute() for each attribute present.
3518 *
3519 * The ID/IDREF checkings are done separately
3520 *
3521 * returns 1 if valid or 0 otherwise
3522 */
3523
3524int
3525xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3526 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003527 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003528 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003529 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003530 xmlNodePtr child;
3531 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003532 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003533
3534 CHECK_DTD;
3535
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003536 if (elem == NULL) return(0);
3537 if (elem->type == XML_TEXT_NODE) {
3538 }
3539 switch (elem->type) {
3540 case XML_ATTRIBUTE_NODE:
3541 VERROR(ctxt->userData,
3542 "Attribute element not expected here\n");
3543 return(0);
3544 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003545 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003546 VERROR(ctxt->userData, "Text element has childs !\n");
3547 return(0);
3548 }
3549 if (elem->properties != NULL) {
3550 VERROR(ctxt->userData, "Text element has attributes !\n");
3551 return(0);
3552 }
3553 if (elem->ns != NULL) {
3554 VERROR(ctxt->userData, "Text element has namespace !\n");
3555 return(0);
3556 }
Daniel Veillard87b95392000-08-12 21:12:04 +00003557 if (elem->nsDef != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003558 VERROR(ctxt->userData,
3559 "Text element carries namespace definitions !\n");
3560 return(0);
3561 }
3562 if (elem->content == NULL) {
3563 VERROR(ctxt->userData,
3564 "Text element has no content !\n");
3565 return(0);
3566 }
3567 return(1);
3568 case XML_CDATA_SECTION_NODE:
3569 case XML_ENTITY_REF_NODE:
3570 case XML_PI_NODE:
3571 case XML_COMMENT_NODE:
3572 return(1);
3573 case XML_ENTITY_NODE:
3574 VERROR(ctxt->userData,
3575 "Entity element not expected here\n");
3576 return(0);
3577 case XML_NOTATION_NODE:
3578 VERROR(ctxt->userData,
3579 "Notation element not expected here\n");
3580 return(0);
3581 case XML_DOCUMENT_NODE:
3582 case XML_DOCUMENT_TYPE_NODE:
3583 case XML_DOCUMENT_FRAG_NODE:
3584 VERROR(ctxt->userData,
3585 "Document element not expected here\n");
3586 return(0);
3587 case XML_HTML_DOCUMENT_NODE:
3588 VERROR(ctxt->userData,
3589 "\n");
3590 return(0);
3591 case XML_ELEMENT_NODE:
3592 break;
3593 default:
3594 VERROR(ctxt->userData,
3595 "unknown element type %d\n", elem->type);
3596 return(0);
3597 }
3598 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003599
Daniel Veillardbe803962000-06-28 23:40:59 +00003600 /*
3601 * Fetch the declaration for the qualified name
3602 */
3603 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3604 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3605 elem->name, elem->ns->prefix);
3606 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3607 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3608 elem->name, elem->ns->prefix);
3609 }
3610
3611 /*
3612 * Fetch the declaration for the non qualified name
3613 */
3614 if (elemDecl == NULL) {
3615 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3616 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3617 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3618 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003619 if (elemDecl == NULL) {
3620 VERROR(ctxt->userData, "No declaration for element %s\n",
3621 elem->name);
3622 return(0);
3623 }
3624
3625 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003626 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003627 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003628 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003629 VERROR(ctxt->userData,
3630 "Element %s was declared EMPTY this one has content\n",
3631 elem->name);
3632 ret = 0;
3633 }
3634 break;
3635 case XML_ELEMENT_TYPE_ANY:
3636 /* I don't think anything is required then */
3637 break;
3638 case XML_ELEMENT_TYPE_MIXED:
3639 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003640 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003641 while (child != NULL) {
3642 if (child->type == XML_ELEMENT_NODE) {
3643 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003644 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3645 xmlChar qname[500];
3646#ifdef HAVE_SNPRINTF
3647 snprintf((char *) qname, sizeof(qname), "%s:%s",
3648 child->ns->prefix, child->name);
3649#else
3650 sprintf(qname, "%s:%s", child->name, child->ns->prefix);
3651#endif
3652 cont = elemDecl->content;
3653 while (cont != NULL) {
3654 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3655 if (!xmlStrcmp(cont->name, qname)) break;
3656 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3657 (cont->c1 != NULL) &&
3658 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
3659 if (!xmlStrcmp(cont->c1->name, qname)) break;
3660 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3661 (cont->c1 == NULL) ||
3662 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3663 /* Internal error !!! */
3664 fprintf(stderr, "Internal: MIXED struct bad\n");
3665 break;
3666 }
3667 cont = cont->c2;
3668 }
3669 if (cont != NULL)
3670 goto child_ok;
3671 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003672 cont = elemDecl->content;
3673 while (cont != NULL) {
3674 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3675 if (!xmlStrcmp(cont->name, name)) break;
3676 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3677 (cont->c1 != NULL) &&
3678 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3679 if (!xmlStrcmp(cont->c1->name, name)) break;
3680 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3681 (cont->c1 == NULL) ||
3682 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3683 /* Internal error !!! */
3684 fprintf(stderr, "Internal: MIXED struct bad\n");
3685 break;
3686 }
3687 cont = cont->c2;
3688 }
3689 if (cont == NULL) {
3690 VERROR(ctxt->userData,
3691 "Element %s is not declared in %s list of possible childs\n",
3692 name, elem->name);
3693 ret = 0;
3694 }
3695 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003696child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003697 child = child->next;
3698 }
3699 break;
3700 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003701 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003702 cont = elemDecl->content;
3703 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3704 if ((ret == 0) || (child != NULL)) {
3705 char expr[1000];
3706 char list[2000];
3707
3708 expr[0] = 0;
3709 xmlSprintfElementContent(expr, cont, 1);
3710 list[0] = 0;
3711 xmlSprintfElementChilds(list, elem, 1);
3712
3713 VERROR(ctxt->userData,
3714 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3715 elem->name, expr, list);
3716 ret = 0;
3717 }
3718 break;
3719 }
3720
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003721 /* [ VC: Required Attribute ] */
3722 attr = elemDecl->attributes;
3723 while (attr != NULL) {
3724 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3725 xmlAttrPtr attrib;
3726 int qualified = -1;
3727
3728 attrib = elem->properties;
3729 while (attrib != NULL) {
3730 if (!xmlStrcmp(attrib->name, attr->name)) {
3731 if (attr->prefix != NULL) {
3732 xmlNsPtr nameSpace = attrib->ns;
3733
3734 if (nameSpace == NULL)
3735 nameSpace = elem->ns;
3736 /*
3737 * qualified names handling is problematic, having a
3738 * different prefix should be possible but DTDs don't
3739 * allow to define the URI instead of the prefix :-(
3740 */
3741 if (nameSpace == NULL) {
3742 if (qualified < 0)
3743 qualified = 0;
3744 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3745 if (qualified < 1)
3746 qualified = 1;
3747 } else
3748 goto found;
3749 } else {
3750 /*
3751 * We should allow applications to define namespaces
3752 * for their application even if the DTD doesn't
3753 * carry one, otherwise, basically we would always
3754 * break.
3755 */
3756 goto found;
3757 }
3758 }
3759 attrib = attrib->next;
3760 }
3761 if (qualified == -1) {
3762 if (attr->prefix == NULL) {
3763 VERROR(ctxt->userData,
3764 "Element %s doesn't carry attribute %s\n",
3765 elem->name, attr->name);
3766 } else {
3767 VERROR(ctxt->userData,
3768 "Element %s doesn't carry attribute %s:%s\n",
3769 elem->name, attr->prefix,attr->name);
3770 }
3771 } else if (qualified == 0) {
3772 VWARNING(ctxt->userData,
3773 "Element %s required attribute %s:%s has no prefix\n",
3774 elem->name, attr->prefix,attr->name);
3775 } else if (qualified == 1) {
3776 VWARNING(ctxt->userData,
3777 "Element %s required attribute %s:%s has different prefix\n",
3778 elem->name, attr->prefix,attr->name);
3779 }
3780 }
3781found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003782 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003783 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003784 return(ret);
3785}
3786
3787/**
3788 * xmlValidateRoot:
3789 * @ctxt: the validation context
3790 * @doc: a document instance
3791 *
3792 * Try to validate a the root element
3793 * basically it does the following check as described by the
3794 * XML-1.0 recommendation:
3795 * - [ VC: Root Element Type ]
3796 * it doesn't try to recurse or apply other check to the element
3797 *
3798 * returns 1 if valid or 0 otherwise
3799 */
3800
3801int
3802xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003803 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003804 if (doc == NULL) return(0);
3805
3806 if ((doc->intSubset == NULL) ||
3807 (doc->intSubset->name == NULL)) {
3808 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3809 return(0);
3810 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003811 root = xmlDocGetRootElement(doc);
3812 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003813 VERROR(ctxt->userData, "Not valid: no root element\n");
3814 return(0);
3815 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003816
3817 /*
3818 * Check first the document root against the NQName
3819 */
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003820 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003821 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3822 xmlChar qname[500];
3823#ifdef HAVE_SNPRINTF
3824 snprintf((char *) qname, sizeof(qname), "%s:%s",
3825 root->ns->prefix, root->name);
3826#else
3827 sprintf(qname, "%s:%s", root->name, root->ns->prefix);
3828#endif
3829 if (!xmlStrcmp(doc->intSubset->name, qname))
3830 goto name_ok;
3831 }
3832 if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
3833 (!xmlStrcmp(root->name, BAD_CAST "html")))
3834 goto name_ok;
3835 VERROR(ctxt->userData,
3836 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3837 root->name, doc->intSubset->name);
3838 return(0);
3839
Daniel Veillardb05deb71999-08-10 19:04:08 +00003840 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003841name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003842 return(1);
3843}
3844
3845
3846/**
3847 * xmlValidateElement:
3848 * @ctxt: the validation context
3849 * @doc: a document instance
3850 * @elem: an element instance
3851 *
3852 * Try to validate the subtree under an element
3853 *
3854 * returns 1 if valid or 0 otherwise
3855 */
3856
3857int
3858xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003859 xmlNodePtr child;
3860 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003861 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003862 int ret = 1;
3863
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003864 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003865 CHECK_DTD;
3866
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003867 ret &= xmlValidateOneElement(ctxt, doc, elem);
3868 attr = elem->properties;
3869 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003870 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003871 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3872 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003873 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003874 attr= attr->next;
3875 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003876 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003877 while (child != NULL) {
3878 ret &= xmlValidateElement(ctxt, doc, child);
3879 child = child->next;
3880 }
3881
3882 return(ret);
3883}
3884
3885/**
3886 * xmlValidateDocumentFinal:
3887 * @ctxt: the validation context
3888 * @doc: a document instance
3889 *
3890 * Does the final step for the document validation once all the
3891 * incremental validation steps have been completed
3892 *
3893 * basically it does the following checks described by the XML Rec
3894 *
3895 *
3896 * returns 1 if valid or 0 otherwise
3897 */
3898
3899int
3900xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3901 int ret = 1, i;
3902 xmlRefTablePtr table;
3903 xmlAttrPtr id;
3904
3905 if (doc == NULL) {
3906 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3907 return(0);
3908 }
3909
3910 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003911 * Check all the NOTATION/NOTATIONS attributes
3912 */
3913 /*
3914 * Check all the ENTITY/ENTITIES attributes definition for validity
3915 */
3916 /*
3917 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003918 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003919 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003920 if (table != NULL) {
3921 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003922 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3923 id = xmlGetID(doc, table->table[i]->value);
3924 if (id == NULL) {
3925 VERROR(ctxt->userData,
3926 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3927 table->table[i]->attr->name, table->table[i]->value);
3928 ret = 0;
3929 }
3930 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
3931 xmlChar *dup, *name = NULL, *cur, save;
3932
3933 dup = xmlStrdup(table->table[i]->value);
3934 if (dup == NULL)
3935 return(0);
3936 cur = dup;
3937 while (*cur != 0) {
3938 name = cur;
3939 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3940 save = *cur;
3941 *cur = 0;
3942 id = xmlGetID(doc, name);
3943 if (id == NULL) {
3944 VERROR(ctxt->userData,
3945 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3946 table->table[i]->attr->name, name);
3947 ret = 0;
3948 }
3949 if (save == 0)
3950 break;
3951 *cur = save;
3952 while (IS_BLANK(*cur)) cur++;
3953 }
3954 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003955 }
3956 }
3957 }
3958 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003959}
3960
3961/**
3962 * xmlValidateDtd:
3963 * @ctxt: the validation context
3964 * @doc: a document instance
3965 * @dtd: a dtd instance
3966 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003967 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003968 *
3969 * basically it does check all the definitions in the DtD.
3970 *
3971 * returns 1 if valid or 0 otherwise
3972 */
3973
3974int
3975xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003976 int ret;
3977 xmlDtdPtr oldExt;
3978 xmlNodePtr root;
3979
3980 if (dtd == NULL) return(0);
3981 if (doc == NULL) return(0);
3982 oldExt = doc->extSubset;
3983 doc->extSubset = dtd;
3984 ret = xmlValidateRoot(ctxt, doc);
3985 if (ret == 0) {
3986 doc->extSubset = oldExt;
3987 return(ret);
3988 }
3989 root = xmlDocGetRootElement(doc);
3990 ret = xmlValidateElement(ctxt, doc, root);
3991 ret &= xmlValidateDocumentFinal(ctxt, doc);
3992 doc->extSubset = oldExt;
3993 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003994}
3995
3996/**
Daniel Veillardcf461992000-03-14 18:30:20 +00003997 * xmlValidateDtdFinal:
3998 * @ctxt: the validation context
3999 * @doc: a document instance
4000 *
4001 * Does the final step for the dtds validation once all the
4002 * subsets have been parsed
4003 *
4004 * basically it does the following checks described by the XML Rec
4005 * - check that ENTITY and ENTITIES type attributes default or
4006 * possible values matches one of the defined entities.
4007 * - check that NOTATION type attributes default or
4008 * possible values matches one of the defined notations.
4009 *
4010 * returns 1 if valid or 0 otherwise
4011 */
4012
4013int
4014xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4015 int ret = 1, i;
4016 xmlDtdPtr dtd;
4017 xmlAttributeTablePtr table;
4018 xmlAttributePtr cur;
4019
4020 if (doc == NULL) return(0);
4021 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4022 return(0);
4023 dtd = doc->intSubset;
4024 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004025 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004026
4027 for (i = 0;i < table->nb_attributes;i++) {
4028 cur = table->table[i];
4029 switch (cur->atype) {
4030 case XML_ATTRIBUTE_CDATA:
4031 case XML_ATTRIBUTE_ID:
4032 case XML_ATTRIBUTE_IDREF :
4033 case XML_ATTRIBUTE_IDREFS:
4034 case XML_ATTRIBUTE_NMTOKEN:
4035 case XML_ATTRIBUTE_NMTOKENS:
4036 case XML_ATTRIBUTE_ENUMERATION:
4037 break;
4038 case XML_ATTRIBUTE_ENTITY:
4039 case XML_ATTRIBUTE_ENTITIES:
4040 case XML_ATTRIBUTE_NOTATION:
4041 if (cur->defaultValue != NULL) {
4042 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4043 cur->atype, cur->defaultValue);
4044 }
4045 if (cur->tree != NULL) {
4046 xmlEnumerationPtr tree = cur->tree;
4047 while (tree != NULL) {
4048 ret &= xmlValidateAttributeValue2(ctxt, doc,
4049 cur->name, cur->atype, tree->name);
4050 tree = tree->next;
4051 }
4052 }
4053 }
4054 }
4055 }
4056 dtd = doc->extSubset;
4057 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004058 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004059
4060 for (i = 0;i < table->nb_attributes;i++) {
4061 cur = table->table[i];
4062 switch (cur->atype) {
4063 case XML_ATTRIBUTE_CDATA:
4064 case XML_ATTRIBUTE_ID:
4065 case XML_ATTRIBUTE_IDREF :
4066 case XML_ATTRIBUTE_IDREFS:
4067 case XML_ATTRIBUTE_NMTOKEN:
4068 case XML_ATTRIBUTE_NMTOKENS:
4069 case XML_ATTRIBUTE_ENUMERATION:
4070 break;
4071 case XML_ATTRIBUTE_ENTITY:
4072 case XML_ATTRIBUTE_ENTITIES:
4073 case XML_ATTRIBUTE_NOTATION:
4074 if (cur->defaultValue != NULL) {
4075 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4076 cur->atype, cur->defaultValue);
4077 }
4078 if (cur->tree != NULL) {
4079 xmlEnumerationPtr tree = cur->tree;
4080 while (tree != NULL) {
4081 ret &= xmlValidateAttributeValue2(ctxt, doc,
4082 cur->name, cur->atype, tree->name);
4083 tree = tree->next;
4084 }
4085 }
4086 }
4087 }
4088 }
4089 return(ret);
4090}
4091
4092/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00004093 * xmlValidateDocument:
4094 * @ctxt: the validation context
4095 * @doc: a document instance
4096 *
4097 * Try to validate the document instance
4098 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004099 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00004100 * i.e. validates the internal and external subset (if present)
4101 * and validate the document tree.
4102 *
4103 * returns 1 if valid or 0 otherwise
4104 */
4105
4106int
4107xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004108 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004109 xmlNodePtr root;
4110
4111 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4112 return(0);
4113 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4114 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4115 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4116 doc->intSubset->SystemID);
4117 if (doc->extSubset == NULL) {
4118 if (doc->intSubset->SystemID != NULL) {
4119 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004120 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004121 doc->intSubset->SystemID);
4122 } else {
4123 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004124 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004125 doc->intSubset->ExternalID);
4126 }
4127 return(0);
4128 }
4129 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004130
Daniel Veillardcf461992000-03-14 18:30:20 +00004131 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004132 if (!xmlValidateRoot(ctxt, doc)) return(0);
4133
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004134 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00004135 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004136 ret &= xmlValidateDocumentFinal(ctxt, doc);
4137 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004138}
4139
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004140
4141/************************************************************************
4142 * *
4143 * Routines for dynamic validation editing *
4144 * *
4145 ************************************************************************/
4146
4147/**
4148 * xmlValidGetPotentialChildren:
4149 * @ctree: an element content tree
4150 * @list: an array to store the list of child names
4151 * @len: a pointer to the number of element in the list
4152 * @max: the size of the array
4153 *
4154 * Build/extend a list of potential children allowed by the content tree
4155 *
4156 * returns the number of element in the list, or -1 in case of error.
4157 */
4158
4159int
4160xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4161 int *len, int max) {
4162 int i;
4163
4164 if ((ctree == NULL) || (list == NULL) || (len == NULL))
4165 return(-1);
4166 if (*len >= max) return(*len);
4167
4168 switch (ctree->type) {
4169 case XML_ELEMENT_CONTENT_PCDATA:
4170 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00004171 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
4172 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004173 break;
4174 case XML_ELEMENT_CONTENT_ELEMENT:
4175 for (i = 0; i < *len;i++)
4176 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
4177 list[(*len)++] = ctree->name;
4178 break;
4179 case XML_ELEMENT_CONTENT_SEQ:
4180 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4181 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4182 break;
4183 case XML_ELEMENT_CONTENT_OR:
4184 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4185 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4186 break;
4187 }
4188
4189 return(*len);
4190}
4191
4192/**
4193 * xmlValidGetValidElements:
4194 * @prev: an element to insert after
4195 * @next: an element to insert next
4196 * @list: an array to store the list of child names
4197 * @max: the size of the array
4198 *
4199 * This function returns the list of authorized children to insert
4200 * within an existing tree while respecting the validity constraints
4201 * forced by the Dtd. The insertion point is defined using @prev and
4202 * @next in the following ways:
4203 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4204 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4205 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4206 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4207 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4208 *
4209 * pointers to the element names are inserted at the beginning of the array
4210 * and do not need to be freed.
4211 *
4212 * returns the number of element in the list, or -1 in case of error. If
4213 * the function returns the value @max the caller is invited to grow the
4214 * receiving array and retry.
4215 */
4216
4217int
4218xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4219 int max) {
4220 int nb_valid_elements = 0;
4221 const xmlChar *elements[256];
4222 int nb_elements = 0, i;
4223
4224 xmlNode *ref_node;
4225 xmlNode *parent;
4226 xmlNode *test_node;
4227
4228 xmlNode *prev_next;
4229 xmlNode *next_prev;
4230 xmlNode *parent_childs;
4231 xmlNode *parent_last;
4232
4233 xmlElement *element_desc;
4234
4235 if (prev == NULL && next == NULL)
4236 return(-1);
4237
4238 if (list == NULL) return(-1);
4239 if (max <= 0) return(-1);
4240
4241 nb_valid_elements = 0;
4242 ref_node = prev ? prev : next;
4243 parent = ref_node->parent;
4244
4245 /*
4246 * Retrieves the parent element declaration
4247 */
4248 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4249 parent->name);
4250 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4251 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4252 parent->name);
4253 if (element_desc == NULL) return(-1);
4254
4255 /*
4256 * Do a backup of the current tree structure
4257 */
4258 prev_next = prev ? prev->next : NULL;
4259 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004260 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004261 parent_last = parent->last;
4262
4263 /*
4264 * Creates a dummy node and insert it into the tree
4265 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004266 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004267 test_node->doc = ref_node->doc;
4268 test_node->parent = parent;
4269 test_node->prev = prev;
4270 test_node->next = next;
4271
4272 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00004273 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004274
4275 if (next) next->prev = test_node;
4276 else parent->last = test_node;
4277
4278 /*
4279 * Insert each potential child node and check if the parent is
4280 * still valid
4281 */
4282 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4283 elements, &nb_elements, 256);
4284
4285 for (i = 0;i < nb_elements;i++) {
4286 test_node->name = elements[i];
4287 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4288 int j;
4289
4290 for (j = 0; j < nb_valid_elements;j++)
4291 if (!xmlStrcmp(elements[i], list[j])) break;
4292 list[nb_valid_elements++] = elements[i];
4293 if (nb_valid_elements >= max) break;
4294 }
4295 }
4296
4297 /*
4298 * Restore the tree structure
4299 */
4300 if (prev) prev->next = prev_next;
4301 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004302 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004303 parent->last = parent_last;
4304
4305 return(nb_valid_elements);
4306}