blob: 3fb79114740ad432198e7f6584b7301bee2e6d96 [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;
296 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
297 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000298 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000299 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000300 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000301}
302
Daniel Veillard1899e851999-02-01 12:18:54 +0000303/**
304 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000305 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000306 * @content: An element table
307 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
308 *
309 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000310 */
311void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000312xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000313 if (content == NULL) return;
314
Daniel Veillard5099ae81999-04-21 20:12:07 +0000315 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000316 switch (content->type) {
317 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000318 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000319 break;
320 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000321 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000322 break;
323 case XML_ELEMENT_CONTENT_SEQ:
324 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
325 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000326 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000327 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000328 xmlDumpElementContent(buf, content->c1, 0);
329 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000330 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000331 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000332 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000333 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000334 break;
335 case XML_ELEMENT_CONTENT_OR:
336 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
337 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000338 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000339 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000340 xmlDumpElementContent(buf, content->c1, 0);
341 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000342 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000343 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000344 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000345 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000346 break;
347 default:
348 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
349 content->type);
350 }
351 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000352 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000353 switch (content->ocur) {
354 case XML_ELEMENT_CONTENT_ONCE:
355 break;
356 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000357 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000358 break;
359 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000360 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000361 break;
362 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000363 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000364 break;
365 }
366}
367
Daniel Veillardb05deb71999-08-10 19:04:08 +0000368/**
369 * xmlSprintfElementContent:
370 * @buf: an output buffer
371 * @content: An element table
372 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
373 *
374 * This will dump the content of the element content definition
375 * Intended just for the debug routine
376 */
377void
378xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
379 if (content == NULL) return;
380 if (glob) strcat(buf, "(");
381 switch (content->type) {
382 case XML_ELEMENT_CONTENT_PCDATA:
383 strcat(buf, "#PCDATA");
384 break;
385 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000386 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000387 break;
388 case XML_ELEMENT_CONTENT_SEQ:
389 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
390 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
391 xmlSprintfElementContent(buf, content->c1, 1);
392 else
393 xmlSprintfElementContent(buf, content->c1, 0);
394 strcat(buf, " , ");
395 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
396 xmlSprintfElementContent(buf, content->c2, 1);
397 else
398 xmlSprintfElementContent(buf, content->c2, 0);
399 break;
400 case XML_ELEMENT_CONTENT_OR:
401 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
402 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
403 xmlSprintfElementContent(buf, content->c1, 1);
404 else
405 xmlSprintfElementContent(buf, content->c1, 0);
406 strcat(buf, " | ");
407 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
408 xmlSprintfElementContent(buf, content->c2, 1);
409 else
410 xmlSprintfElementContent(buf, content->c2, 0);
411 break;
412 }
413 if (glob)
414 strcat(buf, ")");
415 switch (content->ocur) {
416 case XML_ELEMENT_CONTENT_ONCE:
417 break;
418 case XML_ELEMENT_CONTENT_OPT:
419 strcat(buf, "?");
420 break;
421 case XML_ELEMENT_CONTENT_MULT:
422 strcat(buf, "*");
423 break;
424 case XML_ELEMENT_CONTENT_PLUS:
425 strcat(buf, "+");
426 break;
427 }
428}
429
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000430/****************************************************************
431 * *
432 * Registration of DTD declarations *
433 * *
434 ****************************************************************/
435
Daniel Veillard3b9def11999-01-31 22:15:06 +0000436/**
437 * xmlCreateElementTable:
438 *
439 * create and initialize an empty element hash table.
440 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000441 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000442 */
443xmlElementTablePtr
444xmlCreateElementTable(void) {
445 xmlElementTablePtr ret;
446
447 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000448 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000449 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000450 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000451 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000452 return(NULL);
453 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000454 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000455 ret->nb_elements = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000456 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000457 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000458 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000459 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000460 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000461 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000462 return(NULL);
463 }
464 return(ret);
465}
466
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000467
468/**
469 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000470 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000471 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000472 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000473 * @type: the element type
474 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000475 *
476 * Register a new element declaration
477 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000478 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000479 */
480xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000481xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillardcf461992000-03-14 18:30:20 +0000482 xmlElementTypeVal type,
483 xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000484 xmlElementPtr ret, cur;
485 xmlElementTablePtr table;
Daniel Veillardbe803962000-06-28 23:40:59 +0000486 xmlChar *ns, *uqname;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000487 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000488
489 if (dtd == NULL) {
490 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
491 return(NULL);
492 }
493 if (name == NULL) {
494 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
495 return(NULL);
496 }
497 switch (type) {
498 case XML_ELEMENT_TYPE_EMPTY:
499 if (content != NULL) {
500 fprintf(stderr,
501 "xmlAddElementDecl: content != NULL for EMPTY\n");
502 return(NULL);
503 }
504 break;
505 case XML_ELEMENT_TYPE_ANY:
506 if (content != NULL) {
507 fprintf(stderr,
508 "xmlAddElementDecl: content != NULL for ANY\n");
509 return(NULL);
510 }
511 break;
512 case XML_ELEMENT_TYPE_MIXED:
513 if (content == NULL) {
514 fprintf(stderr,
515 "xmlAddElementDecl: content == NULL for MIXED\n");
516 return(NULL);
517 }
518 break;
519 case XML_ELEMENT_TYPE_ELEMENT:
520 if (content == NULL) {
521 fprintf(stderr,
522 "xmlAddElementDecl: content == NULL for ELEMENT\n");
523 return(NULL);
524 }
525 break;
526 default:
527 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
528 return(NULL);
529 }
530
531 /*
Daniel Veillardbe803962000-06-28 23:40:59 +0000532 * check if name is a QName
533 */
534 uqname = xmlSplitQName2(name, &ns);
535 if (uqname != NULL)
536 name = uqname;
537
538 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000539 * Create the Element table if needed.
540 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000541 table = (xmlElementTablePtr) dtd->elements;
542 if (table == NULL) {
543 table = xmlCreateElementTable();
544 dtd->elements = (void *) table;
545 }
Daniel Veillard3b9def11999-01-31 22:15:06 +0000546 if (table == NULL) {
547 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
548 return(NULL);
549 }
550
551 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000552 * Validity Check:
553 * Search the DTD for previous declarations of the ELEMENT
554 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000555 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000556 cur = table->table[i];
Daniel Veillardbe803962000-06-28 23:40:59 +0000557 if ((ns != NULL) && (cur->prefix == NULL)) continue;
558 if ((ns == NULL) && (cur->prefix != NULL)) continue;
559 if ((!xmlStrcmp(cur->name, name)) &&
560 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000561 /*
562 * The element is already defined in this Dtd.
563 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000564 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000565 return(NULL);
566 }
567 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000568
569 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000570 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000571 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000572 if (table->nb_elements >= table->max_elements) {
573 /*
574 * need more elements.
575 */
576 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000577 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000578 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000579 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000580 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
581 return(NULL);
582 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000583 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000584 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000585 if (ret == NULL) {
586 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
587 return(NULL);
588 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000589 memset(ret, 0, sizeof(xmlElement));
590 ret->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000591 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000592
593 /*
594 * fill the structure.
595 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000596 ret->etype = type;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000597 ret->name = xmlStrdup(name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000598 ret->prefix = ns;
Daniel Veillard14fff061999-06-22 21:49:07 +0000599 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000600 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000601 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000602
Daniel Veillardcf461992000-03-14 18:30:20 +0000603 /*
604 * Link it to the Dtd
605 */
606 ret->parent = dtd;
607 ret->doc = dtd->doc;
608 if (dtd->last == NULL) {
609 dtd->children = dtd->last = (xmlNodePtr) ret;
610 } else {
611 dtd->last->next = (xmlNodePtr) ret;
612 ret->prev = dtd->last;
613 dtd->last = (xmlNodePtr) ret;
614 }
Daniel Veillardbe803962000-06-28 23:40:59 +0000615 if (uqname != NULL)
616 xmlFree(uqname);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000617 return(ret);
618}
619
Daniel Veillard3b9def11999-01-31 22:15:06 +0000620/**
621 * xmlFreeElement:
622 * @elem: An element
623 *
624 * Deallocate the memory used by an element definition
625 */
626void
627xmlFreeElement(xmlElementPtr elem) {
628 if (elem == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +0000629 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000630 xmlFreeElementContent(elem->content);
631 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000632 xmlFree((xmlChar *) elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000633 if (elem->prefix != NULL)
634 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000635 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000636 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000637}
638
639/**
640 * xmlFreeElementTable:
641 * @table: An element table
642 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000643 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000644 */
645void
646xmlFreeElementTable(xmlElementTablePtr table) {
647 int i;
648
649 if (table == NULL) return;
650
651 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000652 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000653 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000654 xmlFree(table->table);
655 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000656}
657
658/**
659 * xmlCopyElementTable:
660 * @table: An element table
661 *
662 * Build a copy of an element table.
663 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000664 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000665 */
666xmlElementTablePtr
667xmlCopyElementTable(xmlElementTablePtr table) {
668 xmlElementTablePtr ret;
669 xmlElementPtr cur, ent;
670 int i;
671
Daniel Veillard6454aec1999-09-02 22:04:43 +0000672 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000673 if (ret == NULL) {
674 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
675 return(NULL);
676 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000677 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000678 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000679 if (ret->table == NULL) {
680 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000681 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000682 return(NULL);
683 }
684 ret->max_elements = table->max_elements;
685 ret->nb_elements = table->nb_elements;
686 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000687 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000688 if (cur == NULL) {
689 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000690 xmlFree(ret);
691 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000692 return(NULL);
693 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000694 memset(cur, 0, sizeof(xmlElement));
695 cur->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000696 ret->table[i] = cur;
697 ent = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000698 cur->etype = ent->etype;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000699 if (ent->name != NULL)
700 cur->name = xmlStrdup(ent->name);
701 else
702 cur->name = NULL;
703 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000704 /* TODO : rebuild the attribute list on the copy */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000705 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000706 }
707 return(ret);
708}
709
710/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000711 * xmlDumpElementDecl:
712 * @buf: the XML buffer output
713 * @elem: An element table
714 *
715 * This will dump the content of the element declaration as an XML
716 * DTD definition
717 */
718void
719xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
720 switch (elem->etype) {
721 case XML_ELEMENT_TYPE_EMPTY:
722 xmlBufferWriteChar(buf, "<!ELEMENT ");
723 xmlBufferWriteCHAR(buf, elem->name);
724 xmlBufferWriteChar(buf, " EMPTY>\n");
725 break;
726 case XML_ELEMENT_TYPE_ANY:
727 xmlBufferWriteChar(buf, "<!ELEMENT ");
728 xmlBufferWriteCHAR(buf, elem->name);
729 xmlBufferWriteChar(buf, " ANY>\n");
730 break;
731 case XML_ELEMENT_TYPE_MIXED:
732 xmlBufferWriteChar(buf, "<!ELEMENT ");
733 xmlBufferWriteCHAR(buf, elem->name);
734 xmlBufferWriteChar(buf, " ");
735 xmlDumpElementContent(buf, elem->content, 1);
736 xmlBufferWriteChar(buf, ">\n");
737 break;
738 case XML_ELEMENT_TYPE_ELEMENT:
739 xmlBufferWriteChar(buf, "<!ELEMENT ");
740 xmlBufferWriteCHAR(buf, elem->name);
741 xmlBufferWriteChar(buf, " ");
742 xmlDumpElementContent(buf, elem->content, 1);
743 xmlBufferWriteChar(buf, ">\n");
744 break;
745 default:
746 fprintf(stderr,
747 "xmlDumpElementDecl: internal: unknown type %d\n",
748 elem->etype);
749 }
750}
751
752/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000753 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000754 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000755 * @table: An element table
756 *
757 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000758 */
759void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000760xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000761 int i;
762 xmlElementPtr cur;
763
764 if (table == NULL) return;
765
766 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000767 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000768 xmlDumpElementDecl(buf, cur);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000769 }
770}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000771
772/**
773 * xmlCreateEnumeration:
774 * @name: the enumeration name or NULL
775 *
776 * create and initialize an enumeration attribute node.
777 *
778 * Returns the xmlEnumerationPtr just created or NULL in case
779 * of error.
780 */
781xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000782xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000783 xmlEnumerationPtr ret;
784
Daniel Veillard6454aec1999-09-02 22:04:43 +0000785 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000786 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000787 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000788 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000789 return(NULL);
790 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000791 memset(ret, 0, sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000792
793 if (name != NULL)
794 ret->name = xmlStrdup(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000795 return(ret);
796}
797
798/**
799 * xmlFreeEnumeration:
800 * @cur: the tree to free.
801 *
802 * free an enumeration attribute node (recursive).
803 */
804void
805xmlFreeEnumeration(xmlEnumerationPtr cur) {
806 if (cur == NULL) return;
807
808 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
809
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000810 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000811 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000812 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000813}
814
815/**
816 * xmlCopyEnumeration:
817 * @cur: the tree to copy.
818 *
819 * Copy an enumeration attribute node (recursive).
820 *
821 * Returns the xmlEnumerationPtr just created or NULL in case
822 * of error.
823 */
824xmlEnumerationPtr
825xmlCopyEnumeration(xmlEnumerationPtr cur) {
826 xmlEnumerationPtr ret;
827
828 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000829 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000830
831 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
832 else ret->next = NULL;
833
834 return(ret);
835}
836
837/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000838 * xmlDumpEnumeration:
839 * @buf: the XML buffer output
840 * @enum: An enumeration
841 *
842 * This will dump the content of the enumeration
843 */
844void
845xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
846 if (cur == NULL) return;
847
848 xmlBufferWriteCHAR(buf, cur->name);
849 if (cur->next == NULL)
850 xmlBufferWriteChar(buf, ")");
851 else {
852 xmlBufferWriteChar(buf, " | ");
853 xmlDumpEnumeration(buf, cur->next);
854 }
855}
856
857/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000858 * xmlCreateAttributeTable:
859 *
860 * create and initialize an empty attribute hash table.
861 *
862 * Returns the xmlAttributeTablePtr just created or NULL in case
863 * of error.
864 */
865xmlAttributeTablePtr
866xmlCreateAttributeTable(void) {
867 xmlAttributeTablePtr ret;
868
869 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000870 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000871 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000872 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000873 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000874 return(NULL);
875 }
876 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
877 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000878 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000879 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000880 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000881 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000882 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000883 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000884 return(NULL);
885 }
886 return(ret);
887}
888
Daniel Veillardb05deb71999-08-10 19:04:08 +0000889/**
890 * xmlScanAttributeDecl:
891 * @dtd: pointer to the DTD
892 * @elem: the element name
893 *
894 * When inserting a new element scan the DtD for existing attributes
895 * for taht element and initialize the Attribute chain
896 *
897 * Returns the pointer to the first attribute decl in the chain,
898 * possibly NULL.
899 */
900xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000901xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000902 xmlAttributePtr ret = NULL;
903 xmlAttributeTablePtr table;
904 int i;
905
906 if (dtd == NULL) {
907 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
908 return(NULL);
909 }
910 if (elem == NULL) {
911 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
912 return(NULL);
913 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000914 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000915 if (table == NULL)
916 return(NULL);
917
918 for (i = 0;i < table->nb_attributes;i++) {
919 if (!xmlStrcmp(table->table[i]->elem, elem)) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000920 table->table[i]->nexth = ret;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000921 ret = table->table[i];
922 }
923 }
924 return(ret);
925}
926
927/**
928 * xmlScanIDAttributeDecl:
929 * @ctxt: the validation context
930 * @elem: the element name
931 *
Daniel Veillard71b656e2000-01-05 14:46:17 +0000932 * Verify that the element don't have too many ID attributes
Daniel Veillardb05deb71999-08-10 19:04:08 +0000933 * declared.
934 *
935 * Returns the number of ID attributes found.
936 */
937int
938xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
939 xmlAttributePtr cur;
940 int ret = 0;
941
942 if (elem == NULL) return(0);
943 cur = elem->attributes;
944 while (cur != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000945 if (cur->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000946 ret ++;
947 if (ret > 1)
948 VERROR(ctxt->userData,
949 "Element %s has too may ID attributes defined : %s\n",
950 elem->name, cur->name);
951 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000952 cur = cur->nexth;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000953 }
954 return(ret);
955}
956
Daniel Veillard1e346af1999-02-22 10:33:01 +0000957
958/**
959 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000960 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000961 * @dtd: pointer to the DTD
962 * @elem: the element name
963 * @name: the attribute name
Daniel Veillardcf461992000-03-14 18:30:20 +0000964 * @ns: the attribute namespace prefix
Daniel Veillard1e346af1999-02-22 10:33:01 +0000965 * @type: the attribute type
966 * @def: the attribute default type
967 * @defaultValue: the attribute default value
968 * @tree: if it's an enumeration, the associated list
969 *
970 * Register a new attribute declaration
971 *
Daniel Veillardbe803962000-06-28 23:40:59 +0000972 * Returns NULL if not new, othervise the attribute decl
Daniel Veillard1e346af1999-02-22 10:33:01 +0000973 */
974xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000975xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
Daniel Veillardcf461992000-03-14 18:30:20 +0000976 const xmlChar *name, const xmlChar *ns,
977 xmlAttributeType type, xmlAttributeDefault def,
978 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000979 xmlAttributePtr ret, cur;
980 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000981 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000982 int i;
983
984 if (dtd == NULL) {
985 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
986 return(NULL);
987 }
988 if (name == NULL) {
989 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
990 return(NULL);
991 }
992 if (elem == NULL) {
993 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
994 return(NULL);
995 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000996 /*
997 * Check the type and possibly the default value.
998 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000999 switch (type) {
1000 case XML_ATTRIBUTE_CDATA:
1001 break;
1002 case XML_ATTRIBUTE_ID:
1003 break;
1004 case XML_ATTRIBUTE_IDREF:
1005 break;
1006 case XML_ATTRIBUTE_IDREFS:
1007 break;
1008 case XML_ATTRIBUTE_ENTITY:
1009 break;
1010 case XML_ATTRIBUTE_ENTITIES:
1011 break;
1012 case XML_ATTRIBUTE_NMTOKEN:
1013 break;
1014 case XML_ATTRIBUTE_NMTOKENS:
1015 break;
1016 case XML_ATTRIBUTE_ENUMERATION:
1017 break;
1018 case XML_ATTRIBUTE_NOTATION:
1019 break;
1020 default:
1021 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
1022 return(NULL);
1023 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001024 if ((defaultValue != NULL) &&
1025 (!xmlValidateAttributeValue(type, defaultValue))) {
1026 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
1027 elem, name, defaultValue);
1028 defaultValue = NULL;
1029 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001030
1031 /*
1032 * Create the Attribute table if needed.
1033 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001034 table = (xmlAttributeTablePtr) dtd->attributes;
1035 if (table == NULL) {
1036 table = xmlCreateAttributeTable();
1037 dtd->attributes = (void *) table;
1038 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001039 if (table == NULL) {
1040 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
1041 return(NULL);
1042 }
1043
1044 /*
1045 * Validity Check:
1046 * Search the DTD for previous declarations of the ATTLIST
1047 */
1048 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001049 cur = table->table[i];
Daniel Veillard10a2c651999-12-12 13:03:50 +00001050 if ((ns != NULL) && (cur->prefix == NULL)) continue;
1051 if ((ns == NULL) && (cur->prefix != NULL)) continue;
Daniel Veillardcf461992000-03-14 18:30:20 +00001052 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem)) &&
Daniel Veillard10a2c651999-12-12 13:03:50 +00001053 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001054 /*
1055 * The attribute is already defined in this Dtd.
1056 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001057 VWARNING(ctxt->userData, "Attribute %s on %s: already defined\n",
Daniel Veillardb96e6431999-08-29 21:02:19 +00001058 elem, name);
Daniel Veillardbe803962000-06-28 23:40:59 +00001059 return(NULL);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001060 }
1061 }
1062
1063 /*
1064 * Grow the table, if needed.
1065 */
1066 if (table->nb_attributes >= table->max_attributes) {
1067 /*
1068 * need more attributes.
1069 */
1070 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001071 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001072 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001073 sizeof(xmlAttributePtr));
1074 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001075 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1076 return(NULL);
1077 }
1078 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001079 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001080 if (ret == NULL) {
1081 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1082 return(NULL);
1083 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001084 memset(ret, 0, sizeof(xmlAttribute));
1085 ret->type = XML_ATTRIBUTE_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001086 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001087
1088 /*
1089 * fill the structure.
1090 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001091 ret->atype = type;
1092 ret->name = xmlStrdup(name);
1093 ret->prefix = xmlStrdup(ns);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001094 ret->elem = xmlStrdup(elem);
1095 ret->def = def;
1096 ret->tree = tree;
1097 if (defaultValue != NULL)
1098 ret->defaultValue = xmlStrdup(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001099 elemDef = xmlGetDtdElementDesc(dtd, elem);
1100 if (elemDef != NULL) {
1101 if ((type == XML_ATTRIBUTE_ID) &&
1102 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
1103 VERROR(ctxt->userData,
1104 "Element %s has too may ID attributes defined : %s\n",
1105 elem, name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001106 ret->nexth = elemDef->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001107 elemDef->attributes = ret;
1108 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001109 table->nb_attributes++;
1110
Daniel Veillardcf461992000-03-14 18:30:20 +00001111 /*
1112 * Link it to the Dtd
1113 */
1114 ret->parent = dtd;
1115 ret->doc = dtd->doc;
1116 if (dtd->last == NULL) {
1117 dtd->children = dtd->last = (xmlNodePtr) ret;
1118 } else {
1119 dtd->last->next = (xmlNodePtr) ret;
1120 ret->prev = dtd->last;
1121 dtd->last = (xmlNodePtr) ret;
1122 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001123 return(ret);
1124}
1125
1126/**
1127 * xmlFreeAttribute:
1128 * @elem: An attribute
1129 *
1130 * Deallocate the memory used by an attribute definition
1131 */
1132void
1133xmlFreeAttribute(xmlAttributePtr attr) {
1134 if (attr == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +00001135 xmlUnlinkNode((xmlNodePtr) attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001136 if (attr->tree != NULL)
1137 xmlFreeEnumeration(attr->tree);
1138 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001139 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001140 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001141 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001142 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001143 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +00001144 if (attr->prefix != NULL)
1145 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001146 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001147 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001148}
1149
1150/**
1151 * xmlFreeAttributeTable:
1152 * @table: An attribute table
1153 *
1154 * Deallocate the memory used by an entities hash table.
1155 */
1156void
1157xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1158 int i;
1159
1160 if (table == NULL) return;
1161
1162 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001163 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001164 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001165 xmlFree(table->table);
1166 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001167}
1168
1169/**
1170 * xmlCopyAttributeTable:
1171 * @table: An attribute table
1172 *
1173 * Build a copy of an attribute table.
1174 *
1175 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1176 */
1177xmlAttributeTablePtr
1178xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1179 xmlAttributeTablePtr ret;
1180 xmlAttributePtr cur, attr;
1181 int i;
1182
Daniel Veillard6454aec1999-09-02 22:04:43 +00001183 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001184 if (ret == NULL) {
1185 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1186 return(NULL);
1187 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001188 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001189 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001190 if (ret->table == NULL) {
1191 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001192 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001193 return(NULL);
1194 }
1195 ret->max_attributes = table->max_attributes;
1196 ret->nb_attributes = table->nb_attributes;
1197 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001198 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001199 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001200 if (cur == NULL) {
1201 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001202 xmlFree(ret);
1203 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001204 return(NULL);
1205 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001206 memset(cur, 0, sizeof(xmlAttribute));
1207 /* !!! cur->type = XML_ATTRIBUTE_DECL; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001208 ret->table[i] = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001209 cur->atype = attr->atype;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001210 cur->def = attr->def;
1211 cur->tree = xmlCopyEnumeration(attr->tree);
1212 if (attr->elem != NULL)
1213 cur->elem = xmlStrdup(attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001214 if (attr->name != NULL)
1215 cur->name = xmlStrdup(attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001216 if (attr->defaultValue != NULL)
1217 cur->defaultValue = xmlStrdup(attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001218 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001219 }
1220 return(ret);
1221}
1222
1223/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001224 * xmlDumpAttributeDecl:
1225 * @buf: the XML buffer output
1226 * @attr: An attribute declaration
1227 *
1228 * This will dump the content of the attribute declaration as an XML
1229 * DTD definition
1230 */
1231void
1232xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1233 xmlBufferWriteChar(buf, "<!ATTLIST ");
1234 xmlBufferWriteCHAR(buf, attr->elem);
1235 xmlBufferWriteChar(buf, " ");
Daniel Veillardbe803962000-06-28 23:40:59 +00001236 if (attr->prefix != NULL) {
1237 xmlBufferWriteCHAR(buf, attr->prefix);
1238 xmlBufferWriteChar(buf, ":");
1239 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001240 xmlBufferWriteCHAR(buf, attr->name);
1241 switch (attr->atype) {
1242 case XML_ATTRIBUTE_CDATA:
1243 xmlBufferWriteChar(buf, " CDATA");
1244 break;
1245 case XML_ATTRIBUTE_ID:
1246 xmlBufferWriteChar(buf, " ID");
1247 break;
1248 case XML_ATTRIBUTE_IDREF:
1249 xmlBufferWriteChar(buf, " IDREF");
1250 break;
1251 case XML_ATTRIBUTE_IDREFS:
1252 xmlBufferWriteChar(buf, " IDREFS");
1253 break;
1254 case XML_ATTRIBUTE_ENTITY:
1255 xmlBufferWriteChar(buf, " ENTITY");
1256 break;
1257 case XML_ATTRIBUTE_ENTITIES:
1258 xmlBufferWriteChar(buf, " ENTITIES");
1259 break;
1260 case XML_ATTRIBUTE_NMTOKEN:
1261 xmlBufferWriteChar(buf, " NMTOKEN");
1262 break;
1263 case XML_ATTRIBUTE_NMTOKENS:
1264 xmlBufferWriteChar(buf, " NMTOKENS");
1265 break;
1266 case XML_ATTRIBUTE_ENUMERATION:
1267 xmlBufferWriteChar(buf, " (");
1268 xmlDumpEnumeration(buf, attr->tree);
1269 break;
1270 case XML_ATTRIBUTE_NOTATION:
1271 xmlBufferWriteChar(buf, " NOTATION (");
1272 xmlDumpEnumeration(buf, attr->tree);
1273 break;
1274 default:
1275 fprintf(stderr,
1276 "xmlDumpAttributeTable: internal: unknown type %d\n",
1277 attr->atype);
1278 }
1279 switch (attr->def) {
1280 case XML_ATTRIBUTE_NONE:
1281 break;
1282 case XML_ATTRIBUTE_REQUIRED:
1283 xmlBufferWriteChar(buf, " #REQUIRED");
1284 break;
1285 case XML_ATTRIBUTE_IMPLIED:
1286 xmlBufferWriteChar(buf, " #IMPLIED");
1287 break;
1288 case XML_ATTRIBUTE_FIXED:
1289 xmlBufferWriteChar(buf, " #FIXED");
1290 break;
1291 default:
1292 fprintf(stderr,
1293 "xmlDumpAttributeTable: internal: unknown default %d\n",
1294 attr->def);
1295 }
1296 if (attr->defaultValue != NULL) {
1297 xmlBufferWriteChar(buf, " ");
1298 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1299 }
1300 xmlBufferWriteChar(buf, ">\n");
1301}
1302
1303/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001304 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001305 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001306 * @table: An attribute table
1307 *
1308 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001309 */
1310void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001311xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001312 int i;
1313 xmlAttributePtr cur;
1314
1315 if (table == NULL) return;
1316
1317 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001318 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001319 xmlDumpAttributeDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001320 }
1321}
1322
1323/************************************************************************
1324 * *
1325 * NOTATIONs *
1326 * *
1327 ************************************************************************/
1328/**
1329 * xmlCreateNotationTable:
1330 *
1331 * create and initialize an empty notation hash table.
1332 *
1333 * Returns the xmlNotationTablePtr just created or NULL in case
1334 * of error.
1335 */
1336xmlNotationTablePtr
1337xmlCreateNotationTable(void) {
1338 xmlNotationTablePtr ret;
1339
1340 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001341 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001342 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001343 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001344 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001345 return(NULL);
1346 }
1347 ret->max_notations = XML_MIN_NOTATION_TABLE;
1348 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001349 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001350 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001351 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001352 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001353 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001354 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001355 return(NULL);
1356 }
1357 return(ret);
1358}
1359
1360
1361/**
1362 * xmlAddNotationDecl:
1363 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001364 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001365 * @name: the entity name
1366 * @PublicID: the public identifier or NULL
1367 * @SystemID: the system identifier or NULL
1368 *
1369 * Register a new notation declaration
1370 *
1371 * Returns NULL if not, othervise the entity
1372 */
1373xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001374xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1375 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001376 xmlNotationPtr ret, cur;
1377 xmlNotationTablePtr table;
1378 int i;
1379
1380 if (dtd == NULL) {
1381 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1382 return(NULL);
1383 }
1384 if (name == NULL) {
1385 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1386 return(NULL);
1387 }
1388 if ((PublicID == NULL) && (SystemID == NULL)) {
1389 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1390 }
1391
1392 /*
1393 * Create the Notation table if needed.
1394 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001395 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001396 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001397 dtd->notations = table = xmlCreateNotationTable();
Daniel Veillard1e346af1999-02-22 10:33:01 +00001398 if (table == NULL) {
1399 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1400 return(NULL);
1401 }
1402
1403 /*
1404 * Validity Check:
1405 * Search the DTD for previous declarations of the ATTLIST
1406 */
1407 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001408 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001409 if (!xmlStrcmp(cur->name, name)) {
1410 /*
1411 * The notation is already defined in this Dtd.
1412 */
1413 fprintf(stderr,
1414 "xmlAddNotationDecl: %s already defined\n", name);
1415 }
1416 }
1417
1418 /*
1419 * Grow the table, if needed.
1420 */
1421 if (table->nb_notations >= table->max_notations) {
1422 /*
1423 * need more notations.
1424 */
1425 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001426 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001427 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001428 sizeof(xmlNotationPtr));
1429 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001430 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1431 return(NULL);
1432 }
1433 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001434 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001435 if (ret == NULL) {
1436 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1437 return(NULL);
1438 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001439 memset(ret, 0, sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001440 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001441
1442 /*
1443 * fill the structure.
1444 */
1445 ret->name = xmlStrdup(name);
1446 if (SystemID != NULL)
1447 ret->SystemID = xmlStrdup(SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001448 if (PublicID != NULL)
1449 ret->PublicID = xmlStrdup(PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001450 table->nb_notations++;
1451
1452 return(ret);
1453}
1454
1455/**
1456 * xmlFreeNotation:
1457 * @not: A notation
1458 *
1459 * Deallocate the memory used by an notation definition
1460 */
1461void
1462xmlFreeNotation(xmlNotationPtr nota) {
1463 if (nota == NULL) return;
1464 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001465 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001466 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001467 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001468 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001469 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001470 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001471 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001472}
1473
1474/**
1475 * xmlFreeNotationTable:
1476 * @table: An notation table
1477 *
1478 * Deallocate the memory used by an entities hash table.
1479 */
1480void
1481xmlFreeNotationTable(xmlNotationTablePtr table) {
1482 int i;
1483
1484 if (table == NULL) return;
1485
1486 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001487 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001488 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001489 xmlFree(table->table);
1490 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001491}
1492
1493/**
1494 * xmlCopyNotationTable:
1495 * @table: A notation table
1496 *
1497 * Build a copy of a notation table.
1498 *
1499 * Returns the new xmlNotationTablePtr or NULL in case of error.
1500 */
1501xmlNotationTablePtr
1502xmlCopyNotationTable(xmlNotationTablePtr table) {
1503 xmlNotationTablePtr ret;
1504 xmlNotationPtr cur, nota;
1505 int i;
1506
Daniel Veillard6454aec1999-09-02 22:04:43 +00001507 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001508 if (ret == NULL) {
1509 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1510 return(NULL);
1511 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001512 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001513 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001514 if (ret->table == NULL) {
1515 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001516 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001517 return(NULL);
1518 }
1519 ret->max_notations = table->max_notations;
1520 ret->nb_notations = table->nb_notations;
1521 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001522 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001523 if (cur == NULL) {
1524 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001525 xmlFree(ret);
1526 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001527 return(NULL);
1528 }
1529 ret->table[i] = cur;
1530 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001531 if (nota->name != NULL)
1532 cur->name = xmlStrdup(nota->name);
1533 else
1534 cur->name = NULL;
1535 if (nota->PublicID != NULL)
1536 cur->PublicID = xmlStrdup(nota->PublicID);
1537 else
1538 cur->PublicID = NULL;
1539 if (nota->SystemID != NULL)
1540 cur->SystemID = xmlStrdup(nota->SystemID);
1541 else
1542 cur->SystemID = NULL;
1543 }
1544 return(ret);
1545}
1546
1547/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001548 * xmlDumpNotationDecl:
1549 * @buf: the XML buffer output
1550 * @nota: A notation declaration
1551 *
1552 * This will dump the content the notation declaration as an XML DTD definition
1553 */
1554void
1555xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
1556 xmlBufferWriteChar(buf, "<!NOTATION ");
1557 xmlBufferWriteCHAR(buf, nota->name);
1558 if (nota->PublicID != NULL) {
1559 xmlBufferWriteChar(buf, " PUBLIC ");
1560 xmlBufferWriteQuotedString(buf, nota->PublicID);
1561 if (nota->SystemID != NULL) {
1562 xmlBufferWriteChar(buf, " ");
1563 xmlBufferWriteCHAR(buf, nota->SystemID);
1564 }
1565 } else {
1566 xmlBufferWriteChar(buf, " SYSTEM ");
1567 xmlBufferWriteCHAR(buf, nota->SystemID);
1568 }
1569 xmlBufferWriteChar(buf, " >\n");
1570}
1571
1572/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001573 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001574 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001575 * @table: A notation table
1576 *
1577 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001578 */
1579void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001580xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001581 int i;
1582 xmlNotationPtr cur;
1583
1584 if (table == NULL) return;
1585
1586 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001587 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001588 xmlDumpNotationDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001589 }
1590}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001591
1592/************************************************************************
1593 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001594 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001595 * *
1596 ************************************************************************/
1597/**
1598 * xmlCreateIDTable:
1599 *
1600 * create and initialize an empty id hash table.
1601 *
1602 * Returns the xmlIDTablePtr just created or NULL in case
1603 * of error.
1604 */
1605xmlIDTablePtr
1606xmlCreateIDTable(void) {
1607 xmlIDTablePtr ret;
1608
1609 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001610 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001611 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001612 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001613 (long)sizeof(xmlIDTable));
1614 return(NULL);
1615 }
1616 ret->max_ids = XML_MIN_NOTATION_TABLE;
1617 ret->nb_ids = 0;
1618 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001619 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001620 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001621 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001622 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001623 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001624 return(NULL);
1625 }
1626 return(ret);
1627}
1628
1629
1630/**
1631 * xmlAddID:
1632 * @ctxt: the validation context
1633 * @doc: pointer to the document
1634 * @value: the value name
1635 * @attr: the attribute holding the ID
1636 *
1637 * Register a new id declaration
1638 *
1639 * Returns NULL if not, othervise the new xmlIDPtr
1640 */
1641xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001642xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001643 xmlAttrPtr attr) {
1644 xmlIDPtr ret, cur;
1645 xmlIDTablePtr table;
1646 int i;
1647
1648 if (doc == NULL) {
1649 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1650 return(NULL);
1651 }
1652 if (value == NULL) {
1653 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1654 return(NULL);
1655 }
1656 if (attr == NULL) {
1657 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1658 return(NULL);
1659 }
1660
1661 /*
1662 * Create the ID table if needed.
1663 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001664 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001665 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001666 doc->ids = table = xmlCreateIDTable();
Daniel Veillard991e63d1999-08-15 23:32:28 +00001667 if (table == NULL) {
1668 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1669 return(NULL);
1670 }
1671
1672 /*
1673 * Validity Check:
1674 * Search the DTD for previous declarations of the ATTLIST
1675 */
1676 for (i = 0;i < table->nb_ids;i++) {
1677 cur = table->table[i];
1678 if (!xmlStrcmp(cur->value, value)) {
1679 /*
1680 * The id is already defined in this Dtd.
1681 */
1682 VERROR(ctxt->userData, "ID %s already defined\n", value);
1683 return(NULL);
1684 }
1685 }
1686
1687 /*
1688 * Grow the table, if needed.
1689 */
1690 if (table->nb_ids >= table->max_ids) {
1691 /*
1692 * need more ids.
1693 */
1694 table->max_ids *= 2;
1695 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001696 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001697 sizeof(xmlIDPtr));
1698 if (table->table == NULL) {
1699 fprintf(stderr, "xmlAddID: out of memory\n");
1700 return(NULL);
1701 }
1702 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001703 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001704 if (ret == NULL) {
1705 fprintf(stderr, "xmlAddID: out of memory\n");
1706 return(NULL);
1707 }
1708 table->table[table->nb_ids] = ret;
1709
1710 /*
1711 * fill the structure.
1712 */
1713 ret->value = xmlStrdup(value);
1714 ret->attr = attr;
1715 table->nb_ids++;
1716
1717 return(ret);
1718}
1719
1720/**
1721 * xmlFreeID:
1722 * @not: A id
1723 *
1724 * Deallocate the memory used by an id definition
1725 */
1726void
1727xmlFreeID(xmlIDPtr id) {
1728 if (id == NULL) return;
1729 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001730 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001731 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001732 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001733}
1734
1735/**
1736 * xmlFreeIDTable:
1737 * @table: An id table
1738 *
1739 * Deallocate the memory used by an ID hash table.
1740 */
1741void
1742xmlFreeIDTable(xmlIDTablePtr table) {
1743 int i;
1744
1745 if (table == NULL) return;
1746
1747 for (i = 0;i < table->nb_ids;i++) {
1748 xmlFreeID(table->table[i]);
1749 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001750 xmlFree(table->table);
1751 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001752}
1753
1754/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001755 * xmlIsID:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001756 * @doc: the document
1757 * @elem: the element carrying the attribute
1758 * @attr: the attribute
1759 *
1760 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1761 * then this is simple, otherwise we use an heuristic: name ID (upper
1762 * or lowercase).
1763 *
1764 * Returns 0 or 1 depending on the lookup result
1765 */
1766int
1767xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00001768 if (doc == NULL) return(0);
1769 if (attr == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001770 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1771 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1772 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1773 (attr->name[2] == 0)) return(1);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001774 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1775 if ((!xmlStrcmp(BAD_CAST "id", attr->name)) ||
1776 (!xmlStrcmp(BAD_CAST "name", attr->name)))
1777 return(1);
1778 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001779 } else {
1780 xmlAttributePtr attrDecl;
1781
Daniel Veillard71b656e2000-01-05 14:46:17 +00001782 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001783 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1784 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1785 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1786 attr->name);
1787
Daniel Veillardcf461992000-03-14 18:30:20 +00001788 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001789 return(1);
1790 }
1791 return(0);
1792}
1793
Daniel Veillardb96e6431999-08-29 21:02:19 +00001794/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001795 * xmlRemoveID
1796 * @doc: the document
1797 * @attr: the attribute
1798 *
1799 * Remove the given attribute from the ID table maintained internally.
1800 *
1801 * Returns -1 if the lookup failed and 0 otherwise
1802 */
1803int
1804xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1805 xmlIDPtr cur;
1806 xmlIDTablePtr table;
1807 int i;
1808
1809 if (doc == NULL) return(-1);
1810 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001811 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001812 if (table == NULL)
1813 return(-1);
1814
1815 /*
1816 * Search the ID list.
1817 */
1818 for (i = 0;i < table->nb_ids;i++) {
1819 cur = table->table[i];
1820 if (cur->attr == attr) {
1821 table->nb_ids--;
1822 memmove(&table->table[i], &table->table[i+1],
1823 (table->nb_ids - i) * sizeof(xmlIDPtr));
1824 return(0);
1825 }
1826 }
1827 return(-1);
1828}
1829
1830/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001831 * xmlGetID:
1832 * @doc: pointer to the document
1833 * @ID: the ID value
1834 *
1835 * Search the attribute declaring the given ID
1836 *
1837 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1838 */
1839xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001840xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001841 xmlIDPtr cur;
1842 xmlIDTablePtr table;
1843 int i;
1844
1845 if (doc == NULL) {
1846 fprintf(stderr, "xmlGetID: doc == NULL\n");
1847 return(NULL);
1848 }
1849
1850 if (ID == NULL) {
1851 fprintf(stderr, "xmlGetID: ID == NULL\n");
1852 return(NULL);
1853 }
1854
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001855 table = (xmlIDTablePtr) doc->ids;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001856 if (table == NULL)
1857 return(NULL);
1858
1859 /*
1860 * Search the ID list.
1861 */
1862 for (i = 0;i < table->nb_ids;i++) {
1863 cur = table->table[i];
1864 if (!xmlStrcmp(cur->value, ID)) {
1865 return(cur->attr);
1866 }
1867 }
1868 return(NULL);
1869}
1870
Daniel Veillard991e63d1999-08-15 23:32:28 +00001871/************************************************************************
1872 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001873 * Refs *
1874 * *
1875 ************************************************************************/
1876/**
1877 * xmlCreateRefTable:
1878 *
1879 * create and initialize an empty ref hash table.
1880 *
1881 * Returns the xmlRefTablePtr just created or NULL in case
1882 * of error.
1883 */
1884xmlRefTablePtr
1885xmlCreateRefTable(void) {
1886 xmlRefTablePtr ret;
1887
1888 ret = (xmlRefTablePtr)
1889 xmlMalloc(sizeof(xmlRefTable));
1890 if (ret == NULL) {
1891 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1892 (long)sizeof(xmlRefTable));
1893 return(NULL);
1894 }
1895 ret->max_refs = XML_MIN_NOTATION_TABLE;
1896 ret->nb_refs = 0;
1897 ret->table = (xmlRefPtr *)
1898 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1899 if (ret == NULL) {
1900 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1901 ret->max_refs * (long)sizeof(xmlRef));
1902 xmlFree(ret);
1903 return(NULL);
1904 }
1905 return(ret);
1906}
1907
1908
1909/**
1910 * xmlAddRef:
1911 * @ctxt: the validation context
1912 * @doc: pointer to the document
1913 * @value: the value name
1914 * @attr: the attribute holding the Ref
1915 *
1916 * Register a new ref declaration
1917 *
1918 * Returns NULL if not, othervise the new xmlRefPtr
1919 */
1920xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001921xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001922 xmlAttrPtr attr) {
1923 xmlRefPtr ret;
1924 xmlRefTablePtr table;
1925
1926 if (doc == NULL) {
1927 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1928 return(NULL);
1929 }
1930 if (value == NULL) {
1931 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1932 return(NULL);
1933 }
1934 if (attr == NULL) {
1935 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1936 return(NULL);
1937 }
1938
1939 /*
1940 * Create the Ref table if needed.
1941 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001942 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001943 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001944 doc->refs = table = xmlCreateRefTable();
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001945 if (table == NULL) {
1946 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1947 return(NULL);
1948 }
1949
1950 /*
1951 * Grow the table, if needed.
1952 */
1953 if (table->nb_refs >= table->max_refs) {
1954 /*
1955 * need more refs.
1956 */
1957 table->max_refs *= 2;
1958 table->table = (xmlRefPtr *)
1959 xmlRealloc(table->table, table->max_refs *
1960 sizeof(xmlRefPtr));
1961 if (table->table == NULL) {
1962 fprintf(stderr, "xmlAddRef: out of memory\n");
1963 return(NULL);
1964 }
1965 }
1966 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1967 if (ret == NULL) {
1968 fprintf(stderr, "xmlAddRef: out of memory\n");
1969 return(NULL);
1970 }
1971 table->table[table->nb_refs] = ret;
1972
1973 /*
1974 * fill the structure.
1975 */
1976 ret->value = xmlStrdup(value);
1977 ret->attr = attr;
1978 table->nb_refs++;
1979
1980 return(ret);
1981}
1982
1983/**
1984 * xmlFreeRef:
1985 * @not: A ref
1986 *
1987 * Deallocate the memory used by an ref definition
1988 */
1989void
1990xmlFreeRef(xmlRefPtr ref) {
1991 if (ref == NULL) return;
1992 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001993 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001994 memset(ref, -1, sizeof(xmlRef));
1995 xmlFree(ref);
1996}
1997
1998/**
1999 * xmlFreeRefTable:
2000 * @table: An ref table
2001 *
2002 * Deallocate the memory used by an Ref hash table.
2003 */
2004void
2005xmlFreeRefTable(xmlRefTablePtr table) {
2006 int i;
2007
2008 if (table == NULL) return;
2009
2010 for (i = 0;i < table->nb_refs;i++) {
2011 xmlFreeRef(table->table[i]);
2012 }
2013 xmlFree(table->table);
2014 xmlFree(table);
2015}
2016
2017/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002018 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002019 * @doc: the document
2020 * @elem: the element carrying the attribute
2021 * @attr: the attribute
2022 *
2023 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
2024 * then this is simple, otherwise we use an heuristic: name Ref (upper
2025 * or lowercase).
2026 *
2027 * Returns 0 or 1 depending on the lookup result
2028 */
2029int
2030xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2031 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2032 return(0);
2033 /*******************
2034 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
2035 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
2036 (attr->name[2] == 0)) return(1);
2037 *******************/
Daniel Veillardd83eb822000-06-30 18:39:56 +00002038 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2039 /* TODO @@@ */
2040 return(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002041 } else {
2042 xmlAttributePtr attrDecl;
2043
2044 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2045 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2046 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2047 attr->name);
2048
Daniel Veillardcf461992000-03-14 18:30:20 +00002049 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002050 return(1);
2051 }
2052 return(0);
2053}
2054
2055/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002056 * xmlRemoveRef
2057 * @doc: the document
2058 * @attr: the attribute
2059 *
2060 * Remove the given attribute from the Ref table maintained internally.
2061 *
2062 * Returns -1 if the lookup failed and 0 otherwise
2063 */
2064int
2065xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2066 xmlRefPtr cur;
2067 xmlRefTablePtr table;
2068 int i;
2069
2070 if (doc == NULL) return(-1);
2071 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002072 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard71b656e2000-01-05 14:46:17 +00002073 if (table == NULL)
2074 return(-1);
2075
2076 /*
2077 * Search the Ref list.
2078 */
2079 for (i = 0;i < table->nb_refs;i++) {
2080 cur = table->table[i];
2081 if (cur->attr == attr) {
2082 table->nb_refs--;
2083 memmove(&table->table[i], &table->table[i+1],
2084 (table->nb_refs - i) * sizeof(xmlRefPtr));
2085 return(0);
2086 }
2087 }
2088 return(-1);
2089}
2090
2091/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002092 * xmlGetRef:
2093 * @doc: pointer to the document
2094 * @Ref: the Ref value
2095 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00002096 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002097 *
2098 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
2099 */
2100xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002101xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002102 xmlRefPtr cur;
2103 xmlRefTablePtr table;
2104 int i;
2105
2106 if (doc == NULL) {
2107 fprintf(stderr, "xmlGetRef: doc == NULL\n");
2108 return(NULL);
2109 }
2110
2111 if (Ref == NULL) {
2112 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
2113 return(NULL);
2114 }
2115
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002116 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002117 if (table == NULL)
2118 return(NULL);
2119
2120 /*
2121 * Search the Ref list.
2122 */
2123 for (i = 0;i < table->nb_refs;i++) {
2124 cur = table->table[i];
2125 if (!xmlStrcmp(cur->value, Ref)) {
2126 return(cur->attr);
2127 }
2128 }
2129 return(NULL);
2130}
2131
2132/************************************************************************
2133 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002134 * Routines for validity checking *
2135 * *
2136 ************************************************************************/
2137
2138/**
2139 * xmlGetDtdElementDesc:
2140 * @dtd: a pointer to the DtD to search
2141 * @name: the element name
2142 *
2143 * Search the Dtd for the description of this element
2144 *
2145 * returns the xmlElementPtr if found or NULL
2146 */
2147
2148xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002149xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002150 xmlElementTablePtr table;
2151 xmlElementPtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002152 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002153 int i;
2154
2155 if (dtd == NULL) return(NULL);
2156 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002157 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002158
2159 for (i = 0;i < table->nb_elements;i++) {
2160 cur = table->table[i];
2161 if (!xmlStrcmp(cur->name, name))
2162 return(cur);
2163 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002164
2165 /*
2166 * Specific case if name is a QName.
2167 */
2168 uqname = xmlSplitQName2(name, &prefix);
2169 if (uqname == NULL) return(NULL);
2170
2171 for (i = 0;i < table->nb_elements;i++) {
2172 cur = table->table[i];
2173 if ((!xmlStrcmp(cur->name, uqname)) &&
2174 ((prefix == cur->prefix) ||
2175 ((prefix != NULL) && (cur->prefix != NULL) &&
2176 (!xmlStrcmp(cur->prefix, prefix))))) {
2177 if (prefix != NULL) xmlFree(prefix);
2178 if (uqname != NULL) xmlFree(uqname);
2179 return(cur);
2180 }
2181 }
2182 if (prefix != NULL) xmlFree(prefix);
2183 if (uqname != NULL) xmlFree(uqname);
2184 return(NULL);
2185}
2186
2187/**
2188 * xmlGetDtdQElementDesc:
2189 * @dtd: a pointer to the DtD to search
2190 * @name: the element name
2191 * @prefix: the element namespace prefix
2192 *
2193 * Search the Dtd for the description of this element
2194 *
2195 * returns the xmlElementPtr if found or NULL
2196 */
2197
2198xmlElementPtr
2199xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2200 const xmlChar *prefix) {
2201 xmlElementTablePtr table;
2202 xmlElementPtr cur;
2203 int i;
2204
2205 if (dtd == NULL) return(NULL);
2206 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002207 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardbe803962000-06-28 23:40:59 +00002208
2209 for (i = 0;i < table->nb_elements;i++) {
2210 cur = table->table[i];
2211 if (!xmlStrcmp(cur->name, name) &&
2212 ((prefix == cur->prefix) ||
2213 ((prefix != NULL) && (cur->prefix != NULL) &&
2214 (!xmlStrcmp(cur->prefix, prefix)))))
2215 return(cur);
2216 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002217 return(NULL);
2218}
2219
2220/**
2221 * xmlGetDtdAttrDesc:
2222 * @dtd: a pointer to the DtD to search
2223 * @elem: the element name
2224 * @name: the attribute name
2225 *
2226 * Search the Dtd for the description of this attribute on
2227 * this element.
2228 *
2229 * returns the xmlAttributePtr if found or NULL
2230 */
2231
2232xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002233xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002234 xmlAttributeTablePtr table;
2235 xmlAttributePtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002236 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002237 int i;
2238
2239 if (dtd == NULL) return(NULL);
2240 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002241 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002242
2243 for (i = 0;i < table->nb_attributes;i++) {
2244 cur = table->table[i];
2245 if ((!xmlStrcmp(cur->name, name)) &&
2246 (!xmlStrcmp(cur->elem, elem)))
2247 return(cur);
2248 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002249
2250 /*
2251 * Specific case if name is a QName.
2252 */
2253 uqname = xmlSplitQName2(name, &prefix);
2254 if (uqname == NULL) return(NULL);
2255
2256 for (i = 0;i < table->nb_attributes;i++) {
2257 cur = table->table[i];
2258 if ((!xmlStrcmp(cur->name, uqname)) &&
2259 (!xmlStrcmp(cur->elem, elem)) &&
2260 ((prefix == cur->prefix) ||
2261 ((prefix != NULL) && (cur->prefix != NULL) &&
2262 (!xmlStrcmp(cur->prefix, prefix))))) {
2263 if (prefix != NULL) xmlFree(prefix);
2264 if (uqname != NULL) xmlFree(uqname);
2265 return(cur);
2266 }
2267 }
2268 if (prefix != NULL) xmlFree(prefix);
2269 if (uqname != NULL) xmlFree(uqname);
2270 return(NULL);
2271}
2272
2273/**
2274 * xmlGetDtdQAttrDesc:
2275 * @dtd: a pointer to the DtD to search
2276 * @elem: the element name
2277 * @name: the attribute name
2278 * @prefix: the attribute namespace prefix
2279 *
2280 * Search the Dtd for the description of this qualified attribute on
2281 * this element.
2282 *
2283 * returns the xmlAttributePtr if found or NULL
2284 */
2285
2286xmlAttributePtr
2287xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2288 const xmlChar *prefix) {
2289 xmlAttributeTablePtr table;
2290 xmlAttributePtr cur;
2291 int i;
2292
2293 if (dtd == NULL) return(NULL);
2294 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002295 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardbe803962000-06-28 23:40:59 +00002296
2297 for (i = 0;i < table->nb_attributes;i++) {
2298 cur = table->table[i];
2299 if ((!xmlStrcmp(cur->name, name)) &&
2300 (!xmlStrcmp(cur->elem, elem)) &&
2301 ((prefix == cur->prefix) ||
2302 ((prefix != NULL) && (cur->prefix != NULL) &&
2303 (!xmlStrcmp(cur->prefix, prefix)))))
2304 return(cur);
2305 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002306 return(NULL);
2307}
2308
2309/**
2310 * xmlGetDtdNotationDesc:
2311 * @dtd: a pointer to the DtD to search
2312 * @name: the notation name
2313 *
2314 * Search the Dtd for the description of this notation
2315 *
2316 * returns the xmlNotationPtr if found or NULL
2317 */
2318
2319xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002320xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002321 xmlNotationTablePtr table;
2322 xmlNotationPtr cur;
2323 int i;
2324
2325 if (dtd == NULL) return(NULL);
2326 if (dtd->notations == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002327 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002328
2329 for (i = 0;i < table->nb_notations;i++) {
2330 cur = table->table[i];
2331 if (!xmlStrcmp(cur->name, name))
2332 return(cur);
2333 }
2334 return(NULL);
2335}
2336
2337/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002338 * xmlValidateNotationUse:
2339 * @ctxt: the validation context
2340 * @doc: the document
2341 * @notationName: the notation name to check
2342 *
2343 * Validate that the given mame match a notation declaration.
2344 * - [ VC: Notation Declared ]
2345 *
2346 * returns 1 if valid or 0 otherwise
2347 */
2348
2349int
2350xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002351 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002352 xmlNotationPtr notaDecl;
2353 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2354
2355 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2356 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2357 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2358
2359 if (notaDecl == NULL) {
2360 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2361 notationName);
2362 return(0);
2363 }
2364 return(1);
2365}
2366
2367/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002368 * xmlIsMixedElement
2369 * @doc: the document
2370 * @name: the element name
2371 *
2372 * Search in the DtDs whether an element accept Mixed content (or ANY)
2373 * basically if it is supposed to accept text childs
2374 *
2375 * returns 0 if no, 1 if yes, and -1 if no element description is available
2376 */
2377
2378int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002379xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002380 xmlElementPtr elemDecl;
2381
2382 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2383
2384 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2385 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2386 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2387 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002388 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002389 case XML_ELEMENT_TYPE_ELEMENT:
2390 return(0);
2391 case XML_ELEMENT_TYPE_EMPTY:
2392 /*
2393 * return 1 for EMPTY since we want VC error to pop up
2394 * on <empty> </empty> for example
2395 */
2396 case XML_ELEMENT_TYPE_ANY:
2397 case XML_ELEMENT_TYPE_MIXED:
2398 return(1);
2399 }
2400 return(1);
2401}
2402
2403/**
2404 * xmlValidateNameValue:
2405 * @value: an Name value
2406 *
2407 * Validate that the given value match Name production
2408 *
2409 * returns 1 if valid or 0 otherwise
2410 */
2411
2412int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002413xmlValidateNameValue(const xmlChar *value) {
2414 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002415
2416 if (value == NULL) return(0);
2417 cur = value;
2418
2419 if (!IS_LETTER(*cur) && (*cur != '_') &&
2420 (*cur != ':')) {
2421 return(0);
2422 }
2423
2424 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2425 (*cur == '.') || (*cur == '-') ||
2426 (*cur == '_') || (*cur == ':') ||
2427 (IS_COMBINING(*cur)) ||
2428 (IS_EXTENDER(*cur)))
2429 cur++;
2430
2431 if (*cur != 0) return(0);
2432
2433 return(1);
2434}
2435
2436/**
2437 * xmlValidateNamesValue:
2438 * @value: an Names value
2439 *
2440 * Validate that the given value match Names production
2441 *
2442 * returns 1 if valid or 0 otherwise
2443 */
2444
2445int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002446xmlValidateNamesValue(const xmlChar *value) {
2447 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002448
2449 if (value == NULL) return(0);
2450 cur = value;
2451
2452 if (!IS_LETTER(*cur) && (*cur != '_') &&
2453 (*cur != ':')) {
2454 return(0);
2455 }
2456
2457 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2458 (*cur == '.') || (*cur == '-') ||
2459 (*cur == '_') || (*cur == ':') ||
2460 (IS_COMBINING(*cur)) ||
2461 (IS_EXTENDER(*cur)))
2462 cur++;
2463
2464 while (IS_BLANK(*cur)) {
2465 while (IS_BLANK(*cur)) cur++;
2466
2467 if (!IS_LETTER(*cur) && (*cur != '_') &&
2468 (*cur != ':')) {
2469 return(0);
2470 }
2471
2472 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2473 (*cur == '.') || (*cur == '-') ||
2474 (*cur == '_') || (*cur == ':') ||
2475 (IS_COMBINING(*cur)) ||
2476 (IS_EXTENDER(*cur)))
2477 cur++;
2478 }
2479
2480 if (*cur != 0) return(0);
2481
2482 return(1);
2483}
2484
2485/**
2486 * xmlValidateNmtokenValue:
2487 * @value: an Mntoken value
2488 *
2489 * Validate that the given value match Nmtoken production
2490 *
2491 * [ VC: Name Token ]
2492 *
2493 * returns 1 if valid or 0 otherwise
2494 */
2495
2496int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002497xmlValidateNmtokenValue(const xmlChar *value) {
2498 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002499
2500 if (value == NULL) return(0);
2501 cur = value;
2502
2503 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2504 (*cur != '.') && (*cur != '-') &&
2505 (*cur != '_') && (*cur != ':') &&
2506 (!IS_COMBINING(*cur)) &&
2507 (!IS_EXTENDER(*cur)))
2508 return(0);
2509
2510 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2511 (*cur == '.') || (*cur == '-') ||
2512 (*cur == '_') || (*cur == ':') ||
2513 (IS_COMBINING(*cur)) ||
2514 (IS_EXTENDER(*cur)))
2515 cur++;
2516
2517 if (*cur != 0) return(0);
2518
2519 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002520}
2521
2522/**
2523 * xmlValidateNmtokensValue:
2524 * @value: an Mntokens value
2525 *
2526 * Validate that the given value match Nmtokens production
2527 *
2528 * [ VC: Name Token ]
2529 *
2530 * returns 1 if valid or 0 otherwise
2531 */
2532
2533int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002534xmlValidateNmtokensValue(const xmlChar *value) {
2535 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002536
2537 if (value == NULL) return(0);
2538 cur = value;
2539
Daniel Veillardcf461992000-03-14 18:30:20 +00002540 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002541 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2542 (*cur != '.') && (*cur != '-') &&
2543 (*cur != '_') && (*cur != ':') &&
2544 (!IS_COMBINING(*cur)) &&
2545 (!IS_EXTENDER(*cur)))
2546 return(0);
2547
2548 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2549 (*cur == '.') || (*cur == '-') ||
2550 (*cur == '_') || (*cur == ':') ||
2551 (IS_COMBINING(*cur)) ||
2552 (IS_EXTENDER(*cur)))
2553 cur++;
2554
2555 while (IS_BLANK(*cur)) {
2556 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002557 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002558
2559 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2560 (*cur != '.') && (*cur != '-') &&
2561 (*cur != '_') && (*cur != ':') &&
2562 (!IS_COMBINING(*cur)) &&
2563 (!IS_EXTENDER(*cur)))
2564 return(0);
2565
2566 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2567 (*cur == '.') || (*cur == '-') ||
2568 (*cur == '_') || (*cur == ':') ||
2569 (IS_COMBINING(*cur)) ||
2570 (IS_EXTENDER(*cur)))
2571 cur++;
2572 }
2573
2574 if (*cur != 0) return(0);
2575
2576 return(1);
2577}
2578
2579/**
2580 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002581 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002582 * @doc: a document instance
2583 * @nota: a notation definition
2584 *
2585 * Try to validate a single notation definition
2586 * basically it does the following checks as described by the
2587 * XML-1.0 recommendation:
2588 * - it seems that no validity constraing exist on notation declarations
2589 * But this function get called anyway ...
2590 *
2591 * returns 1 if valid or 0 otherwise
2592 */
2593
2594int
2595xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2596 xmlNotationPtr nota) {
2597 int ret = 1;
2598
2599 return(ret);
2600}
2601
2602/**
2603 * xmlValidateAttributeValue:
2604 * @type: an attribute type
2605 * @value: an attribute value
2606 *
2607 * Validate that the given attribute value match the proper production
2608 *
2609 * [ VC: ID ]
2610 * Values of type ID must match the Name production....
2611 *
2612 * [ VC: IDREF ]
2613 * Values of type IDREF must match the Name production, and values
2614 * of type IDREFS must match Names ...
2615 *
2616 * [ VC: Entity Name ]
2617 * Values of type ENTITY must match the Name production, values
2618 * of type ENTITIES must match Names ...
2619 *
2620 * [ VC: Name Token ]
2621 * Values of type NMTOKEN must match the Nmtoken production; values
2622 * of type NMTOKENS must match Nmtokens.
2623 *
2624 * returns 1 if valid or 0 otherwise
2625 */
2626
2627int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002628xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002629 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002630 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002631 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002632 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002633 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002634 case XML_ATTRIBUTE_IDREF:
2635 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002636 case XML_ATTRIBUTE_NOTATION:
2637 return(xmlValidateNameValue(value));
2638 case XML_ATTRIBUTE_NMTOKENS:
2639 case XML_ATTRIBUTE_ENUMERATION:
2640 return(xmlValidateNmtokensValue(value));
2641 case XML_ATTRIBUTE_NMTOKEN:
2642 return(xmlValidateNmtokenValue(value));
2643 case XML_ATTRIBUTE_CDATA:
2644 break;
2645 }
2646 return(1);
2647}
2648
2649/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002650 * xmlValidateAttributeValue2:
2651 * @ctxt: the validation context
2652 * @doc: the document
2653 * @name: the attribute name (used for error reporting only)
2654 * @type: the attribute type
2655 * @value: the attribute value
2656 *
2657 * Validate that the given attribute value match a given type.
2658 * This typically cannot be done before having finished parsing
2659 * the subsets.
2660 *
2661 * [ VC: IDREF ]
2662 * Values of type IDREF must match one of the declared IDs
2663 * Values of type IDREFS must match a sequence of the declared IDs
2664 * each Name must match the value of an ID attribute on some element
2665 * in the XML document; i.e. IDREF values must match the value of
2666 * some ID attribute
2667 *
2668 * [ VC: Entity Name ]
2669 * Values of type ENTITY must match one declared entity
2670 * Values of type ENTITIES must match a sequence of declared entities
2671 *
2672 * [ VC: Notation Attributes ]
2673 * all notation names in the declaration must be declared.
2674 *
2675 * returns 1 if valid or 0 otherwise
2676 */
2677
2678int
2679xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2680 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2681 int ret = 1;
2682 switch (type) {
2683 case XML_ATTRIBUTE_IDREFS:
2684 case XML_ATTRIBUTE_IDREF:
2685 case XML_ATTRIBUTE_ID:
2686 case XML_ATTRIBUTE_NMTOKENS:
2687 case XML_ATTRIBUTE_ENUMERATION:
2688 case XML_ATTRIBUTE_NMTOKEN:
2689 case XML_ATTRIBUTE_CDATA:
2690 break;
2691 case XML_ATTRIBUTE_ENTITY: {
2692 xmlEntityPtr ent;
2693
2694 ent = xmlGetDocEntity(doc, value);
2695 if (ent == NULL) {
2696 VERROR(ctxt->userData,
2697 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2698 name, value);
2699 ret = 0;
2700 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2701 VERROR(ctxt->userData,
2702 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2703 name, value);
2704 ret = 0;
2705 }
2706 break;
2707 }
2708 case XML_ATTRIBUTE_ENTITIES: {
2709 xmlChar *dup, *nam = NULL, *cur, save;
2710 xmlEntityPtr ent;
2711
2712 dup = xmlStrdup(value);
2713 if (dup == NULL)
2714 return(0);
2715 cur = dup;
2716 while (*cur != 0) {
2717 nam = cur;
2718 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2719 save = *cur;
2720 *cur = 0;
2721 ent = xmlGetDocEntity(doc, nam);
2722 if (ent == NULL) {
2723 VERROR(ctxt->userData,
2724 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2725 name, nam);
2726 ret = 0;
2727 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2728 VERROR(ctxt->userData,
2729 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2730 name, nam);
2731 ret = 0;
2732 }
2733 if (save == 0)
2734 break;
2735 *cur = save;
2736 while (IS_BLANK(*cur)) cur++;
2737 }
2738 xmlFree(dup);
2739 break;
2740 }
2741 case XML_ATTRIBUTE_NOTATION: {
2742 xmlNotationPtr nota;
2743
2744 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2745 if ((nota == NULL) && (doc->extSubset != NULL))
2746 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2747
2748 if (nota == NULL) {
2749 VERROR(ctxt->userData,
2750 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2751 name, value);
2752 ret = 0;
2753 }
2754 break;
2755 }
2756 }
2757 return(ret);
2758}
2759
2760/**
2761 * xmlValidNormalizeAttributeValue:
2762 * @doc: the document
2763 * @elem: the parent
2764 * @name: the attribute name
2765 * @value: the attribute value
2766 *
2767 * Does the validation related extra step of the normalization of attribute
2768 * values:
2769 *
2770 * If the declared value is not CDATA, then the XML processor must further
2771 * process the normalized attribute value by discarding any leading and
2772 * trailing space (#x20) characters, and by replacing sequences of space
2773 * (#x20) characters by single space (#x20) character.
2774 *
2775 * returns a new normalized string if normalization is needed, NULL otherwise
2776 * the caller must free the returned value.
2777 */
2778
2779xmlChar *
2780xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2781 const xmlChar *name, const xmlChar *value) {
2782 xmlChar *ret, *dst;
2783 const xmlChar *src;
Daniel Veillardbe803962000-06-28 23:40:59 +00002784 xmlAttributePtr attrDecl = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002785
2786 if (doc == NULL) return(NULL);
2787 if (elem == NULL) return(NULL);
2788 if (name == NULL) return(NULL);
2789 if (value == NULL) return(NULL);
2790
Daniel Veillardbe803962000-06-28 23:40:59 +00002791 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2792 xmlChar qname[500];
2793#ifdef HAVE_SNPRINTF
2794 snprintf((char *) qname, sizeof(qname), "%s:%s",
2795 elem->ns->prefix, elem->name);
2796#else
2797 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
2798#endif
2799 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2800 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2801 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2802 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002803 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2804 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2805 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2806
2807 if (attrDecl == NULL)
2808 return(NULL);
2809 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2810 return(NULL);
2811
2812 ret = xmlStrdup(value);
2813 if (ret == NULL)
2814 return(NULL);
2815 src = value;
2816 dst = ret;
2817 while (*src == 0x20) src++;
2818 while (*src != 0) {
2819 if (*src == 0x20) {
2820 while (*src == 0x20) src++;
2821 if (*src != 0)
2822 *dst++ = 0x20;
2823 } else {
2824 *dst++ = *src++;
2825 }
2826 }
2827 *dst = 0;
2828 return(ret);
2829}
2830
2831/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002832 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002833 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002834 * @doc: a document instance
2835 * @attr: an attribute definition
2836 *
2837 * Try to validate a single attribute definition
2838 * basically it does the following checks as described by the
2839 * XML-1.0 recommendation:
2840 * - [ VC: Attribute Default Legal ]
2841 * - [ VC: Enumeration ]
2842 * - [ VC: ID Attribute Default ]
2843 *
2844 * The ID/IDREF uniqueness and matching are done separately
2845 *
2846 * returns 1 if valid or 0 otherwise
2847 */
2848
2849int
2850xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2851 xmlAttributePtr attr) {
2852 int ret = 1;
2853 int val;
2854 CHECK_DTD;
2855 if(attr == NULL) return(1);
2856
2857 /* Attribute Default Legal */
2858 /* Enumeration */
2859 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002860 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002861 if (val == 0) {
2862 VERROR(ctxt->userData,
2863 "Syntax of default value for attribute %s on %s is not valid\n",
2864 attr->name, attr->elem);
2865 }
2866 ret &= val;
2867 }
2868
2869 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002870 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002871 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2872 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2873 VERROR(ctxt->userData,
2874 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2875 attr->name, attr->elem);
2876 ret = 0;
2877 }
2878
Daniel Veillardb96e6431999-08-29 21:02:19 +00002879 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002880 if (attr->atype == XML_ATTRIBUTE_ID) {
2881 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002882
2883 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002884 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002885 attr->elem);
2886 if (elem != NULL) {
2887 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002888 } else {
2889 xmlAttributeTablePtr table;
2890 int i;
2891
2892 /*
2893 * The attribute may be declared in the internal subset and the
2894 * element in the external subset.
2895 */
2896 nbId = 0;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002897 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00002898 if (table != NULL) {
2899 for (i = 0;i < table->nb_attributes;i++) {
2900 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2901 (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2902 nbId++;
2903 }
2904 }
2905 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002906 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002907 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002908 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002909 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2910 attr->elem, nbId, attr->name);
2911 } else if (doc->extSubset != NULL) {
2912 int extId = 0;
2913 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2914 if (elem != NULL) {
2915 extId = xmlScanIDAttributeDecl(NULL, elem);
2916 }
2917 if (extId > 1) {
2918 VERROR(ctxt->userData,
2919 "Element %s has %d ID attribute defined in the external subset : %s\n",
2920 attr->elem, extId, attr->name);
2921 } else if (extId + nbId > 1) {
2922 VERROR(ctxt->userData,
2923"Element %s has ID attributes defined in the internal and external subset : %s\n",
2924 attr->elem, attr->name);
2925 }
2926 }
2927 }
2928
2929 /* Validity Constraint: Enumeration */
2930 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2931 xmlEnumerationPtr tree = attr->tree;
2932 while (tree != NULL) {
2933 if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2934 tree = tree->next;
2935 }
2936 if (tree == NULL) {
2937 VERROR(ctxt->userData,
2938"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2939 attr->defaultValue, attr->name, attr->elem);
2940 ret = 0;
2941 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002942 }
2943
2944 return(ret);
2945}
2946
2947/**
2948 * xmlValidateElementDecl:
2949 * @ctxt: the validation context
2950 * @doc: a document instance
2951 * @elem: an element definition
2952 *
2953 * Try to validate a single element definition
2954 * basically it does the following checks as described by the
2955 * XML-1.0 recommendation:
2956 * - [ VC: One ID per Element Type ]
2957 * - [ VC: No Duplicate Types ]
2958 * - [ VC: Unique Element Type Declaration ]
2959 *
2960 * returns 1 if valid or 0 otherwise
2961 */
2962
2963int
2964xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2965 xmlElementPtr elem) {
2966 int ret = 1;
2967 xmlElementPtr tst;
2968
2969 CHECK_DTD;
2970
2971 if (elem == NULL) return(1);
2972
2973 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00002974 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002975 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002976 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002977
2978 cur = elem->content;
2979 while (cur != NULL) {
2980 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2981 if (cur->c1 == NULL) break;
2982 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2983 name = cur->c1->name;
2984 next = cur->c2;
2985 while (next != NULL) {
2986 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2987 if (!xmlStrcmp(next->name, name)) {
2988 VERROR(ctxt->userData,
2989 "Definition of %s has duplicate references of %s\n",
2990 elem->name, name);
2991 ret = 0;
2992 }
2993 break;
2994 }
2995 if (next->c1 == NULL) break;
2996 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2997 if (!xmlStrcmp(next->c1->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 next = next->c2;
3004 }
3005 }
3006 cur = cur->c2;
3007 }
3008 }
3009
3010 /* VC: Unique Element Type Declaration */
3011 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3012 if ((tst != NULL ) && (tst != elem)) {
3013 VERROR(ctxt->userData, "Redefinition of element %s\n",
3014 elem->name);
3015 ret = 0;
3016 }
3017 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3018 if ((tst != NULL ) && (tst != elem)) {
3019 VERROR(ctxt->userData, "Redefinition of element %s\n",
3020 elem->name);
3021 ret = 0;
3022 }
3023
3024 /* One ID per Element Type */
3025 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3026 ret = 0;
3027 }
3028 return(ret);
3029}
3030
3031/**
3032 * xmlValidateOneAttribute:
3033 * @ctxt: the validation context
3034 * @doc: a document instance
3035 * @elem: an element instance
3036 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00003037 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003038 *
3039 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00003040 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00003041 * XML-1.0 recommendation:
3042 * - [ VC: Attribute Value Type ]
3043 * - [ VC: Fixed Attribute Default ]
3044 * - [ VC: Entity Name ]
3045 * - [ VC: Name Token ]
3046 * - [ VC: ID ]
3047 * - [ VC: IDREF ]
3048 * - [ VC: Entity Name ]
3049 * - [ VC: Notation Attributes ]
3050 *
3051 * The ID/IDREF uniqueness and matching are done separately
3052 *
3053 * returns 1 if valid or 0 otherwise
3054 */
3055
3056int
3057xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003058 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003059 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00003060 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003061 int val;
3062 int ret = 1;
3063
3064 CHECK_DTD;
3065 if ((elem == NULL) || (elem->name == NULL)) return(0);
3066 if ((attr == NULL) || (attr->name == NULL)) return(0);
3067
Daniel Veillardbe803962000-06-28 23:40:59 +00003068 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3069 xmlChar qname[500];
3070#ifdef HAVE_SNPRINTF
3071 snprintf((char *) qname, sizeof(qname), "%s:%s",
3072 elem->ns->prefix, elem->name);
3073#else
3074 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
3075#endif
3076 if (attr->ns != NULL) {
3077 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3078 attr->name, attr->ns->prefix);
3079 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3080 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3081 attr->name, attr->ns->prefix);
3082 } else {
3083 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3084 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3085 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3086 qname, attr->name);
3087 }
3088 }
3089 if (attrDecl == NULL) {
3090 if (attr->ns != NULL) {
3091 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3092 attr->name, attr->ns->prefix);
3093 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3094 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3095 attr->name, attr->ns->prefix);
3096 } else {
3097 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3098 elem->name, attr->name);
3099 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3100 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3101 elem->name, attr->name);
3102 }
3103 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003104
3105
3106 /* Validity Constraint: Attribute Value Type */
3107 if (attrDecl == NULL) {
3108 VERROR(ctxt->userData,
3109 "No declaration for attribute %s on element %s\n",
3110 attr->name, elem->name);
3111 return(0);
3112 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003113 attr->atype = attrDecl->atype;
3114
3115 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003116 if (val == 0) {
3117 VERROR(ctxt->userData,
3118 "Syntax of value for attribute %s on %s is not valid\n",
3119 attr->name, elem->name);
3120 ret = 0;
3121 }
3122
Daniel Veillardcf461992000-03-14 18:30:20 +00003123 /* Validity constraint: Fixed Attribute Default */
3124 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3125 if (xmlStrcmp(value, attrDecl->defaultValue)) {
3126 VERROR(ctxt->userData,
3127 "Value for attribute %s on %s is differnt from default \"%s\"\n",
3128 attr->name, elem->name, attrDecl->defaultValue);
3129 ret = 0;
3130 }
3131 }
3132
Daniel Veillardb96e6431999-08-29 21:02:19 +00003133 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00003134 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003135 xmlAddID(ctxt, doc, value, attr);
3136 }
3137
Daniel Veillardcf461992000-03-14 18:30:20 +00003138 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3139 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003140 xmlAddRef(ctxt, doc, value, attr);
3141 }
3142
Daniel Veillardb05deb71999-08-10 19:04:08 +00003143 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00003144 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003145 xmlEnumerationPtr tree = attrDecl->tree;
3146 xmlNotationPtr nota;
3147
3148 /* First check that the given NOTATION was declared */
3149 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3150 if (nota == NULL)
3151 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3152
3153 if (nota == NULL) {
3154 VERROR(ctxt->userData,
3155 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3156 value, attr->name, elem->name);
3157 ret = 0;
3158 }
3159
3160 /* Second, verify that it's among the list */
3161 while (tree != NULL) {
3162 if (!xmlStrcmp(tree->name, value)) break;
3163 tree = tree->next;
3164 }
3165 if (tree == NULL) {
3166 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003167"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003168 value, attr->name, elem->name);
3169 ret = 0;
3170 }
3171 }
3172
3173 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00003174 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003175 xmlEnumerationPtr tree = attrDecl->tree;
3176 while (tree != NULL) {
3177 if (!xmlStrcmp(tree->name, value)) break;
3178 tree = tree->next;
3179 }
3180 if (tree == NULL) {
3181 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003182 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003183 value, attr->name, elem->name);
3184 ret = 0;
3185 }
3186 }
3187
3188 /* Fixed Attribute Default */
3189 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3190 (xmlStrcmp(attrDecl->defaultValue, value))) {
3191 VERROR(ctxt->userData,
3192 "Value for attribute %s on %s must be \"%s\"\n",
3193 attr->name, elem->name, attrDecl->defaultValue);
3194 ret = 0;
3195 }
3196
Daniel Veillardcf461992000-03-14 18:30:20 +00003197 /* Extra check for the attribute value */
3198 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3199 attrDecl->atype, value);
3200
Daniel Veillardb05deb71999-08-10 19:04:08 +00003201 return(ret);
3202}
3203
3204int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3205 xmlElementContentPtr cont);
3206
3207/**
3208 * xmlValidateElementTypeExpr:
3209 * @ctxt: the validation context
3210 * @child: pointer to the child list
3211 * @cont: pointer to the content declaration
3212 *
3213 * Try to validate the content of an element of type element
3214 * but don't handle the occurence factor
3215 *
3216 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3217 * also update child value in-situ.
3218 */
3219
3220int
3221xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3222 xmlElementContentPtr cont) {
3223 xmlNodePtr cur;
3224 int ret = 1;
3225
3226 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003227 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003228 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003229 if ((*child)->type == XML_ENTITY_REF_NODE) {
3230 /*
3231 * If there is an entity declared an it's not empty
3232 * Push the current node on the stack and process with the
3233 * entity content.
3234 */
3235 if (((*child)->children != NULL) &&
3236 ((*child)->children->children != NULL)) {
3237 nodeVPush(ctxt, *child);
3238 *child = (*child)->children->children;
3239 } else
3240 *child = (*child)->next;
3241 continue;
3242 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003243 if ((*child)->type == XML_PI_NODE) {
3244 *child = (*child)->next;
3245 continue;
3246 }
3247 if ((*child)->type == XML_COMMENT_NODE) {
3248 *child = (*child)->next;
3249 continue;
3250 }
3251 else if ((*child)->type != XML_ELEMENT_NODE) {
3252 return(-1);
3253 }
3254 break;
3255 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003256 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003257 switch (cont->type) {
3258 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003259 if (*child == NULL) return(0);
3260 if ((*child)->type == XML_TEXT_NODE) return(1);
3261 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003262 case XML_ELEMENT_CONTENT_ELEMENT:
3263 if (*child == NULL) return(0);
3264 ret = (!xmlStrcmp((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003265 if (ret == 1) {
3266 while ((*child)->next == NULL) {
3267 if (((*child)->parent != NULL) &&
3268 ((*child)->parent->type == XML_ENTITY_DECL)) {
3269 *child = nodeVPop(ctxt);
3270 } else
3271 break;
3272 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003273 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003274 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003275 return(ret);
3276 case XML_ELEMENT_CONTENT_OR:
3277 cur = *child;
3278 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3279 if (ret == -1) return(-1);
3280 if (ret == 1) {
3281 return(1);
3282 }
3283 /* rollback and retry the other path */
3284 *child = cur;
3285 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3286 if (ret == -1) return(-1);
3287 if (ret == 0) {
3288 *child = cur;
3289 return(0);
3290 }
3291 return(1);
3292 case XML_ELEMENT_CONTENT_SEQ:
3293 cur = *child;
3294 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3295 if (ret == -1) return(-1);
3296 if (ret == 0) {
3297 *child = cur;
3298 return(0);
3299 }
3300 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3301 if (ret == -1) return(-1);
3302 if (ret == 0) {
3303 *child = cur;
3304 return(0);
3305 }
3306 return(1);
3307 }
3308 return(ret);
3309}
3310
3311/**
3312 * xmlValidateElementTypeElement:
3313 * @ctxt: the validation context
3314 * @child: pointer to the child list
3315 * @cont: pointer to the content declaration
3316 *
3317 * Try to validate the content of an element of type element
3318 * yeah, Yet Another Regexp Implementation, and recursive
3319 *
3320 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3321 * also update child and content values in-situ.
3322 */
3323
3324int
3325xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3326 xmlElementContentPtr cont) {
3327 xmlNodePtr cur;
3328 int ret = 1;
3329
3330 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003331
3332 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003333 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003334 if ((*child)->type == XML_ENTITY_REF_NODE) {
3335 /*
3336 * If there is an entity declared an it's not empty
3337 * Push the current node on the stack and process with the
3338 * entity content.
3339 */
3340 if (((*child)->children != NULL) &&
3341 ((*child)->children->children != NULL)) {
3342 nodeVPush(ctxt, *child);
3343 *child = (*child)->children->children;
3344 } else
3345 *child = (*child)->next;
3346 continue;
3347 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003348 if ((*child)->type == XML_PI_NODE) {
3349 *child = (*child)->next;
3350 continue;
3351 }
3352 if ((*child)->type == XML_COMMENT_NODE) {
3353 *child = (*child)->next;
3354 continue;
3355 }
3356 else if ((*child)->type != XML_ELEMENT_NODE) {
3357 return(-1);
3358 }
3359 break;
3360 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003361 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003362 cur = *child;
3363 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3364 if (ret == -1) return(-1);
3365 switch (cont->ocur) {
3366 case XML_ELEMENT_CONTENT_ONCE:
3367 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003368 /* skip ignorable elems */
3369 while ((*child != NULL) &&
3370 (((*child)->type == XML_PI_NODE) ||
3371 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003372 while ((*child)->next == NULL) {
3373 if (((*child)->parent != NULL) &&
3374 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3375 *child = (*child)->parent;
3376 } else
3377 break;
3378 }
3379 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003380 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003381 return(1);
3382 }
3383 *child = cur;
3384 return(0);
3385 case XML_ELEMENT_CONTENT_OPT:
3386 if (ret == 0) {
3387 *child = cur;
3388 return(1);
3389 }
3390 break;
3391 case XML_ELEMENT_CONTENT_MULT:
3392 if (ret == 0) {
3393 *child = cur;
3394 break;
3395 }
3396 /* no break on purpose */
3397 case XML_ELEMENT_CONTENT_PLUS:
3398 if (ret == 0) {
3399 *child = cur;
3400 return(0);
3401 }
3402 do {
3403 cur = *child;
3404 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3405 } while (ret == 1);
3406 if (ret == -1) return(-1);
3407 *child = cur;
3408 break;
3409 }
3410 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003411 if ((*child)->type == XML_ENTITY_REF_NODE) {
3412 /*
3413 * If there is an entity declared an it's not empty
3414 * Push the current node on the stack and process with the
3415 * entity content.
3416 */
3417 if (((*child)->children != NULL) &&
3418 ((*child)->children->children != NULL)) {
3419 nodeVPush(ctxt, *child);
3420 *child = (*child)->children->children;
3421 } else
3422 *child = (*child)->next;
3423 continue;
3424 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003425 if ((*child)->type == XML_PI_NODE) {
3426 *child = (*child)->next;
3427 continue;
3428 }
3429 if ((*child)->type == XML_COMMENT_NODE) {
3430 *child = (*child)->next;
3431 continue;
3432 }
3433 else if ((*child)->type != XML_ELEMENT_NODE) {
3434 return(-1);
3435 }
3436 break;
3437 }
3438 return(1);
3439}
3440
3441/**
3442 * xmlSprintfElementChilds:
3443 * @buf: an output buffer
3444 * @content: An element
3445 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3446 *
3447 * This will dump the list of childs to the buffer
3448 * Intended just for the debug routine
3449 */
3450void
3451xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3452 xmlNodePtr cur;
3453
3454 if (node == NULL) return;
3455 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003456 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003457 while (cur != NULL) {
3458 switch (cur->type) {
3459 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003460 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003461 if (cur->next != NULL)
3462 strcat(buf, " ");
3463 break;
3464 case XML_TEXT_NODE:
3465 case XML_CDATA_SECTION_NODE:
3466 case XML_ENTITY_REF_NODE:
3467 strcat(buf, "CDATA");
3468 if (cur->next != NULL)
3469 strcat(buf, " ");
3470 break;
3471 case XML_ATTRIBUTE_NODE:
3472 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003473 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003474 case XML_DOCUMENT_TYPE_NODE:
3475 case XML_DOCUMENT_FRAG_NODE:
3476 case XML_NOTATION_NODE:
3477 strcat(buf, "???");
3478 if (cur->next != NULL)
3479 strcat(buf, " ");
3480 break;
3481 case XML_ENTITY_NODE:
3482 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003483 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003484 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003485 case XML_ELEMENT_DECL:
3486 case XML_ATTRIBUTE_DECL:
3487 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003488 break;
3489 }
3490 cur = cur->next;
3491 }
3492 if (glob) strcat(buf, ")");
3493}
3494
3495
3496/**
3497 * xmlValidateOneElement:
3498 * @ctxt: the validation context
3499 * @doc: a document instance
3500 * @elem: an element instance
3501 *
3502 * Try to validate a single element and it's attributes,
3503 * basically it does the following checks as described by the
3504 * XML-1.0 recommendation:
3505 * - [ VC: Element Valid ]
3506 * - [ VC: Required Attribute ]
3507 * Then call xmlValidateOneAttribute() for each attribute present.
3508 *
3509 * The ID/IDREF checkings are done separately
3510 *
3511 * returns 1 if valid or 0 otherwise
3512 */
3513
3514int
3515xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3516 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003517 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003518 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003519 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003520 xmlNodePtr child;
3521 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003522 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003523
3524 CHECK_DTD;
3525
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003526 if (elem == NULL) return(0);
3527 if (elem->type == XML_TEXT_NODE) {
3528 }
3529 switch (elem->type) {
3530 case XML_ATTRIBUTE_NODE:
3531 VERROR(ctxt->userData,
3532 "Attribute element not expected here\n");
3533 return(0);
3534 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003535 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003536 VERROR(ctxt->userData, "Text element has childs !\n");
3537 return(0);
3538 }
3539 if (elem->properties != NULL) {
3540 VERROR(ctxt->userData, "Text element has attributes !\n");
3541 return(0);
3542 }
3543 if (elem->ns != NULL) {
3544 VERROR(ctxt->userData, "Text element has namespace !\n");
3545 return(0);
3546 }
3547 if (elem->ns != NULL) {
3548 VERROR(ctxt->userData,
3549 "Text element carries namespace definitions !\n");
3550 return(0);
3551 }
3552 if (elem->content == NULL) {
3553 VERROR(ctxt->userData,
3554 "Text element has no content !\n");
3555 return(0);
3556 }
3557 return(1);
3558 case XML_CDATA_SECTION_NODE:
3559 case XML_ENTITY_REF_NODE:
3560 case XML_PI_NODE:
3561 case XML_COMMENT_NODE:
3562 return(1);
3563 case XML_ENTITY_NODE:
3564 VERROR(ctxt->userData,
3565 "Entity element not expected here\n");
3566 return(0);
3567 case XML_NOTATION_NODE:
3568 VERROR(ctxt->userData,
3569 "Notation element not expected here\n");
3570 return(0);
3571 case XML_DOCUMENT_NODE:
3572 case XML_DOCUMENT_TYPE_NODE:
3573 case XML_DOCUMENT_FRAG_NODE:
3574 VERROR(ctxt->userData,
3575 "Document element not expected here\n");
3576 return(0);
3577 case XML_HTML_DOCUMENT_NODE:
3578 VERROR(ctxt->userData,
3579 "\n");
3580 return(0);
3581 case XML_ELEMENT_NODE:
3582 break;
3583 default:
3584 VERROR(ctxt->userData,
3585 "unknown element type %d\n", elem->type);
3586 return(0);
3587 }
3588 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003589
Daniel Veillardbe803962000-06-28 23:40:59 +00003590 /*
3591 * Fetch the declaration for the qualified name
3592 */
3593 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3594 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3595 elem->name, elem->ns->prefix);
3596 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3597 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3598 elem->name, elem->ns->prefix);
3599 }
3600
3601 /*
3602 * Fetch the declaration for the non qualified name
3603 */
3604 if (elemDecl == NULL) {
3605 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3606 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3607 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3608 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003609 if (elemDecl == NULL) {
3610 VERROR(ctxt->userData, "No declaration for element %s\n",
3611 elem->name);
3612 return(0);
3613 }
3614
3615 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003616 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003617 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003618 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003619 VERROR(ctxt->userData,
3620 "Element %s was declared EMPTY this one has content\n",
3621 elem->name);
3622 ret = 0;
3623 }
3624 break;
3625 case XML_ELEMENT_TYPE_ANY:
3626 /* I don't think anything is required then */
3627 break;
3628 case XML_ELEMENT_TYPE_MIXED:
3629 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003630 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003631 while (child != NULL) {
3632 if (child->type == XML_ELEMENT_NODE) {
3633 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003634 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3635 xmlChar qname[500];
3636#ifdef HAVE_SNPRINTF
3637 snprintf((char *) qname, sizeof(qname), "%s:%s",
3638 child->ns->prefix, child->name);
3639#else
3640 sprintf(qname, "%s:%s", child->name, child->ns->prefix);
3641#endif
3642 cont = elemDecl->content;
3643 while (cont != NULL) {
3644 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3645 if (!xmlStrcmp(cont->name, qname)) break;
3646 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3647 (cont->c1 != NULL) &&
3648 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
3649 if (!xmlStrcmp(cont->c1->name, qname)) break;
3650 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3651 (cont->c1 == NULL) ||
3652 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3653 /* Internal error !!! */
3654 fprintf(stderr, "Internal: MIXED struct bad\n");
3655 break;
3656 }
3657 cont = cont->c2;
3658 }
3659 if (cont != NULL)
3660 goto child_ok;
3661 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003662 cont = elemDecl->content;
3663 while (cont != NULL) {
3664 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3665 if (!xmlStrcmp(cont->name, name)) break;
3666 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3667 (cont->c1 != NULL) &&
3668 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3669 if (!xmlStrcmp(cont->c1->name, name)) break;
3670 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3671 (cont->c1 == NULL) ||
3672 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3673 /* Internal error !!! */
3674 fprintf(stderr, "Internal: MIXED struct bad\n");
3675 break;
3676 }
3677 cont = cont->c2;
3678 }
3679 if (cont == NULL) {
3680 VERROR(ctxt->userData,
3681 "Element %s is not declared in %s list of possible childs\n",
3682 name, elem->name);
3683 ret = 0;
3684 }
3685 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003686child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003687 child = child->next;
3688 }
3689 break;
3690 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003691 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003692 cont = elemDecl->content;
3693 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3694 if ((ret == 0) || (child != NULL)) {
3695 char expr[1000];
3696 char list[2000];
3697
3698 expr[0] = 0;
3699 xmlSprintfElementContent(expr, cont, 1);
3700 list[0] = 0;
3701 xmlSprintfElementChilds(list, elem, 1);
3702
3703 VERROR(ctxt->userData,
3704 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3705 elem->name, expr, list);
3706 ret = 0;
3707 }
3708 break;
3709 }
3710
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003711 /* [ VC: Required Attribute ] */
3712 attr = elemDecl->attributes;
3713 while (attr != NULL) {
3714 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3715 xmlAttrPtr attrib;
3716 int qualified = -1;
3717
3718 attrib = elem->properties;
3719 while (attrib != NULL) {
3720 if (!xmlStrcmp(attrib->name, attr->name)) {
3721 if (attr->prefix != NULL) {
3722 xmlNsPtr nameSpace = attrib->ns;
3723
3724 if (nameSpace == NULL)
3725 nameSpace = elem->ns;
3726 /*
3727 * qualified names handling is problematic, having a
3728 * different prefix should be possible but DTDs don't
3729 * allow to define the URI instead of the prefix :-(
3730 */
3731 if (nameSpace == NULL) {
3732 if (qualified < 0)
3733 qualified = 0;
3734 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3735 if (qualified < 1)
3736 qualified = 1;
3737 } else
3738 goto found;
3739 } else {
3740 /*
3741 * We should allow applications to define namespaces
3742 * for their application even if the DTD doesn't
3743 * carry one, otherwise, basically we would always
3744 * break.
3745 */
3746 goto found;
3747 }
3748 }
3749 attrib = attrib->next;
3750 }
3751 if (qualified == -1) {
3752 if (attr->prefix == NULL) {
3753 VERROR(ctxt->userData,
3754 "Element %s doesn't carry attribute %s\n",
3755 elem->name, attr->name);
3756 } else {
3757 VERROR(ctxt->userData,
3758 "Element %s doesn't carry attribute %s:%s\n",
3759 elem->name, attr->prefix,attr->name);
3760 }
3761 } else if (qualified == 0) {
3762 VWARNING(ctxt->userData,
3763 "Element %s required attribute %s:%s has no prefix\n",
3764 elem->name, attr->prefix,attr->name);
3765 } else if (qualified == 1) {
3766 VWARNING(ctxt->userData,
3767 "Element %s required attribute %s:%s has different prefix\n",
3768 elem->name, attr->prefix,attr->name);
3769 }
3770 }
3771found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003772 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003773 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003774 return(ret);
3775}
3776
3777/**
3778 * xmlValidateRoot:
3779 * @ctxt: the validation context
3780 * @doc: a document instance
3781 *
3782 * Try to validate a the root element
3783 * basically it does the following check as described by the
3784 * XML-1.0 recommendation:
3785 * - [ VC: Root Element Type ]
3786 * it doesn't try to recurse or apply other check to the element
3787 *
3788 * returns 1 if valid or 0 otherwise
3789 */
3790
3791int
3792xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003793 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003794 if (doc == NULL) return(0);
3795
3796 if ((doc->intSubset == NULL) ||
3797 (doc->intSubset->name == NULL)) {
3798 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3799 return(0);
3800 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003801 root = xmlDocGetRootElement(doc);
3802 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003803 VERROR(ctxt->userData, "Not valid: no root element\n");
3804 return(0);
3805 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003806
3807 /*
3808 * Check first the document root against the NQName
3809 */
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003810 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003811 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3812 xmlChar qname[500];
3813#ifdef HAVE_SNPRINTF
3814 snprintf((char *) qname, sizeof(qname), "%s:%s",
3815 root->ns->prefix, root->name);
3816#else
3817 sprintf(qname, "%s:%s", root->name, root->ns->prefix);
3818#endif
3819 if (!xmlStrcmp(doc->intSubset->name, qname))
3820 goto name_ok;
3821 }
3822 if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
3823 (!xmlStrcmp(root->name, BAD_CAST "html")))
3824 goto name_ok;
3825 VERROR(ctxt->userData,
3826 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3827 root->name, doc->intSubset->name);
3828 return(0);
3829
Daniel Veillardb05deb71999-08-10 19:04:08 +00003830 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003831name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003832 return(1);
3833}
3834
3835
3836/**
3837 * xmlValidateElement:
3838 * @ctxt: the validation context
3839 * @doc: a document instance
3840 * @elem: an element instance
3841 *
3842 * Try to validate the subtree under an element
3843 *
3844 * returns 1 if valid or 0 otherwise
3845 */
3846
3847int
3848xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003849 xmlNodePtr child;
3850 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003851 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003852 int ret = 1;
3853
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003854 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003855 CHECK_DTD;
3856
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003857 ret &= xmlValidateOneElement(ctxt, doc, elem);
3858 attr = elem->properties;
3859 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003860 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003861 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3862 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003863 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003864 attr= attr->next;
3865 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003866 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003867 while (child != NULL) {
3868 ret &= xmlValidateElement(ctxt, doc, child);
3869 child = child->next;
3870 }
3871
3872 return(ret);
3873}
3874
3875/**
3876 * xmlValidateDocumentFinal:
3877 * @ctxt: the validation context
3878 * @doc: a document instance
3879 *
3880 * Does the final step for the document validation once all the
3881 * incremental validation steps have been completed
3882 *
3883 * basically it does the following checks described by the XML Rec
3884 *
3885 *
3886 * returns 1 if valid or 0 otherwise
3887 */
3888
3889int
3890xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3891 int ret = 1, i;
3892 xmlRefTablePtr table;
3893 xmlAttrPtr id;
3894
3895 if (doc == NULL) {
3896 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3897 return(0);
3898 }
3899
3900 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003901 * Check all the NOTATION/NOTATIONS attributes
3902 */
3903 /*
3904 * Check all the ENTITY/ENTITIES attributes definition for validity
3905 */
3906 /*
3907 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003908 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003909 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003910 if (table != NULL) {
3911 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003912 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3913 id = xmlGetID(doc, table->table[i]->value);
3914 if (id == NULL) {
3915 VERROR(ctxt->userData,
3916 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3917 table->table[i]->attr->name, table->table[i]->value);
3918 ret = 0;
3919 }
3920 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
3921 xmlChar *dup, *name = NULL, *cur, save;
3922
3923 dup = xmlStrdup(table->table[i]->value);
3924 if (dup == NULL)
3925 return(0);
3926 cur = dup;
3927 while (*cur != 0) {
3928 name = cur;
3929 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3930 save = *cur;
3931 *cur = 0;
3932 id = xmlGetID(doc, name);
3933 if (id == NULL) {
3934 VERROR(ctxt->userData,
3935 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3936 table->table[i]->attr->name, name);
3937 ret = 0;
3938 }
3939 if (save == 0)
3940 break;
3941 *cur = save;
3942 while (IS_BLANK(*cur)) cur++;
3943 }
3944 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003945 }
3946 }
3947 }
3948 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003949}
3950
3951/**
3952 * xmlValidateDtd:
3953 * @ctxt: the validation context
3954 * @doc: a document instance
3955 * @dtd: a dtd instance
3956 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003957 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003958 *
3959 * basically it does check all the definitions in the DtD.
3960 *
3961 * returns 1 if valid or 0 otherwise
3962 */
3963
3964int
3965xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003966 int ret;
3967 xmlDtdPtr oldExt;
3968 xmlNodePtr root;
3969
3970 if (dtd == NULL) return(0);
3971 if (doc == NULL) return(0);
3972 oldExt = doc->extSubset;
3973 doc->extSubset = dtd;
3974 ret = xmlValidateRoot(ctxt, doc);
3975 if (ret == 0) {
3976 doc->extSubset = oldExt;
3977 return(ret);
3978 }
3979 root = xmlDocGetRootElement(doc);
3980 ret = xmlValidateElement(ctxt, doc, root);
3981 ret &= xmlValidateDocumentFinal(ctxt, doc);
3982 doc->extSubset = oldExt;
3983 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003984}
3985
3986/**
Daniel Veillardcf461992000-03-14 18:30:20 +00003987 * xmlValidateDtdFinal:
3988 * @ctxt: the validation context
3989 * @doc: a document instance
3990 *
3991 * Does the final step for the dtds validation once all the
3992 * subsets have been parsed
3993 *
3994 * basically it does the following checks described by the XML Rec
3995 * - check that ENTITY and ENTITIES type attributes default or
3996 * possible values matches one of the defined entities.
3997 * - check that NOTATION type attributes default or
3998 * possible values matches one of the defined notations.
3999 *
4000 * returns 1 if valid or 0 otherwise
4001 */
4002
4003int
4004xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4005 int ret = 1, i;
4006 xmlDtdPtr dtd;
4007 xmlAttributeTablePtr table;
4008 xmlAttributePtr cur;
4009
4010 if (doc == NULL) return(0);
4011 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4012 return(0);
4013 dtd = doc->intSubset;
4014 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004015 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004016
4017 for (i = 0;i < table->nb_attributes;i++) {
4018 cur = table->table[i];
4019 switch (cur->atype) {
4020 case XML_ATTRIBUTE_CDATA:
4021 case XML_ATTRIBUTE_ID:
4022 case XML_ATTRIBUTE_IDREF :
4023 case XML_ATTRIBUTE_IDREFS:
4024 case XML_ATTRIBUTE_NMTOKEN:
4025 case XML_ATTRIBUTE_NMTOKENS:
4026 case XML_ATTRIBUTE_ENUMERATION:
4027 break;
4028 case XML_ATTRIBUTE_ENTITY:
4029 case XML_ATTRIBUTE_ENTITIES:
4030 case XML_ATTRIBUTE_NOTATION:
4031 if (cur->defaultValue != NULL) {
4032 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4033 cur->atype, cur->defaultValue);
4034 }
4035 if (cur->tree != NULL) {
4036 xmlEnumerationPtr tree = cur->tree;
4037 while (tree != NULL) {
4038 ret &= xmlValidateAttributeValue2(ctxt, doc,
4039 cur->name, cur->atype, tree->name);
4040 tree = tree->next;
4041 }
4042 }
4043 }
4044 }
4045 }
4046 dtd = doc->extSubset;
4047 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00004048 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardcf461992000-03-14 18:30:20 +00004049
4050 for (i = 0;i < table->nb_attributes;i++) {
4051 cur = table->table[i];
4052 switch (cur->atype) {
4053 case XML_ATTRIBUTE_CDATA:
4054 case XML_ATTRIBUTE_ID:
4055 case XML_ATTRIBUTE_IDREF :
4056 case XML_ATTRIBUTE_IDREFS:
4057 case XML_ATTRIBUTE_NMTOKEN:
4058 case XML_ATTRIBUTE_NMTOKENS:
4059 case XML_ATTRIBUTE_ENUMERATION:
4060 break;
4061 case XML_ATTRIBUTE_ENTITY:
4062 case XML_ATTRIBUTE_ENTITIES:
4063 case XML_ATTRIBUTE_NOTATION:
4064 if (cur->defaultValue != NULL) {
4065 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4066 cur->atype, cur->defaultValue);
4067 }
4068 if (cur->tree != NULL) {
4069 xmlEnumerationPtr tree = cur->tree;
4070 while (tree != NULL) {
4071 ret &= xmlValidateAttributeValue2(ctxt, doc,
4072 cur->name, cur->atype, tree->name);
4073 tree = tree->next;
4074 }
4075 }
4076 }
4077 }
4078 }
4079 return(ret);
4080}
4081
4082/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00004083 * xmlValidateDocument:
4084 * @ctxt: the validation context
4085 * @doc: a document instance
4086 *
4087 * Try to validate the document instance
4088 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004089 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00004090 * i.e. validates the internal and external subset (if present)
4091 * and validate the document tree.
4092 *
4093 * returns 1 if valid or 0 otherwise
4094 */
4095
4096int
4097xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004098 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004099 xmlNodePtr root;
4100
4101 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4102 return(0);
4103 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4104 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4105 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4106 doc->intSubset->SystemID);
4107 if (doc->extSubset == NULL) {
4108 if (doc->intSubset->SystemID != NULL) {
4109 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004110 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004111 doc->intSubset->SystemID);
4112 } else {
4113 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004114 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004115 doc->intSubset->ExternalID);
4116 }
4117 return(0);
4118 }
4119 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004120
Daniel Veillardcf461992000-03-14 18:30:20 +00004121 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004122 if (!xmlValidateRoot(ctxt, doc)) return(0);
4123
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004124 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00004125 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004126 ret &= xmlValidateDocumentFinal(ctxt, doc);
4127 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004128}
4129
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004130
4131/************************************************************************
4132 * *
4133 * Routines for dynamic validation editing *
4134 * *
4135 ************************************************************************/
4136
4137/**
4138 * xmlValidGetPotentialChildren:
4139 * @ctree: an element content tree
4140 * @list: an array to store the list of child names
4141 * @len: a pointer to the number of element in the list
4142 * @max: the size of the array
4143 *
4144 * Build/extend a list of potential children allowed by the content tree
4145 *
4146 * returns the number of element in the list, or -1 in case of error.
4147 */
4148
4149int
4150xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4151 int *len, int max) {
4152 int i;
4153
4154 if ((ctree == NULL) || (list == NULL) || (len == NULL))
4155 return(-1);
4156 if (*len >= max) return(*len);
4157
4158 switch (ctree->type) {
4159 case XML_ELEMENT_CONTENT_PCDATA:
4160 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00004161 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
4162 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004163 break;
4164 case XML_ELEMENT_CONTENT_ELEMENT:
4165 for (i = 0; i < *len;i++)
4166 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
4167 list[(*len)++] = ctree->name;
4168 break;
4169 case XML_ELEMENT_CONTENT_SEQ:
4170 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4171 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4172 break;
4173 case XML_ELEMENT_CONTENT_OR:
4174 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4175 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4176 break;
4177 }
4178
4179 return(*len);
4180}
4181
4182/**
4183 * xmlValidGetValidElements:
4184 * @prev: an element to insert after
4185 * @next: an element to insert next
4186 * @list: an array to store the list of child names
4187 * @max: the size of the array
4188 *
4189 * This function returns the list of authorized children to insert
4190 * within an existing tree while respecting the validity constraints
4191 * forced by the Dtd. The insertion point is defined using @prev and
4192 * @next in the following ways:
4193 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4194 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4195 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4196 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4197 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4198 *
4199 * pointers to the element names are inserted at the beginning of the array
4200 * and do not need to be freed.
4201 *
4202 * returns the number of element in the list, or -1 in case of error. If
4203 * the function returns the value @max the caller is invited to grow the
4204 * receiving array and retry.
4205 */
4206
4207int
4208xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4209 int max) {
4210 int nb_valid_elements = 0;
4211 const xmlChar *elements[256];
4212 int nb_elements = 0, i;
4213
4214 xmlNode *ref_node;
4215 xmlNode *parent;
4216 xmlNode *test_node;
4217
4218 xmlNode *prev_next;
4219 xmlNode *next_prev;
4220 xmlNode *parent_childs;
4221 xmlNode *parent_last;
4222
4223 xmlElement *element_desc;
4224
4225 if (prev == NULL && next == NULL)
4226 return(-1);
4227
4228 if (list == NULL) return(-1);
4229 if (max <= 0) return(-1);
4230
4231 nb_valid_elements = 0;
4232 ref_node = prev ? prev : next;
4233 parent = ref_node->parent;
4234
4235 /*
4236 * Retrieves the parent element declaration
4237 */
4238 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4239 parent->name);
4240 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4241 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4242 parent->name);
4243 if (element_desc == NULL) return(-1);
4244
4245 /*
4246 * Do a backup of the current tree structure
4247 */
4248 prev_next = prev ? prev->next : NULL;
4249 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004250 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004251 parent_last = parent->last;
4252
4253 /*
4254 * Creates a dummy node and insert it into the tree
4255 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004256 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004257 test_node->doc = ref_node->doc;
4258 test_node->parent = parent;
4259 test_node->prev = prev;
4260 test_node->next = next;
4261
4262 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00004263 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004264
4265 if (next) next->prev = test_node;
4266 else parent->last = test_node;
4267
4268 /*
4269 * Insert each potential child node and check if the parent is
4270 * still valid
4271 */
4272 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4273 elements, &nb_elements, 256);
4274
4275 for (i = 0;i < nb_elements;i++) {
4276 test_node->name = elements[i];
4277 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4278 int j;
4279
4280 for (j = 0; j < nb_valid_elements;j++)
4281 if (!xmlStrcmp(elements[i], list[j])) break;
4282 list[nb_valid_elements++] = elements[i];
4283 if (nb_valid_elements >= max) break;
4284 }
4285 }
4286
4287 /*
4288 * Restore the tree structure
4289 */
4290 if (prev) prev->next = prev_next;
4291 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004292 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004293 parent->last = parent_last;
4294
4295 return(nb_valid_elements);
4296}