blob: 52359913c28f4b097e4f4108bf61e18802543c7e [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; \
36 ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab, \
37 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 */
541 table = dtd->elements;
542 if (table == NULL)
543 table = dtd->elements = xmlCreateElementTable();
544 if (table == NULL) {
545 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
546 return(NULL);
547 }
548
549 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000550 * Validity Check:
551 * Search the DTD for previous declarations of the ELEMENT
552 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000553 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000554 cur = table->table[i];
Daniel Veillardbe803962000-06-28 23:40:59 +0000555 if ((ns != NULL) && (cur->prefix == NULL)) continue;
556 if ((ns == NULL) && (cur->prefix != NULL)) continue;
557 if ((!xmlStrcmp(cur->name, name)) &&
558 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000559 /*
560 * The element is already defined in this Dtd.
561 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000562 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000563 return(NULL);
564 }
565 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000566
567 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000568 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000569 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000570 if (table->nb_elements >= table->max_elements) {
571 /*
572 * need more elements.
573 */
574 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000575 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000576 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000577 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000578 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
579 return(NULL);
580 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000581 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000582 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000583 if (ret == NULL) {
584 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
585 return(NULL);
586 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000587 memset(ret, 0, sizeof(xmlElement));
588 ret->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000589 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000590
591 /*
592 * fill the structure.
593 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000594 ret->etype = type;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000595 ret->name = xmlStrdup(name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000596 ret->prefix = ns;
Daniel Veillard14fff061999-06-22 21:49:07 +0000597 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000598 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000599 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000600
Daniel Veillardcf461992000-03-14 18:30:20 +0000601 /*
602 * Link it to the Dtd
603 */
604 ret->parent = dtd;
605 ret->doc = dtd->doc;
606 if (dtd->last == NULL) {
607 dtd->children = dtd->last = (xmlNodePtr) ret;
608 } else {
609 dtd->last->next = (xmlNodePtr) ret;
610 ret->prev = dtd->last;
611 dtd->last = (xmlNodePtr) ret;
612 }
Daniel Veillardbe803962000-06-28 23:40:59 +0000613 if (uqname != NULL)
614 xmlFree(uqname);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000615 return(ret);
616}
617
Daniel Veillard3b9def11999-01-31 22:15:06 +0000618/**
619 * xmlFreeElement:
620 * @elem: An element
621 *
622 * Deallocate the memory used by an element definition
623 */
624void
625xmlFreeElement(xmlElementPtr elem) {
626 if (elem == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +0000627 xmlUnlinkNode((xmlNodePtr) elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000628 xmlFreeElementContent(elem->content);
629 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000630 xmlFree((xmlChar *) elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000631 if (elem->prefix != NULL)
632 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000633 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000634 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000635}
636
637/**
638 * xmlFreeElementTable:
639 * @table: An element table
640 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000641 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000642 */
643void
644xmlFreeElementTable(xmlElementTablePtr table) {
645 int i;
646
647 if (table == NULL) return;
648
649 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000650 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000651 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000652 xmlFree(table->table);
653 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000654}
655
656/**
657 * xmlCopyElementTable:
658 * @table: An element table
659 *
660 * Build a copy of an element table.
661 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000662 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000663 */
664xmlElementTablePtr
665xmlCopyElementTable(xmlElementTablePtr table) {
666 xmlElementTablePtr ret;
667 xmlElementPtr cur, ent;
668 int i;
669
Daniel Veillard6454aec1999-09-02 22:04:43 +0000670 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000671 if (ret == NULL) {
672 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
673 return(NULL);
674 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000675 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000676 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000677 if (ret->table == NULL) {
678 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000679 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000680 return(NULL);
681 }
682 ret->max_elements = table->max_elements;
683 ret->nb_elements = table->nb_elements;
684 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000685 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000686 if (cur == NULL) {
687 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000688 xmlFree(ret);
689 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000690 return(NULL);
691 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000692 memset(cur, 0, sizeof(xmlElement));
693 cur->type = XML_ELEMENT_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000694 ret->table[i] = cur;
695 ent = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000696 cur->etype = ent->etype;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000697 if (ent->name != NULL)
698 cur->name = xmlStrdup(ent->name);
699 else
700 cur->name = NULL;
701 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000702 /* TODO : rebuild the attribute list on the copy */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000703 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000704 }
705 return(ret);
706}
707
708/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000709 * xmlDumpElementDecl:
710 * @buf: the XML buffer output
711 * @elem: An element table
712 *
713 * This will dump the content of the element declaration as an XML
714 * DTD definition
715 */
716void
717xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
718 switch (elem->etype) {
719 case XML_ELEMENT_TYPE_EMPTY:
720 xmlBufferWriteChar(buf, "<!ELEMENT ");
721 xmlBufferWriteCHAR(buf, elem->name);
722 xmlBufferWriteChar(buf, " EMPTY>\n");
723 break;
724 case XML_ELEMENT_TYPE_ANY:
725 xmlBufferWriteChar(buf, "<!ELEMENT ");
726 xmlBufferWriteCHAR(buf, elem->name);
727 xmlBufferWriteChar(buf, " ANY>\n");
728 break;
729 case XML_ELEMENT_TYPE_MIXED:
730 xmlBufferWriteChar(buf, "<!ELEMENT ");
731 xmlBufferWriteCHAR(buf, elem->name);
732 xmlBufferWriteChar(buf, " ");
733 xmlDumpElementContent(buf, elem->content, 1);
734 xmlBufferWriteChar(buf, ">\n");
735 break;
736 case XML_ELEMENT_TYPE_ELEMENT:
737 xmlBufferWriteChar(buf, "<!ELEMENT ");
738 xmlBufferWriteCHAR(buf, elem->name);
739 xmlBufferWriteChar(buf, " ");
740 xmlDumpElementContent(buf, elem->content, 1);
741 xmlBufferWriteChar(buf, ">\n");
742 break;
743 default:
744 fprintf(stderr,
745 "xmlDumpElementDecl: internal: unknown type %d\n",
746 elem->etype);
747 }
748}
749
750/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000751 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000752 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000753 * @table: An element table
754 *
755 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000756 */
757void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000758xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000759 int i;
760 xmlElementPtr cur;
761
762 if (table == NULL) return;
763
764 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000765 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +0000766 xmlDumpElementDecl(buf, cur);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000767 }
768}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000769
770/**
771 * xmlCreateEnumeration:
772 * @name: the enumeration name or NULL
773 *
774 * create and initialize an enumeration attribute node.
775 *
776 * Returns the xmlEnumerationPtr just created or NULL in case
777 * of error.
778 */
779xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000780xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000781 xmlEnumerationPtr ret;
782
Daniel Veillard6454aec1999-09-02 22:04:43 +0000783 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000784 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000785 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000786 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000787 return(NULL);
788 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000789 memset(ret, 0, sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000790
791 if (name != NULL)
792 ret->name = xmlStrdup(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000793 return(ret);
794}
795
796/**
797 * xmlFreeEnumeration:
798 * @cur: the tree to free.
799 *
800 * free an enumeration attribute node (recursive).
801 */
802void
803xmlFreeEnumeration(xmlEnumerationPtr cur) {
804 if (cur == NULL) return;
805
806 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
807
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000808 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000809 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000810 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000811}
812
813/**
814 * xmlCopyEnumeration:
815 * @cur: the tree to copy.
816 *
817 * Copy an enumeration attribute node (recursive).
818 *
819 * Returns the xmlEnumerationPtr just created or NULL in case
820 * of error.
821 */
822xmlEnumerationPtr
823xmlCopyEnumeration(xmlEnumerationPtr cur) {
824 xmlEnumerationPtr ret;
825
826 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000827 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000828
829 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
830 else ret->next = NULL;
831
832 return(ret);
833}
834
835/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000836 * xmlDumpEnumeration:
837 * @buf: the XML buffer output
838 * @enum: An enumeration
839 *
840 * This will dump the content of the enumeration
841 */
842void
843xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
844 if (cur == NULL) return;
845
846 xmlBufferWriteCHAR(buf, cur->name);
847 if (cur->next == NULL)
848 xmlBufferWriteChar(buf, ")");
849 else {
850 xmlBufferWriteChar(buf, " | ");
851 xmlDumpEnumeration(buf, cur->next);
852 }
853}
854
855/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000856 * xmlCreateAttributeTable:
857 *
858 * create and initialize an empty attribute hash table.
859 *
860 * Returns the xmlAttributeTablePtr just created or NULL in case
861 * of error.
862 */
863xmlAttributeTablePtr
864xmlCreateAttributeTable(void) {
865 xmlAttributeTablePtr ret;
866
867 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000868 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000869 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000870 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000871 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000872 return(NULL);
873 }
874 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
875 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000876 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000877 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000878 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000879 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000880 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000881 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000882 return(NULL);
883 }
884 return(ret);
885}
886
Daniel Veillardb05deb71999-08-10 19:04:08 +0000887/**
888 * xmlScanAttributeDecl:
889 * @dtd: pointer to the DTD
890 * @elem: the element name
891 *
892 * When inserting a new element scan the DtD for existing attributes
893 * for taht element and initialize the Attribute chain
894 *
895 * Returns the pointer to the first attribute decl in the chain,
896 * possibly NULL.
897 */
898xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000899xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000900 xmlAttributePtr ret = NULL;
901 xmlAttributeTablePtr table;
902 int i;
903
904 if (dtd == NULL) {
905 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
906 return(NULL);
907 }
908 if (elem == NULL) {
909 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
910 return(NULL);
911 }
912 table = dtd->attributes;
913 if (table == NULL)
914 return(NULL);
915
916 for (i = 0;i < table->nb_attributes;i++) {
917 if (!xmlStrcmp(table->table[i]->elem, elem)) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000918 table->table[i]->nexth = ret;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000919 ret = table->table[i];
920 }
921 }
922 return(ret);
923}
924
925/**
926 * xmlScanIDAttributeDecl:
927 * @ctxt: the validation context
928 * @elem: the element name
929 *
Daniel Veillard71b656e2000-01-05 14:46:17 +0000930 * Verify that the element don't have too many ID attributes
Daniel Veillardb05deb71999-08-10 19:04:08 +0000931 * declared.
932 *
933 * Returns the number of ID attributes found.
934 */
935int
936xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
937 xmlAttributePtr cur;
938 int ret = 0;
939
940 if (elem == NULL) return(0);
941 cur = elem->attributes;
942 while (cur != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000943 if (cur->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000944 ret ++;
945 if (ret > 1)
946 VERROR(ctxt->userData,
947 "Element %s has too may ID attributes defined : %s\n",
948 elem->name, cur->name);
949 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000950 cur = cur->nexth;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000951 }
952 return(ret);
953}
954
Daniel Veillard1e346af1999-02-22 10:33:01 +0000955
956/**
957 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000958 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000959 * @dtd: pointer to the DTD
960 * @elem: the element name
961 * @name: the attribute name
Daniel Veillardcf461992000-03-14 18:30:20 +0000962 * @ns: the attribute namespace prefix
Daniel Veillard1e346af1999-02-22 10:33:01 +0000963 * @type: the attribute type
964 * @def: the attribute default type
965 * @defaultValue: the attribute default value
966 * @tree: if it's an enumeration, the associated list
967 *
968 * Register a new attribute declaration
969 *
Daniel Veillardbe803962000-06-28 23:40:59 +0000970 * Returns NULL if not new, othervise the attribute decl
Daniel Veillard1e346af1999-02-22 10:33:01 +0000971 */
972xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000973xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
Daniel Veillardcf461992000-03-14 18:30:20 +0000974 const xmlChar *name, const xmlChar *ns,
975 xmlAttributeType type, xmlAttributeDefault def,
976 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000977 xmlAttributePtr ret, cur;
978 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000979 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000980 int i;
981
982 if (dtd == NULL) {
983 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
984 return(NULL);
985 }
986 if (name == NULL) {
987 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
988 return(NULL);
989 }
990 if (elem == NULL) {
991 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
992 return(NULL);
993 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000994 /*
995 * Check the type and possibly the default value.
996 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000997 switch (type) {
998 case XML_ATTRIBUTE_CDATA:
999 break;
1000 case XML_ATTRIBUTE_ID:
1001 break;
1002 case XML_ATTRIBUTE_IDREF:
1003 break;
1004 case XML_ATTRIBUTE_IDREFS:
1005 break;
1006 case XML_ATTRIBUTE_ENTITY:
1007 break;
1008 case XML_ATTRIBUTE_ENTITIES:
1009 break;
1010 case XML_ATTRIBUTE_NMTOKEN:
1011 break;
1012 case XML_ATTRIBUTE_NMTOKENS:
1013 break;
1014 case XML_ATTRIBUTE_ENUMERATION:
1015 break;
1016 case XML_ATTRIBUTE_NOTATION:
1017 break;
1018 default:
1019 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
1020 return(NULL);
1021 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001022 if ((defaultValue != NULL) &&
1023 (!xmlValidateAttributeValue(type, defaultValue))) {
1024 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
1025 elem, name, defaultValue);
1026 defaultValue = NULL;
1027 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001028
1029 /*
1030 * Create the Attribute table if needed.
1031 */
1032 table = dtd->attributes;
1033 if (table == NULL)
1034 table = dtd->attributes = xmlCreateAttributeTable();
1035 if (table == NULL) {
1036 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
1037 return(NULL);
1038 }
1039
1040 /*
1041 * Validity Check:
1042 * Search the DTD for previous declarations of the ATTLIST
1043 */
1044 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001045 cur = table->table[i];
Daniel Veillard10a2c651999-12-12 13:03:50 +00001046 if ((ns != NULL) && (cur->prefix == NULL)) continue;
1047 if ((ns == NULL) && (cur->prefix != NULL)) continue;
Daniel Veillardcf461992000-03-14 18:30:20 +00001048 if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem)) &&
Daniel Veillard10a2c651999-12-12 13:03:50 +00001049 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001050 /*
1051 * The attribute is already defined in this Dtd.
1052 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001053 VWARNING(ctxt->userData, "Attribute %s on %s: already defined\n",
Daniel Veillardb96e6431999-08-29 21:02:19 +00001054 elem, name);
Daniel Veillardbe803962000-06-28 23:40:59 +00001055 return(NULL);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001056 }
1057 }
1058
1059 /*
1060 * Grow the table, if needed.
1061 */
1062 if (table->nb_attributes >= table->max_attributes) {
1063 /*
1064 * need more attributes.
1065 */
1066 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001067 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001068 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001069 sizeof(xmlAttributePtr));
1070 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001071 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1072 return(NULL);
1073 }
1074 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001075 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001076 if (ret == NULL) {
1077 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
1078 return(NULL);
1079 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001080 memset(ret, 0, sizeof(xmlAttribute));
1081 ret->type = XML_ATTRIBUTE_DECL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001082 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001083
1084 /*
1085 * fill the structure.
1086 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001087 ret->atype = type;
1088 ret->name = xmlStrdup(name);
1089 ret->prefix = xmlStrdup(ns);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001090 ret->elem = xmlStrdup(elem);
1091 ret->def = def;
1092 ret->tree = tree;
1093 if (defaultValue != NULL)
1094 ret->defaultValue = xmlStrdup(defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001095 elemDef = xmlGetDtdElementDesc(dtd, elem);
1096 if (elemDef != NULL) {
1097 if ((type == XML_ATTRIBUTE_ID) &&
1098 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
1099 VERROR(ctxt->userData,
1100 "Element %s has too may ID attributes defined : %s\n",
1101 elem, name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001102 ret->nexth = elemDef->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001103 elemDef->attributes = ret;
1104 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001105 table->nb_attributes++;
1106
Daniel Veillardcf461992000-03-14 18:30:20 +00001107 /*
1108 * Link it to the Dtd
1109 */
1110 ret->parent = dtd;
1111 ret->doc = dtd->doc;
1112 if (dtd->last == NULL) {
1113 dtd->children = dtd->last = (xmlNodePtr) ret;
1114 } else {
1115 dtd->last->next = (xmlNodePtr) ret;
1116 ret->prev = dtd->last;
1117 dtd->last = (xmlNodePtr) ret;
1118 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001119 return(ret);
1120}
1121
1122/**
1123 * xmlFreeAttribute:
1124 * @elem: An attribute
1125 *
1126 * Deallocate the memory used by an attribute definition
1127 */
1128void
1129xmlFreeAttribute(xmlAttributePtr attr) {
1130 if (attr == NULL) return;
Daniel Veillardcf461992000-03-14 18:30:20 +00001131 xmlUnlinkNode((xmlNodePtr) attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001132 if (attr->tree != NULL)
1133 xmlFreeEnumeration(attr->tree);
1134 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001135 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001136 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001137 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001138 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001139 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +00001140 if (attr->prefix != NULL)
1141 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001142 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001143 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001144}
1145
1146/**
1147 * xmlFreeAttributeTable:
1148 * @table: An attribute table
1149 *
1150 * Deallocate the memory used by an entities hash table.
1151 */
1152void
1153xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1154 int i;
1155
1156 if (table == NULL) return;
1157
1158 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001159 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001160 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001161 xmlFree(table->table);
1162 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001163}
1164
1165/**
1166 * xmlCopyAttributeTable:
1167 * @table: An attribute table
1168 *
1169 * Build a copy of an attribute table.
1170 *
1171 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1172 */
1173xmlAttributeTablePtr
1174xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1175 xmlAttributeTablePtr ret;
1176 xmlAttributePtr cur, attr;
1177 int i;
1178
Daniel Veillard6454aec1999-09-02 22:04:43 +00001179 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001180 if (ret == NULL) {
1181 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1182 return(NULL);
1183 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001184 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001185 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001186 if (ret->table == NULL) {
1187 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001188 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001189 return(NULL);
1190 }
1191 ret->max_attributes = table->max_attributes;
1192 ret->nb_attributes = table->nb_attributes;
1193 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001194 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +00001195 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001196 if (cur == NULL) {
1197 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001198 xmlFree(ret);
1199 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001200 return(NULL);
1201 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001202 memset(cur, 0, sizeof(xmlAttribute));
1203 /* !!! cur->type = XML_ATTRIBUTE_DECL; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001204 ret->table[i] = cur;
Daniel Veillardcf461992000-03-14 18:30:20 +00001205 cur->atype = attr->atype;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001206 cur->def = attr->def;
1207 cur->tree = xmlCopyEnumeration(attr->tree);
1208 if (attr->elem != NULL)
1209 cur->elem = xmlStrdup(attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001210 if (attr->name != NULL)
1211 cur->name = xmlStrdup(attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001212 if (attr->defaultValue != NULL)
1213 cur->defaultValue = xmlStrdup(attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001214 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +00001215 }
1216 return(ret);
1217}
1218
1219/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001220 * xmlDumpAttributeDecl:
1221 * @buf: the XML buffer output
1222 * @attr: An attribute declaration
1223 *
1224 * This will dump the content of the attribute declaration as an XML
1225 * DTD definition
1226 */
1227void
1228xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1229 xmlBufferWriteChar(buf, "<!ATTLIST ");
1230 xmlBufferWriteCHAR(buf, attr->elem);
1231 xmlBufferWriteChar(buf, " ");
Daniel Veillardbe803962000-06-28 23:40:59 +00001232 if (attr->prefix != NULL) {
1233 xmlBufferWriteCHAR(buf, attr->prefix);
1234 xmlBufferWriteChar(buf, ":");
1235 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001236 xmlBufferWriteCHAR(buf, attr->name);
1237 switch (attr->atype) {
1238 case XML_ATTRIBUTE_CDATA:
1239 xmlBufferWriteChar(buf, " CDATA");
1240 break;
1241 case XML_ATTRIBUTE_ID:
1242 xmlBufferWriteChar(buf, " ID");
1243 break;
1244 case XML_ATTRIBUTE_IDREF:
1245 xmlBufferWriteChar(buf, " IDREF");
1246 break;
1247 case XML_ATTRIBUTE_IDREFS:
1248 xmlBufferWriteChar(buf, " IDREFS");
1249 break;
1250 case XML_ATTRIBUTE_ENTITY:
1251 xmlBufferWriteChar(buf, " ENTITY");
1252 break;
1253 case XML_ATTRIBUTE_ENTITIES:
1254 xmlBufferWriteChar(buf, " ENTITIES");
1255 break;
1256 case XML_ATTRIBUTE_NMTOKEN:
1257 xmlBufferWriteChar(buf, " NMTOKEN");
1258 break;
1259 case XML_ATTRIBUTE_NMTOKENS:
1260 xmlBufferWriteChar(buf, " NMTOKENS");
1261 break;
1262 case XML_ATTRIBUTE_ENUMERATION:
1263 xmlBufferWriteChar(buf, " (");
1264 xmlDumpEnumeration(buf, attr->tree);
1265 break;
1266 case XML_ATTRIBUTE_NOTATION:
1267 xmlBufferWriteChar(buf, " NOTATION (");
1268 xmlDumpEnumeration(buf, attr->tree);
1269 break;
1270 default:
1271 fprintf(stderr,
1272 "xmlDumpAttributeTable: internal: unknown type %d\n",
1273 attr->atype);
1274 }
1275 switch (attr->def) {
1276 case XML_ATTRIBUTE_NONE:
1277 break;
1278 case XML_ATTRIBUTE_REQUIRED:
1279 xmlBufferWriteChar(buf, " #REQUIRED");
1280 break;
1281 case XML_ATTRIBUTE_IMPLIED:
1282 xmlBufferWriteChar(buf, " #IMPLIED");
1283 break;
1284 case XML_ATTRIBUTE_FIXED:
1285 xmlBufferWriteChar(buf, " #FIXED");
1286 break;
1287 default:
1288 fprintf(stderr,
1289 "xmlDumpAttributeTable: internal: unknown default %d\n",
1290 attr->def);
1291 }
1292 if (attr->defaultValue != NULL) {
1293 xmlBufferWriteChar(buf, " ");
1294 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1295 }
1296 xmlBufferWriteChar(buf, ">\n");
1297}
1298
1299/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001300 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001301 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001302 * @table: An attribute table
1303 *
1304 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001305 */
1306void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001307xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001308 int i;
1309 xmlAttributePtr cur;
1310
1311 if (table == NULL) return;
1312
1313 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001314 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001315 xmlDumpAttributeDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001316 }
1317}
1318
1319/************************************************************************
1320 * *
1321 * NOTATIONs *
1322 * *
1323 ************************************************************************/
1324/**
1325 * xmlCreateNotationTable:
1326 *
1327 * create and initialize an empty notation hash table.
1328 *
1329 * Returns the xmlNotationTablePtr just created or NULL in case
1330 * of error.
1331 */
1332xmlNotationTablePtr
1333xmlCreateNotationTable(void) {
1334 xmlNotationTablePtr ret;
1335
1336 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001337 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001338 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001339 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001340 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001341 return(NULL);
1342 }
1343 ret->max_notations = XML_MIN_NOTATION_TABLE;
1344 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001345 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001346 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001347 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001348 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001349 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001350 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001351 return(NULL);
1352 }
1353 return(ret);
1354}
1355
1356
1357/**
1358 * xmlAddNotationDecl:
1359 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001360 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001361 * @name: the entity name
1362 * @PublicID: the public identifier or NULL
1363 * @SystemID: the system identifier or NULL
1364 *
1365 * Register a new notation declaration
1366 *
1367 * Returns NULL if not, othervise the entity
1368 */
1369xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001370xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1371 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001372 xmlNotationPtr ret, cur;
1373 xmlNotationTablePtr table;
1374 int i;
1375
1376 if (dtd == NULL) {
1377 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1378 return(NULL);
1379 }
1380 if (name == NULL) {
1381 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1382 return(NULL);
1383 }
1384 if ((PublicID == NULL) && (SystemID == NULL)) {
1385 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1386 }
1387
1388 /*
1389 * Create the Notation table if needed.
1390 */
1391 table = dtd->notations;
1392 if (table == NULL)
1393 table = dtd->notations = xmlCreateNotationTable();
1394 if (table == NULL) {
1395 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1396 return(NULL);
1397 }
1398
1399 /*
1400 * Validity Check:
1401 * Search the DTD for previous declarations of the ATTLIST
1402 */
1403 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001404 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001405 if (!xmlStrcmp(cur->name, name)) {
1406 /*
1407 * The notation is already defined in this Dtd.
1408 */
1409 fprintf(stderr,
1410 "xmlAddNotationDecl: %s already defined\n", name);
1411 }
1412 }
1413
1414 /*
1415 * Grow the table, if needed.
1416 */
1417 if (table->nb_notations >= table->max_notations) {
1418 /*
1419 * need more notations.
1420 */
1421 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001422 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001423 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001424 sizeof(xmlNotationPtr));
1425 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001426 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1427 return(NULL);
1428 }
1429 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001430 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001431 if (ret == NULL) {
1432 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1433 return(NULL);
1434 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001435 memset(ret, 0, sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001436 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001437
1438 /*
1439 * fill the structure.
1440 */
1441 ret->name = xmlStrdup(name);
1442 if (SystemID != NULL)
1443 ret->SystemID = xmlStrdup(SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001444 if (PublicID != NULL)
1445 ret->PublicID = xmlStrdup(PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001446 table->nb_notations++;
1447
1448 return(ret);
1449}
1450
1451/**
1452 * xmlFreeNotation:
1453 * @not: A notation
1454 *
1455 * Deallocate the memory used by an notation definition
1456 */
1457void
1458xmlFreeNotation(xmlNotationPtr nota) {
1459 if (nota == NULL) return;
1460 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001461 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001462 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001463 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001464 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001465 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001466 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001467 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001468}
1469
1470/**
1471 * xmlFreeNotationTable:
1472 * @table: An notation table
1473 *
1474 * Deallocate the memory used by an entities hash table.
1475 */
1476void
1477xmlFreeNotationTable(xmlNotationTablePtr table) {
1478 int i;
1479
1480 if (table == NULL) return;
1481
1482 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001483 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001484 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001485 xmlFree(table->table);
1486 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001487}
1488
1489/**
1490 * xmlCopyNotationTable:
1491 * @table: A notation table
1492 *
1493 * Build a copy of a notation table.
1494 *
1495 * Returns the new xmlNotationTablePtr or NULL in case of error.
1496 */
1497xmlNotationTablePtr
1498xmlCopyNotationTable(xmlNotationTablePtr table) {
1499 xmlNotationTablePtr ret;
1500 xmlNotationPtr cur, nota;
1501 int i;
1502
Daniel Veillard6454aec1999-09-02 22:04:43 +00001503 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001504 if (ret == NULL) {
1505 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1506 return(NULL);
1507 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001508 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001509 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001510 if (ret->table == NULL) {
1511 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001512 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001513 return(NULL);
1514 }
1515 ret->max_notations = table->max_notations;
1516 ret->nb_notations = table->nb_notations;
1517 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001518 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001519 if (cur == NULL) {
1520 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001521 xmlFree(ret);
1522 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001523 return(NULL);
1524 }
1525 ret->table[i] = cur;
1526 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001527 if (nota->name != NULL)
1528 cur->name = xmlStrdup(nota->name);
1529 else
1530 cur->name = NULL;
1531 if (nota->PublicID != NULL)
1532 cur->PublicID = xmlStrdup(nota->PublicID);
1533 else
1534 cur->PublicID = NULL;
1535 if (nota->SystemID != NULL)
1536 cur->SystemID = xmlStrdup(nota->SystemID);
1537 else
1538 cur->SystemID = NULL;
1539 }
1540 return(ret);
1541}
1542
1543/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001544 * xmlDumpNotationDecl:
1545 * @buf: the XML buffer output
1546 * @nota: A notation declaration
1547 *
1548 * This will dump the content the notation declaration as an XML DTD definition
1549 */
1550void
1551xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
1552 xmlBufferWriteChar(buf, "<!NOTATION ");
1553 xmlBufferWriteCHAR(buf, nota->name);
1554 if (nota->PublicID != NULL) {
1555 xmlBufferWriteChar(buf, " PUBLIC ");
1556 xmlBufferWriteQuotedString(buf, nota->PublicID);
1557 if (nota->SystemID != NULL) {
1558 xmlBufferWriteChar(buf, " ");
1559 xmlBufferWriteCHAR(buf, nota->SystemID);
1560 }
1561 } else {
1562 xmlBufferWriteChar(buf, " SYSTEM ");
1563 xmlBufferWriteCHAR(buf, nota->SystemID);
1564 }
1565 xmlBufferWriteChar(buf, " >\n");
1566}
1567
1568/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001569 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001570 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001571 * @table: A notation table
1572 *
1573 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001574 */
1575void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001576xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001577 int i;
1578 xmlNotationPtr cur;
1579
1580 if (table == NULL) return;
1581
1582 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001583 cur = table->table[i];
Daniel Veillardcf461992000-03-14 18:30:20 +00001584 xmlDumpNotationDecl(buf, cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001585 }
1586}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001587
1588/************************************************************************
1589 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001590 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001591 * *
1592 ************************************************************************/
1593/**
1594 * xmlCreateIDTable:
1595 *
1596 * create and initialize an empty id hash table.
1597 *
1598 * Returns the xmlIDTablePtr just created or NULL in case
1599 * of error.
1600 */
1601xmlIDTablePtr
1602xmlCreateIDTable(void) {
1603 xmlIDTablePtr ret;
1604
1605 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001606 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001607 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001608 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001609 (long)sizeof(xmlIDTable));
1610 return(NULL);
1611 }
1612 ret->max_ids = XML_MIN_NOTATION_TABLE;
1613 ret->nb_ids = 0;
1614 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001615 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001616 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001617 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001618 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001619 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001620 return(NULL);
1621 }
1622 return(ret);
1623}
1624
1625
1626/**
1627 * xmlAddID:
1628 * @ctxt: the validation context
1629 * @doc: pointer to the document
1630 * @value: the value name
1631 * @attr: the attribute holding the ID
1632 *
1633 * Register a new id declaration
1634 *
1635 * Returns NULL if not, othervise the new xmlIDPtr
1636 */
1637xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001638xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001639 xmlAttrPtr attr) {
1640 xmlIDPtr ret, cur;
1641 xmlIDTablePtr table;
1642 int i;
1643
1644 if (doc == NULL) {
1645 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1646 return(NULL);
1647 }
1648 if (value == NULL) {
1649 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1650 return(NULL);
1651 }
1652 if (attr == NULL) {
1653 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1654 return(NULL);
1655 }
1656
1657 /*
1658 * Create the ID table if needed.
1659 */
1660 table = doc->ids;
1661 if (table == NULL)
1662 table = doc->ids = xmlCreateIDTable();
1663 if (table == NULL) {
1664 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1665 return(NULL);
1666 }
1667
1668 /*
1669 * Validity Check:
1670 * Search the DTD for previous declarations of the ATTLIST
1671 */
1672 for (i = 0;i < table->nb_ids;i++) {
1673 cur = table->table[i];
1674 if (!xmlStrcmp(cur->value, value)) {
1675 /*
1676 * The id is already defined in this Dtd.
1677 */
1678 VERROR(ctxt->userData, "ID %s already defined\n", value);
1679 return(NULL);
1680 }
1681 }
1682
1683 /*
1684 * Grow the table, if needed.
1685 */
1686 if (table->nb_ids >= table->max_ids) {
1687 /*
1688 * need more ids.
1689 */
1690 table->max_ids *= 2;
1691 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001692 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001693 sizeof(xmlIDPtr));
1694 if (table->table == NULL) {
1695 fprintf(stderr, "xmlAddID: out of memory\n");
1696 return(NULL);
1697 }
1698 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001699 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001700 if (ret == NULL) {
1701 fprintf(stderr, "xmlAddID: out of memory\n");
1702 return(NULL);
1703 }
1704 table->table[table->nb_ids] = ret;
1705
1706 /*
1707 * fill the structure.
1708 */
1709 ret->value = xmlStrdup(value);
1710 ret->attr = attr;
1711 table->nb_ids++;
1712
1713 return(ret);
1714}
1715
1716/**
1717 * xmlFreeID:
1718 * @not: A id
1719 *
1720 * Deallocate the memory used by an id definition
1721 */
1722void
1723xmlFreeID(xmlIDPtr id) {
1724 if (id == NULL) return;
1725 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001726 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001727 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001728 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001729}
1730
1731/**
1732 * xmlFreeIDTable:
1733 * @table: An id table
1734 *
1735 * Deallocate the memory used by an ID hash table.
1736 */
1737void
1738xmlFreeIDTable(xmlIDTablePtr table) {
1739 int i;
1740
1741 if (table == NULL) return;
1742
1743 for (i = 0;i < table->nb_ids;i++) {
1744 xmlFreeID(table->table[i]);
1745 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001746 xmlFree(table->table);
1747 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001748}
1749
1750/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001751 * xmlIsID:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001752 * @doc: the document
1753 * @elem: the element carrying the attribute
1754 * @attr: the attribute
1755 *
1756 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1757 * then this is simple, otherwise we use an heuristic: name ID (upper
1758 * or lowercase).
1759 *
1760 * Returns 0 or 1 depending on the lookup result
1761 */
1762int
1763xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00001764 if (doc == NULL) return(0);
1765 if (attr == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001766 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1767 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1768 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1769 (attr->name[2] == 0)) return(1);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001770 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1771 if ((!xmlStrcmp(BAD_CAST "id", attr->name)) ||
1772 (!xmlStrcmp(BAD_CAST "name", attr->name)))
1773 return(1);
1774 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001775 } else {
1776 xmlAttributePtr attrDecl;
1777
Daniel Veillard71b656e2000-01-05 14:46:17 +00001778 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001779 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1780 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1781 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1782 attr->name);
1783
Daniel Veillardcf461992000-03-14 18:30:20 +00001784 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001785 return(1);
1786 }
1787 return(0);
1788}
1789
Daniel Veillardb96e6431999-08-29 21:02:19 +00001790/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001791 * xmlRemoveID
1792 * @doc: the document
1793 * @attr: the attribute
1794 *
1795 * Remove the given attribute from the ID table maintained internally.
1796 *
1797 * Returns -1 if the lookup failed and 0 otherwise
1798 */
1799int
1800xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1801 xmlIDPtr cur;
1802 xmlIDTablePtr table;
1803 int i;
1804
1805 if (doc == NULL) return(-1);
1806 if (attr == NULL) return(-1);
1807 table = doc->ids;
1808 if (table == NULL)
1809 return(-1);
1810
1811 /*
1812 * Search the ID list.
1813 */
1814 for (i = 0;i < table->nb_ids;i++) {
1815 cur = table->table[i];
1816 if (cur->attr == attr) {
1817 table->nb_ids--;
1818 memmove(&table->table[i], &table->table[i+1],
1819 (table->nb_ids - i) * sizeof(xmlIDPtr));
1820 return(0);
1821 }
1822 }
1823 return(-1);
1824}
1825
1826/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001827 * xmlGetID:
1828 * @doc: pointer to the document
1829 * @ID: the ID value
1830 *
1831 * Search the attribute declaring the given ID
1832 *
1833 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1834 */
1835xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001836xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001837 xmlIDPtr cur;
1838 xmlIDTablePtr table;
1839 int i;
1840
1841 if (doc == NULL) {
1842 fprintf(stderr, "xmlGetID: doc == NULL\n");
1843 return(NULL);
1844 }
1845
1846 if (ID == NULL) {
1847 fprintf(stderr, "xmlGetID: ID == NULL\n");
1848 return(NULL);
1849 }
1850
1851 table = doc->ids;
1852 if (table == NULL)
1853 return(NULL);
1854
1855 /*
1856 * Search the ID list.
1857 */
1858 for (i = 0;i < table->nb_ids;i++) {
1859 cur = table->table[i];
1860 if (!xmlStrcmp(cur->value, ID)) {
1861 return(cur->attr);
1862 }
1863 }
1864 return(NULL);
1865}
1866
Daniel Veillard991e63d1999-08-15 23:32:28 +00001867/************************************************************************
1868 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001869 * Refs *
1870 * *
1871 ************************************************************************/
1872/**
1873 * xmlCreateRefTable:
1874 *
1875 * create and initialize an empty ref hash table.
1876 *
1877 * Returns the xmlRefTablePtr just created or NULL in case
1878 * of error.
1879 */
1880xmlRefTablePtr
1881xmlCreateRefTable(void) {
1882 xmlRefTablePtr ret;
1883
1884 ret = (xmlRefTablePtr)
1885 xmlMalloc(sizeof(xmlRefTable));
1886 if (ret == NULL) {
1887 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1888 (long)sizeof(xmlRefTable));
1889 return(NULL);
1890 }
1891 ret->max_refs = XML_MIN_NOTATION_TABLE;
1892 ret->nb_refs = 0;
1893 ret->table = (xmlRefPtr *)
1894 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1895 if (ret == NULL) {
1896 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1897 ret->max_refs * (long)sizeof(xmlRef));
1898 xmlFree(ret);
1899 return(NULL);
1900 }
1901 return(ret);
1902}
1903
1904
1905/**
1906 * xmlAddRef:
1907 * @ctxt: the validation context
1908 * @doc: pointer to the document
1909 * @value: the value name
1910 * @attr: the attribute holding the Ref
1911 *
1912 * Register a new ref declaration
1913 *
1914 * Returns NULL if not, othervise the new xmlRefPtr
1915 */
1916xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001917xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001918 xmlAttrPtr attr) {
1919 xmlRefPtr ret;
1920 xmlRefTablePtr table;
1921
1922 if (doc == NULL) {
1923 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1924 return(NULL);
1925 }
1926 if (value == NULL) {
1927 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1928 return(NULL);
1929 }
1930 if (attr == NULL) {
1931 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1932 return(NULL);
1933 }
1934
1935 /*
1936 * Create the Ref table if needed.
1937 */
1938 table = doc->refs;
1939 if (table == NULL)
1940 table = doc->refs = xmlCreateRefTable();
1941 if (table == NULL) {
1942 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1943 return(NULL);
1944 }
1945
1946 /*
1947 * Grow the table, if needed.
1948 */
1949 if (table->nb_refs >= table->max_refs) {
1950 /*
1951 * need more refs.
1952 */
1953 table->max_refs *= 2;
1954 table->table = (xmlRefPtr *)
1955 xmlRealloc(table->table, table->max_refs *
1956 sizeof(xmlRefPtr));
1957 if (table->table == NULL) {
1958 fprintf(stderr, "xmlAddRef: out of memory\n");
1959 return(NULL);
1960 }
1961 }
1962 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1963 if (ret == NULL) {
1964 fprintf(stderr, "xmlAddRef: out of memory\n");
1965 return(NULL);
1966 }
1967 table->table[table->nb_refs] = ret;
1968
1969 /*
1970 * fill the structure.
1971 */
1972 ret->value = xmlStrdup(value);
1973 ret->attr = attr;
1974 table->nb_refs++;
1975
1976 return(ret);
1977}
1978
1979/**
1980 * xmlFreeRef:
1981 * @not: A ref
1982 *
1983 * Deallocate the memory used by an ref definition
1984 */
1985void
1986xmlFreeRef(xmlRefPtr ref) {
1987 if (ref == NULL) return;
1988 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001989 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001990 memset(ref, -1, sizeof(xmlRef));
1991 xmlFree(ref);
1992}
1993
1994/**
1995 * xmlFreeRefTable:
1996 * @table: An ref table
1997 *
1998 * Deallocate the memory used by an Ref hash table.
1999 */
2000void
2001xmlFreeRefTable(xmlRefTablePtr table) {
2002 int i;
2003
2004 if (table == NULL) return;
2005
2006 for (i = 0;i < table->nb_refs;i++) {
2007 xmlFreeRef(table->table[i]);
2008 }
2009 xmlFree(table->table);
2010 xmlFree(table);
2011}
2012
2013/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002014 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002015 * @doc: the document
2016 * @elem: the element carrying the attribute
2017 * @attr: the attribute
2018 *
2019 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
2020 * then this is simple, otherwise we use an heuristic: name Ref (upper
2021 * or lowercase).
2022 *
2023 * Returns 0 or 1 depending on the lookup result
2024 */
2025int
2026xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2027 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2028 return(0);
2029 /*******************
2030 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
2031 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
2032 (attr->name[2] == 0)) return(1);
2033 *******************/
Daniel Veillardd83eb822000-06-30 18:39:56 +00002034 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2035 /* TODO @@@ */
2036 return(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002037 } else {
2038 xmlAttributePtr attrDecl;
2039
2040 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2041 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2042 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2043 attr->name);
2044
Daniel Veillardcf461992000-03-14 18:30:20 +00002045 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002046 return(1);
2047 }
2048 return(0);
2049}
2050
2051/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002052 * xmlRemoveRef
2053 * @doc: the document
2054 * @attr: the attribute
2055 *
2056 * Remove the given attribute from the Ref table maintained internally.
2057 *
2058 * Returns -1 if the lookup failed and 0 otherwise
2059 */
2060int
2061xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2062 xmlRefPtr cur;
2063 xmlRefTablePtr table;
2064 int i;
2065
2066 if (doc == NULL) return(-1);
2067 if (attr == NULL) return(-1);
2068 table = doc->refs;
2069 if (table == NULL)
2070 return(-1);
2071
2072 /*
2073 * Search the Ref list.
2074 */
2075 for (i = 0;i < table->nb_refs;i++) {
2076 cur = table->table[i];
2077 if (cur->attr == attr) {
2078 table->nb_refs--;
2079 memmove(&table->table[i], &table->table[i+1],
2080 (table->nb_refs - i) * sizeof(xmlRefPtr));
2081 return(0);
2082 }
2083 }
2084 return(-1);
2085}
2086
2087/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002088 * xmlGetRef:
2089 * @doc: pointer to the document
2090 * @Ref: the Ref value
2091 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00002092 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002093 *
2094 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
2095 */
2096xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002097xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002098 xmlRefPtr cur;
2099 xmlRefTablePtr table;
2100 int i;
2101
2102 if (doc == NULL) {
2103 fprintf(stderr, "xmlGetRef: doc == NULL\n");
2104 return(NULL);
2105 }
2106
2107 if (Ref == NULL) {
2108 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
2109 return(NULL);
2110 }
2111
2112 table = doc->refs;
2113 if (table == NULL)
2114 return(NULL);
2115
2116 /*
2117 * Search the Ref list.
2118 */
2119 for (i = 0;i < table->nb_refs;i++) {
2120 cur = table->table[i];
2121 if (!xmlStrcmp(cur->value, Ref)) {
2122 return(cur->attr);
2123 }
2124 }
2125 return(NULL);
2126}
2127
2128/************************************************************************
2129 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002130 * Routines for validity checking *
2131 * *
2132 ************************************************************************/
2133
2134/**
2135 * xmlGetDtdElementDesc:
2136 * @dtd: a pointer to the DtD to search
2137 * @name: the element name
2138 *
2139 * Search the Dtd for the description of this element
2140 *
2141 * returns the xmlElementPtr if found or NULL
2142 */
2143
2144xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002145xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002146 xmlElementTablePtr table;
2147 xmlElementPtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002148 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002149 int i;
2150
2151 if (dtd == NULL) return(NULL);
2152 if (dtd->elements == NULL) return(NULL);
2153 table = dtd->elements;
2154
2155 for (i = 0;i < table->nb_elements;i++) {
2156 cur = table->table[i];
2157 if (!xmlStrcmp(cur->name, name))
2158 return(cur);
2159 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002160
2161 /*
2162 * Specific case if name is a QName.
2163 */
2164 uqname = xmlSplitQName2(name, &prefix);
2165 if (uqname == NULL) return(NULL);
2166
2167 for (i = 0;i < table->nb_elements;i++) {
2168 cur = table->table[i];
2169 if ((!xmlStrcmp(cur->name, uqname)) &&
2170 ((prefix == cur->prefix) ||
2171 ((prefix != NULL) && (cur->prefix != NULL) &&
2172 (!xmlStrcmp(cur->prefix, prefix))))) {
2173 if (prefix != NULL) xmlFree(prefix);
2174 if (uqname != NULL) xmlFree(uqname);
2175 return(cur);
2176 }
2177 }
2178 if (prefix != NULL) xmlFree(prefix);
2179 if (uqname != NULL) xmlFree(uqname);
2180 return(NULL);
2181}
2182
2183/**
2184 * xmlGetDtdQElementDesc:
2185 * @dtd: a pointer to the DtD to search
2186 * @name: the element name
2187 * @prefix: the element namespace prefix
2188 *
2189 * Search the Dtd for the description of this element
2190 *
2191 * returns the xmlElementPtr if found or NULL
2192 */
2193
2194xmlElementPtr
2195xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2196 const xmlChar *prefix) {
2197 xmlElementTablePtr table;
2198 xmlElementPtr cur;
2199 int i;
2200
2201 if (dtd == NULL) return(NULL);
2202 if (dtd->elements == NULL) return(NULL);
2203 table = dtd->elements;
2204
2205 for (i = 0;i < table->nb_elements;i++) {
2206 cur = table->table[i];
2207 if (!xmlStrcmp(cur->name, name) &&
2208 ((prefix == cur->prefix) ||
2209 ((prefix != NULL) && (cur->prefix != NULL) &&
2210 (!xmlStrcmp(cur->prefix, prefix)))))
2211 return(cur);
2212 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002213 return(NULL);
2214}
2215
2216/**
2217 * xmlGetDtdAttrDesc:
2218 * @dtd: a pointer to the DtD to search
2219 * @elem: the element name
2220 * @name: the attribute name
2221 *
2222 * Search the Dtd for the description of this attribute on
2223 * this element.
2224 *
2225 * returns the xmlAttributePtr if found or NULL
2226 */
2227
2228xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002229xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002230 xmlAttributeTablePtr table;
2231 xmlAttributePtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002232 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002233 int i;
2234
2235 if (dtd == NULL) return(NULL);
2236 if (dtd->attributes == NULL) return(NULL);
2237 table = dtd->attributes;
2238
2239 for (i = 0;i < table->nb_attributes;i++) {
2240 cur = table->table[i];
2241 if ((!xmlStrcmp(cur->name, name)) &&
2242 (!xmlStrcmp(cur->elem, elem)))
2243 return(cur);
2244 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002245
2246 /*
2247 * Specific case if name is a QName.
2248 */
2249 uqname = xmlSplitQName2(name, &prefix);
2250 if (uqname == NULL) return(NULL);
2251
2252 for (i = 0;i < table->nb_attributes;i++) {
2253 cur = table->table[i];
2254 if ((!xmlStrcmp(cur->name, uqname)) &&
2255 (!xmlStrcmp(cur->elem, elem)) &&
2256 ((prefix == cur->prefix) ||
2257 ((prefix != NULL) && (cur->prefix != NULL) &&
2258 (!xmlStrcmp(cur->prefix, prefix))))) {
2259 if (prefix != NULL) xmlFree(prefix);
2260 if (uqname != NULL) xmlFree(uqname);
2261 return(cur);
2262 }
2263 }
2264 if (prefix != NULL) xmlFree(prefix);
2265 if (uqname != NULL) xmlFree(uqname);
2266 return(NULL);
2267}
2268
2269/**
2270 * xmlGetDtdQAttrDesc:
2271 * @dtd: a pointer to the DtD to search
2272 * @elem: the element name
2273 * @name: the attribute name
2274 * @prefix: the attribute namespace prefix
2275 *
2276 * Search the Dtd for the description of this qualified attribute on
2277 * this element.
2278 *
2279 * returns the xmlAttributePtr if found or NULL
2280 */
2281
2282xmlAttributePtr
2283xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2284 const xmlChar *prefix) {
2285 xmlAttributeTablePtr table;
2286 xmlAttributePtr cur;
2287 int i;
2288
2289 if (dtd == NULL) return(NULL);
2290 if (dtd->attributes == NULL) return(NULL);
2291 table = dtd->attributes;
2292
2293 for (i = 0;i < table->nb_attributes;i++) {
2294 cur = table->table[i];
2295 if ((!xmlStrcmp(cur->name, name)) &&
2296 (!xmlStrcmp(cur->elem, elem)) &&
2297 ((prefix == cur->prefix) ||
2298 ((prefix != NULL) && (cur->prefix != NULL) &&
2299 (!xmlStrcmp(cur->prefix, prefix)))))
2300 return(cur);
2301 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002302 return(NULL);
2303}
2304
2305/**
2306 * xmlGetDtdNotationDesc:
2307 * @dtd: a pointer to the DtD to search
2308 * @name: the notation name
2309 *
2310 * Search the Dtd for the description of this notation
2311 *
2312 * returns the xmlNotationPtr if found or NULL
2313 */
2314
2315xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002316xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002317 xmlNotationTablePtr table;
2318 xmlNotationPtr cur;
2319 int i;
2320
2321 if (dtd == NULL) return(NULL);
2322 if (dtd->notations == NULL) return(NULL);
2323 table = dtd->notations;
2324
2325 for (i = 0;i < table->nb_notations;i++) {
2326 cur = table->table[i];
2327 if (!xmlStrcmp(cur->name, name))
2328 return(cur);
2329 }
2330 return(NULL);
2331}
2332
2333/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002334 * xmlValidateNotationUse:
2335 * @ctxt: the validation context
2336 * @doc: the document
2337 * @notationName: the notation name to check
2338 *
2339 * Validate that the given mame match a notation declaration.
2340 * - [ VC: Notation Declared ]
2341 *
2342 * returns 1 if valid or 0 otherwise
2343 */
2344
2345int
2346xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002347 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002348 xmlNotationPtr notaDecl;
2349 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2350
2351 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2352 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2353 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2354
2355 if (notaDecl == NULL) {
2356 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2357 notationName);
2358 return(0);
2359 }
2360 return(1);
2361}
2362
2363/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002364 * xmlIsMixedElement
2365 * @doc: the document
2366 * @name: the element name
2367 *
2368 * Search in the DtDs whether an element accept Mixed content (or ANY)
2369 * basically if it is supposed to accept text childs
2370 *
2371 * returns 0 if no, 1 if yes, and -1 if no element description is available
2372 */
2373
2374int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002375xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002376 xmlElementPtr elemDecl;
2377
2378 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2379
2380 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2381 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2382 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2383 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002384 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002385 case XML_ELEMENT_TYPE_ELEMENT:
2386 return(0);
2387 case XML_ELEMENT_TYPE_EMPTY:
2388 /*
2389 * return 1 for EMPTY since we want VC error to pop up
2390 * on <empty> </empty> for example
2391 */
2392 case XML_ELEMENT_TYPE_ANY:
2393 case XML_ELEMENT_TYPE_MIXED:
2394 return(1);
2395 }
2396 return(1);
2397}
2398
2399/**
2400 * xmlValidateNameValue:
2401 * @value: an Name value
2402 *
2403 * Validate that the given value match Name production
2404 *
2405 * returns 1 if valid or 0 otherwise
2406 */
2407
2408int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002409xmlValidateNameValue(const xmlChar *value) {
2410 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002411
2412 if (value == NULL) return(0);
2413 cur = value;
2414
2415 if (!IS_LETTER(*cur) && (*cur != '_') &&
2416 (*cur != ':')) {
2417 return(0);
2418 }
2419
2420 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2421 (*cur == '.') || (*cur == '-') ||
2422 (*cur == '_') || (*cur == ':') ||
2423 (IS_COMBINING(*cur)) ||
2424 (IS_EXTENDER(*cur)))
2425 cur++;
2426
2427 if (*cur != 0) return(0);
2428
2429 return(1);
2430}
2431
2432/**
2433 * xmlValidateNamesValue:
2434 * @value: an Names value
2435 *
2436 * Validate that the given value match Names production
2437 *
2438 * returns 1 if valid or 0 otherwise
2439 */
2440
2441int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002442xmlValidateNamesValue(const xmlChar *value) {
2443 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002444
2445 if (value == NULL) return(0);
2446 cur = value;
2447
2448 if (!IS_LETTER(*cur) && (*cur != '_') &&
2449 (*cur != ':')) {
2450 return(0);
2451 }
2452
2453 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2454 (*cur == '.') || (*cur == '-') ||
2455 (*cur == '_') || (*cur == ':') ||
2456 (IS_COMBINING(*cur)) ||
2457 (IS_EXTENDER(*cur)))
2458 cur++;
2459
2460 while (IS_BLANK(*cur)) {
2461 while (IS_BLANK(*cur)) cur++;
2462
2463 if (!IS_LETTER(*cur) && (*cur != '_') &&
2464 (*cur != ':')) {
2465 return(0);
2466 }
2467
2468 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2469 (*cur == '.') || (*cur == '-') ||
2470 (*cur == '_') || (*cur == ':') ||
2471 (IS_COMBINING(*cur)) ||
2472 (IS_EXTENDER(*cur)))
2473 cur++;
2474 }
2475
2476 if (*cur != 0) return(0);
2477
2478 return(1);
2479}
2480
2481/**
2482 * xmlValidateNmtokenValue:
2483 * @value: an Mntoken value
2484 *
2485 * Validate that the given value match Nmtoken production
2486 *
2487 * [ VC: Name Token ]
2488 *
2489 * returns 1 if valid or 0 otherwise
2490 */
2491
2492int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002493xmlValidateNmtokenValue(const xmlChar *value) {
2494 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002495
2496 if (value == NULL) return(0);
2497 cur = value;
2498
2499 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2500 (*cur != '.') && (*cur != '-') &&
2501 (*cur != '_') && (*cur != ':') &&
2502 (!IS_COMBINING(*cur)) &&
2503 (!IS_EXTENDER(*cur)))
2504 return(0);
2505
2506 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2507 (*cur == '.') || (*cur == '-') ||
2508 (*cur == '_') || (*cur == ':') ||
2509 (IS_COMBINING(*cur)) ||
2510 (IS_EXTENDER(*cur)))
2511 cur++;
2512
2513 if (*cur != 0) return(0);
2514
2515 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002516}
2517
2518/**
2519 * xmlValidateNmtokensValue:
2520 * @value: an Mntokens value
2521 *
2522 * Validate that the given value match Nmtokens production
2523 *
2524 * [ VC: Name Token ]
2525 *
2526 * returns 1 if valid or 0 otherwise
2527 */
2528
2529int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002530xmlValidateNmtokensValue(const xmlChar *value) {
2531 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002532
2533 if (value == NULL) return(0);
2534 cur = value;
2535
Daniel Veillardcf461992000-03-14 18:30:20 +00002536 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002537 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2538 (*cur != '.') && (*cur != '-') &&
2539 (*cur != '_') && (*cur != ':') &&
2540 (!IS_COMBINING(*cur)) &&
2541 (!IS_EXTENDER(*cur)))
2542 return(0);
2543
2544 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2545 (*cur == '.') || (*cur == '-') ||
2546 (*cur == '_') || (*cur == ':') ||
2547 (IS_COMBINING(*cur)) ||
2548 (IS_EXTENDER(*cur)))
2549 cur++;
2550
2551 while (IS_BLANK(*cur)) {
2552 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002553 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002554
2555 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2556 (*cur != '.') && (*cur != '-') &&
2557 (*cur != '_') && (*cur != ':') &&
2558 (!IS_COMBINING(*cur)) &&
2559 (!IS_EXTENDER(*cur)))
2560 return(0);
2561
2562 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2563 (*cur == '.') || (*cur == '-') ||
2564 (*cur == '_') || (*cur == ':') ||
2565 (IS_COMBINING(*cur)) ||
2566 (IS_EXTENDER(*cur)))
2567 cur++;
2568 }
2569
2570 if (*cur != 0) return(0);
2571
2572 return(1);
2573}
2574
2575/**
2576 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002577 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002578 * @doc: a document instance
2579 * @nota: a notation definition
2580 *
2581 * Try to validate a single notation definition
2582 * basically it does the following checks as described by the
2583 * XML-1.0 recommendation:
2584 * - it seems that no validity constraing exist on notation declarations
2585 * But this function get called anyway ...
2586 *
2587 * returns 1 if valid or 0 otherwise
2588 */
2589
2590int
2591xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2592 xmlNotationPtr nota) {
2593 int ret = 1;
2594
2595 return(ret);
2596}
2597
2598/**
2599 * xmlValidateAttributeValue:
2600 * @type: an attribute type
2601 * @value: an attribute value
2602 *
2603 * Validate that the given attribute value match the proper production
2604 *
2605 * [ VC: ID ]
2606 * Values of type ID must match the Name production....
2607 *
2608 * [ VC: IDREF ]
2609 * Values of type IDREF must match the Name production, and values
2610 * of type IDREFS must match Names ...
2611 *
2612 * [ VC: Entity Name ]
2613 * Values of type ENTITY must match the Name production, values
2614 * of type ENTITIES must match Names ...
2615 *
2616 * [ VC: Name Token ]
2617 * Values of type NMTOKEN must match the Nmtoken production; values
2618 * of type NMTOKENS must match Nmtokens.
2619 *
2620 * returns 1 if valid or 0 otherwise
2621 */
2622
2623int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002624xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002625 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002626 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002627 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002628 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002629 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002630 case XML_ATTRIBUTE_IDREF:
2631 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002632 case XML_ATTRIBUTE_NOTATION:
2633 return(xmlValidateNameValue(value));
2634 case XML_ATTRIBUTE_NMTOKENS:
2635 case XML_ATTRIBUTE_ENUMERATION:
2636 return(xmlValidateNmtokensValue(value));
2637 case XML_ATTRIBUTE_NMTOKEN:
2638 return(xmlValidateNmtokenValue(value));
2639 case XML_ATTRIBUTE_CDATA:
2640 break;
2641 }
2642 return(1);
2643}
2644
2645/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002646 * xmlValidateAttributeValue2:
2647 * @ctxt: the validation context
2648 * @doc: the document
2649 * @name: the attribute name (used for error reporting only)
2650 * @type: the attribute type
2651 * @value: the attribute value
2652 *
2653 * Validate that the given attribute value match a given type.
2654 * This typically cannot be done before having finished parsing
2655 * the subsets.
2656 *
2657 * [ VC: IDREF ]
2658 * Values of type IDREF must match one of the declared IDs
2659 * Values of type IDREFS must match a sequence of the declared IDs
2660 * each Name must match the value of an ID attribute on some element
2661 * in the XML document; i.e. IDREF values must match the value of
2662 * some ID attribute
2663 *
2664 * [ VC: Entity Name ]
2665 * Values of type ENTITY must match one declared entity
2666 * Values of type ENTITIES must match a sequence of declared entities
2667 *
2668 * [ VC: Notation Attributes ]
2669 * all notation names in the declaration must be declared.
2670 *
2671 * returns 1 if valid or 0 otherwise
2672 */
2673
2674int
2675xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2676 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2677 int ret = 1;
2678 switch (type) {
2679 case XML_ATTRIBUTE_IDREFS:
2680 case XML_ATTRIBUTE_IDREF:
2681 case XML_ATTRIBUTE_ID:
2682 case XML_ATTRIBUTE_NMTOKENS:
2683 case XML_ATTRIBUTE_ENUMERATION:
2684 case XML_ATTRIBUTE_NMTOKEN:
2685 case XML_ATTRIBUTE_CDATA:
2686 break;
2687 case XML_ATTRIBUTE_ENTITY: {
2688 xmlEntityPtr ent;
2689
2690 ent = xmlGetDocEntity(doc, value);
2691 if (ent == NULL) {
2692 VERROR(ctxt->userData,
2693 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2694 name, value);
2695 ret = 0;
2696 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2697 VERROR(ctxt->userData,
2698 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2699 name, value);
2700 ret = 0;
2701 }
2702 break;
2703 }
2704 case XML_ATTRIBUTE_ENTITIES: {
2705 xmlChar *dup, *nam = NULL, *cur, save;
2706 xmlEntityPtr ent;
2707
2708 dup = xmlStrdup(value);
2709 if (dup == NULL)
2710 return(0);
2711 cur = dup;
2712 while (*cur != 0) {
2713 nam = cur;
2714 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2715 save = *cur;
2716 *cur = 0;
2717 ent = xmlGetDocEntity(doc, nam);
2718 if (ent == NULL) {
2719 VERROR(ctxt->userData,
2720 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2721 name, nam);
2722 ret = 0;
2723 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2724 VERROR(ctxt->userData,
2725 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2726 name, nam);
2727 ret = 0;
2728 }
2729 if (save == 0)
2730 break;
2731 *cur = save;
2732 while (IS_BLANK(*cur)) cur++;
2733 }
2734 xmlFree(dup);
2735 break;
2736 }
2737 case XML_ATTRIBUTE_NOTATION: {
2738 xmlNotationPtr nota;
2739
2740 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2741 if ((nota == NULL) && (doc->extSubset != NULL))
2742 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2743
2744 if (nota == NULL) {
2745 VERROR(ctxt->userData,
2746 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2747 name, value);
2748 ret = 0;
2749 }
2750 break;
2751 }
2752 }
2753 return(ret);
2754}
2755
2756/**
2757 * xmlValidNormalizeAttributeValue:
2758 * @doc: the document
2759 * @elem: the parent
2760 * @name: the attribute name
2761 * @value: the attribute value
2762 *
2763 * Does the validation related extra step of the normalization of attribute
2764 * values:
2765 *
2766 * If the declared value is not CDATA, then the XML processor must further
2767 * process the normalized attribute value by discarding any leading and
2768 * trailing space (#x20) characters, and by replacing sequences of space
2769 * (#x20) characters by single space (#x20) character.
2770 *
2771 * returns a new normalized string if normalization is needed, NULL otherwise
2772 * the caller must free the returned value.
2773 */
2774
2775xmlChar *
2776xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2777 const xmlChar *name, const xmlChar *value) {
2778 xmlChar *ret, *dst;
2779 const xmlChar *src;
Daniel Veillardbe803962000-06-28 23:40:59 +00002780 xmlAttributePtr attrDecl = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002781
2782 if (doc == NULL) return(NULL);
2783 if (elem == NULL) return(NULL);
2784 if (name == NULL) return(NULL);
2785 if (value == NULL) return(NULL);
2786
Daniel Veillardbe803962000-06-28 23:40:59 +00002787 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2788 xmlChar qname[500];
2789#ifdef HAVE_SNPRINTF
2790 snprintf((char *) qname, sizeof(qname), "%s:%s",
2791 elem->ns->prefix, elem->name);
2792#else
2793 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
2794#endif
2795 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2796 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2797 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2798 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002799 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2800 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2801 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2802
2803 if (attrDecl == NULL)
2804 return(NULL);
2805 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2806 return(NULL);
2807
2808 ret = xmlStrdup(value);
2809 if (ret == NULL)
2810 return(NULL);
2811 src = value;
2812 dst = ret;
2813 while (*src == 0x20) src++;
2814 while (*src != 0) {
2815 if (*src == 0x20) {
2816 while (*src == 0x20) src++;
2817 if (*src != 0)
2818 *dst++ = 0x20;
2819 } else {
2820 *dst++ = *src++;
2821 }
2822 }
2823 *dst = 0;
2824 return(ret);
2825}
2826
2827/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002828 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002829 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002830 * @doc: a document instance
2831 * @attr: an attribute definition
2832 *
2833 * Try to validate a single attribute definition
2834 * basically it does the following checks as described by the
2835 * XML-1.0 recommendation:
2836 * - [ VC: Attribute Default Legal ]
2837 * - [ VC: Enumeration ]
2838 * - [ VC: ID Attribute Default ]
2839 *
2840 * The ID/IDREF uniqueness and matching are done separately
2841 *
2842 * returns 1 if valid or 0 otherwise
2843 */
2844
2845int
2846xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2847 xmlAttributePtr attr) {
2848 int ret = 1;
2849 int val;
2850 CHECK_DTD;
2851 if(attr == NULL) return(1);
2852
2853 /* Attribute Default Legal */
2854 /* Enumeration */
2855 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002856 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002857 if (val == 0) {
2858 VERROR(ctxt->userData,
2859 "Syntax of default value for attribute %s on %s is not valid\n",
2860 attr->name, attr->elem);
2861 }
2862 ret &= val;
2863 }
2864
2865 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002866 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002867 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2868 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2869 VERROR(ctxt->userData,
2870 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2871 attr->name, attr->elem);
2872 ret = 0;
2873 }
2874
Daniel Veillardb96e6431999-08-29 21:02:19 +00002875 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002876 if (attr->atype == XML_ATTRIBUTE_ID) {
2877 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002878
2879 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002880 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002881 attr->elem);
2882 if (elem != NULL) {
2883 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002884 } else {
2885 xmlAttributeTablePtr table;
2886 int i;
2887
2888 /*
2889 * The attribute may be declared in the internal subset and the
2890 * element in the external subset.
2891 */
2892 nbId = 0;
2893 table = doc->intSubset->attributes;
2894 if (table != NULL) {
2895 for (i = 0;i < table->nb_attributes;i++) {
2896 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2897 (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2898 nbId++;
2899 }
2900 }
2901 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002902 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002903 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002904 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002905 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2906 attr->elem, nbId, attr->name);
2907 } else if (doc->extSubset != NULL) {
2908 int extId = 0;
2909 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2910 if (elem != NULL) {
2911 extId = xmlScanIDAttributeDecl(NULL, elem);
2912 }
2913 if (extId > 1) {
2914 VERROR(ctxt->userData,
2915 "Element %s has %d ID attribute defined in the external subset : %s\n",
2916 attr->elem, extId, attr->name);
2917 } else if (extId + nbId > 1) {
2918 VERROR(ctxt->userData,
2919"Element %s has ID attributes defined in the internal and external subset : %s\n",
2920 attr->elem, attr->name);
2921 }
2922 }
2923 }
2924
2925 /* Validity Constraint: Enumeration */
2926 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2927 xmlEnumerationPtr tree = attr->tree;
2928 while (tree != NULL) {
2929 if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2930 tree = tree->next;
2931 }
2932 if (tree == NULL) {
2933 VERROR(ctxt->userData,
2934"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2935 attr->defaultValue, attr->name, attr->elem);
2936 ret = 0;
2937 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002938 }
2939
2940 return(ret);
2941}
2942
2943/**
2944 * xmlValidateElementDecl:
2945 * @ctxt: the validation context
2946 * @doc: a document instance
2947 * @elem: an element definition
2948 *
2949 * Try to validate a single element definition
2950 * basically it does the following checks as described by the
2951 * XML-1.0 recommendation:
2952 * - [ VC: One ID per Element Type ]
2953 * - [ VC: No Duplicate Types ]
2954 * - [ VC: Unique Element Type Declaration ]
2955 *
2956 * returns 1 if valid or 0 otherwise
2957 */
2958
2959int
2960xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2961 xmlElementPtr elem) {
2962 int ret = 1;
2963 xmlElementPtr tst;
2964
2965 CHECK_DTD;
2966
2967 if (elem == NULL) return(1);
2968
2969 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00002970 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002971 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002972 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002973
2974 cur = elem->content;
2975 while (cur != NULL) {
2976 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2977 if (cur->c1 == NULL) break;
2978 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2979 name = cur->c1->name;
2980 next = cur->c2;
2981 while (next != NULL) {
2982 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2983 if (!xmlStrcmp(next->name, name)) {
2984 VERROR(ctxt->userData,
2985 "Definition of %s has duplicate references of %s\n",
2986 elem->name, name);
2987 ret = 0;
2988 }
2989 break;
2990 }
2991 if (next->c1 == NULL) break;
2992 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2993 if (!xmlStrcmp(next->c1->name, name)) {
2994 VERROR(ctxt->userData,
2995 "Definition of %s has duplicate references of %s\n",
2996 elem->name, name);
2997 ret = 0;
2998 }
2999 next = next->c2;
3000 }
3001 }
3002 cur = cur->c2;
3003 }
3004 }
3005
3006 /* VC: Unique Element Type Declaration */
3007 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3008 if ((tst != NULL ) && (tst != elem)) {
3009 VERROR(ctxt->userData, "Redefinition of element %s\n",
3010 elem->name);
3011 ret = 0;
3012 }
3013 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3014 if ((tst != NULL ) && (tst != elem)) {
3015 VERROR(ctxt->userData, "Redefinition of element %s\n",
3016 elem->name);
3017 ret = 0;
3018 }
3019
3020 /* One ID per Element Type */
3021 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3022 ret = 0;
3023 }
3024 return(ret);
3025}
3026
3027/**
3028 * xmlValidateOneAttribute:
3029 * @ctxt: the validation context
3030 * @doc: a document instance
3031 * @elem: an element instance
3032 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00003033 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003034 *
3035 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00003036 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00003037 * XML-1.0 recommendation:
3038 * - [ VC: Attribute Value Type ]
3039 * - [ VC: Fixed Attribute Default ]
3040 * - [ VC: Entity Name ]
3041 * - [ VC: Name Token ]
3042 * - [ VC: ID ]
3043 * - [ VC: IDREF ]
3044 * - [ VC: Entity Name ]
3045 * - [ VC: Notation Attributes ]
3046 *
3047 * The ID/IDREF uniqueness and matching are done separately
3048 *
3049 * returns 1 if valid or 0 otherwise
3050 */
3051
3052int
3053xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003054 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003055 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00003056 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003057 int val;
3058 int ret = 1;
3059
3060 CHECK_DTD;
3061 if ((elem == NULL) || (elem->name == NULL)) return(0);
3062 if ((attr == NULL) || (attr->name == NULL)) return(0);
3063
Daniel Veillardbe803962000-06-28 23:40:59 +00003064 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3065 xmlChar qname[500];
3066#ifdef HAVE_SNPRINTF
3067 snprintf((char *) qname, sizeof(qname), "%s:%s",
3068 elem->ns->prefix, elem->name);
3069#else
3070 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
3071#endif
3072 if (attr->ns != NULL) {
3073 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3074 attr->name, attr->ns->prefix);
3075 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3076 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3077 attr->name, attr->ns->prefix);
3078 } else {
3079 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3080 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3081 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3082 qname, attr->name);
3083 }
3084 }
3085 if (attrDecl == NULL) {
3086 if (attr->ns != NULL) {
3087 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3088 attr->name, attr->ns->prefix);
3089 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3090 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3091 attr->name, attr->ns->prefix);
3092 } else {
3093 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3094 elem->name, attr->name);
3095 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3096 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3097 elem->name, attr->name);
3098 }
3099 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003100
3101
3102 /* Validity Constraint: Attribute Value Type */
3103 if (attrDecl == NULL) {
3104 VERROR(ctxt->userData,
3105 "No declaration for attribute %s on element %s\n",
3106 attr->name, elem->name);
3107 return(0);
3108 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003109 attr->atype = attrDecl->atype;
3110
3111 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003112 if (val == 0) {
3113 VERROR(ctxt->userData,
3114 "Syntax of value for attribute %s on %s is not valid\n",
3115 attr->name, elem->name);
3116 ret = 0;
3117 }
3118
Daniel Veillardcf461992000-03-14 18:30:20 +00003119 /* Validity constraint: Fixed Attribute Default */
3120 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3121 if (xmlStrcmp(value, attrDecl->defaultValue)) {
3122 VERROR(ctxt->userData,
3123 "Value for attribute %s on %s is differnt from default \"%s\"\n",
3124 attr->name, elem->name, attrDecl->defaultValue);
3125 ret = 0;
3126 }
3127 }
3128
Daniel Veillardb96e6431999-08-29 21:02:19 +00003129 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00003130 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003131 xmlAddID(ctxt, doc, value, attr);
3132 }
3133
Daniel Veillardcf461992000-03-14 18:30:20 +00003134 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3135 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003136 xmlAddRef(ctxt, doc, value, attr);
3137 }
3138
Daniel Veillardb05deb71999-08-10 19:04:08 +00003139 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00003140 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003141 xmlEnumerationPtr tree = attrDecl->tree;
3142 xmlNotationPtr nota;
3143
3144 /* First check that the given NOTATION was declared */
3145 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3146 if (nota == NULL)
3147 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3148
3149 if (nota == NULL) {
3150 VERROR(ctxt->userData,
3151 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3152 value, attr->name, elem->name);
3153 ret = 0;
3154 }
3155
3156 /* Second, verify that it's among the list */
3157 while (tree != NULL) {
3158 if (!xmlStrcmp(tree->name, value)) break;
3159 tree = tree->next;
3160 }
3161 if (tree == NULL) {
3162 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003163"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003164 value, attr->name, elem->name);
3165 ret = 0;
3166 }
3167 }
3168
3169 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00003170 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003171 xmlEnumerationPtr tree = attrDecl->tree;
3172 while (tree != NULL) {
3173 if (!xmlStrcmp(tree->name, value)) break;
3174 tree = tree->next;
3175 }
3176 if (tree == NULL) {
3177 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003178 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003179 value, attr->name, elem->name);
3180 ret = 0;
3181 }
3182 }
3183
3184 /* Fixed Attribute Default */
3185 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3186 (xmlStrcmp(attrDecl->defaultValue, value))) {
3187 VERROR(ctxt->userData,
3188 "Value for attribute %s on %s must be \"%s\"\n",
3189 attr->name, elem->name, attrDecl->defaultValue);
3190 ret = 0;
3191 }
3192
Daniel Veillardcf461992000-03-14 18:30:20 +00003193 /* Extra check for the attribute value */
3194 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3195 attrDecl->atype, value);
3196
Daniel Veillardb05deb71999-08-10 19:04:08 +00003197 return(ret);
3198}
3199
3200int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3201 xmlElementContentPtr cont);
3202
3203/**
3204 * xmlValidateElementTypeExpr:
3205 * @ctxt: the validation context
3206 * @child: pointer to the child list
3207 * @cont: pointer to the content declaration
3208 *
3209 * Try to validate the content of an element of type element
3210 * but don't handle the occurence factor
3211 *
3212 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3213 * also update child value in-situ.
3214 */
3215
3216int
3217xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3218 xmlElementContentPtr cont) {
3219 xmlNodePtr cur;
3220 int ret = 1;
3221
3222 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003223 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003224 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003225 if ((*child)->type == XML_ENTITY_REF_NODE) {
3226 /*
3227 * If there is an entity declared an it's not empty
3228 * Push the current node on the stack and process with the
3229 * entity content.
3230 */
3231 if (((*child)->children != NULL) &&
3232 ((*child)->children->children != NULL)) {
3233 nodeVPush(ctxt, *child);
3234 *child = (*child)->children->children;
3235 } else
3236 *child = (*child)->next;
3237 continue;
3238 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003239 if ((*child)->type == XML_PI_NODE) {
3240 *child = (*child)->next;
3241 continue;
3242 }
3243 if ((*child)->type == XML_COMMENT_NODE) {
3244 *child = (*child)->next;
3245 continue;
3246 }
3247 else if ((*child)->type != XML_ELEMENT_NODE) {
3248 return(-1);
3249 }
3250 break;
3251 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003252 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003253 switch (cont->type) {
3254 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003255 if (*child == NULL) return(0);
3256 if ((*child)->type == XML_TEXT_NODE) return(1);
3257 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003258 case XML_ELEMENT_CONTENT_ELEMENT:
3259 if (*child == NULL) return(0);
3260 ret = (!xmlStrcmp((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003261 if (ret == 1) {
3262 while ((*child)->next == NULL) {
3263 if (((*child)->parent != NULL) &&
3264 ((*child)->parent->type == XML_ENTITY_DECL)) {
3265 *child = nodeVPop(ctxt);
3266 } else
3267 break;
3268 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003269 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003270 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003271 return(ret);
3272 case XML_ELEMENT_CONTENT_OR:
3273 cur = *child;
3274 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3275 if (ret == -1) return(-1);
3276 if (ret == 1) {
3277 return(1);
3278 }
3279 /* rollback and retry the other path */
3280 *child = cur;
3281 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3282 if (ret == -1) return(-1);
3283 if (ret == 0) {
3284 *child = cur;
3285 return(0);
3286 }
3287 return(1);
3288 case XML_ELEMENT_CONTENT_SEQ:
3289 cur = *child;
3290 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3291 if (ret == -1) return(-1);
3292 if (ret == 0) {
3293 *child = cur;
3294 return(0);
3295 }
3296 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3297 if (ret == -1) return(-1);
3298 if (ret == 0) {
3299 *child = cur;
3300 return(0);
3301 }
3302 return(1);
3303 }
3304 return(ret);
3305}
3306
3307/**
3308 * xmlValidateElementTypeElement:
3309 * @ctxt: the validation context
3310 * @child: pointer to the child list
3311 * @cont: pointer to the content declaration
3312 *
3313 * Try to validate the content of an element of type element
3314 * yeah, Yet Another Regexp Implementation, and recursive
3315 *
3316 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3317 * also update child and content values in-situ.
3318 */
3319
3320int
3321xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3322 xmlElementContentPtr cont) {
3323 xmlNodePtr cur;
3324 int ret = 1;
3325
3326 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003327
3328 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003329 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003330 if ((*child)->type == XML_ENTITY_REF_NODE) {
3331 /*
3332 * If there is an entity declared an it's not empty
3333 * Push the current node on the stack and process with the
3334 * entity content.
3335 */
3336 if (((*child)->children != NULL) &&
3337 ((*child)->children->children != NULL)) {
3338 nodeVPush(ctxt, *child);
3339 *child = (*child)->children->children;
3340 } else
3341 *child = (*child)->next;
3342 continue;
3343 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003344 if ((*child)->type == XML_PI_NODE) {
3345 *child = (*child)->next;
3346 continue;
3347 }
3348 if ((*child)->type == XML_COMMENT_NODE) {
3349 *child = (*child)->next;
3350 continue;
3351 }
3352 else if ((*child)->type != XML_ELEMENT_NODE) {
3353 return(-1);
3354 }
3355 break;
3356 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003357 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003358 cur = *child;
3359 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3360 if (ret == -1) return(-1);
3361 switch (cont->ocur) {
3362 case XML_ELEMENT_CONTENT_ONCE:
3363 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003364 /* skip ignorable elems */
3365 while ((*child != NULL) &&
3366 (((*child)->type == XML_PI_NODE) ||
3367 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003368 while ((*child)->next == NULL) {
3369 if (((*child)->parent != NULL) &&
3370 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3371 *child = (*child)->parent;
3372 } else
3373 break;
3374 }
3375 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003376 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003377 return(1);
3378 }
3379 *child = cur;
3380 return(0);
3381 case XML_ELEMENT_CONTENT_OPT:
3382 if (ret == 0) {
3383 *child = cur;
3384 return(1);
3385 }
3386 break;
3387 case XML_ELEMENT_CONTENT_MULT:
3388 if (ret == 0) {
3389 *child = cur;
3390 break;
3391 }
3392 /* no break on purpose */
3393 case XML_ELEMENT_CONTENT_PLUS:
3394 if (ret == 0) {
3395 *child = cur;
3396 return(0);
3397 }
3398 do {
3399 cur = *child;
3400 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3401 } while (ret == 1);
3402 if (ret == -1) return(-1);
3403 *child = cur;
3404 break;
3405 }
3406 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003407 if ((*child)->type == XML_ENTITY_REF_NODE) {
3408 /*
3409 * If there is an entity declared an it's not empty
3410 * Push the current node on the stack and process with the
3411 * entity content.
3412 */
3413 if (((*child)->children != NULL) &&
3414 ((*child)->children->children != NULL)) {
3415 nodeVPush(ctxt, *child);
3416 *child = (*child)->children->children;
3417 } else
3418 *child = (*child)->next;
3419 continue;
3420 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003421 if ((*child)->type == XML_PI_NODE) {
3422 *child = (*child)->next;
3423 continue;
3424 }
3425 if ((*child)->type == XML_COMMENT_NODE) {
3426 *child = (*child)->next;
3427 continue;
3428 }
3429 else if ((*child)->type != XML_ELEMENT_NODE) {
3430 return(-1);
3431 }
3432 break;
3433 }
3434 return(1);
3435}
3436
3437/**
3438 * xmlSprintfElementChilds:
3439 * @buf: an output buffer
3440 * @content: An element
3441 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3442 *
3443 * This will dump the list of childs to the buffer
3444 * Intended just for the debug routine
3445 */
3446void
3447xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3448 xmlNodePtr cur;
3449
3450 if (node == NULL) return;
3451 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003452 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003453 while (cur != NULL) {
3454 switch (cur->type) {
3455 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003456 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003457 if (cur->next != NULL)
3458 strcat(buf, " ");
3459 break;
3460 case XML_TEXT_NODE:
3461 case XML_CDATA_SECTION_NODE:
3462 case XML_ENTITY_REF_NODE:
3463 strcat(buf, "CDATA");
3464 if (cur->next != NULL)
3465 strcat(buf, " ");
3466 break;
3467 case XML_ATTRIBUTE_NODE:
3468 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003469 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003470 case XML_DOCUMENT_TYPE_NODE:
3471 case XML_DOCUMENT_FRAG_NODE:
3472 case XML_NOTATION_NODE:
3473 strcat(buf, "???");
3474 if (cur->next != NULL)
3475 strcat(buf, " ");
3476 break;
3477 case XML_ENTITY_NODE:
3478 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003479 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003480 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003481 case XML_ELEMENT_DECL:
3482 case XML_ATTRIBUTE_DECL:
3483 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003484 break;
3485 }
3486 cur = cur->next;
3487 }
3488 if (glob) strcat(buf, ")");
3489}
3490
3491
3492/**
3493 * xmlValidateOneElement:
3494 * @ctxt: the validation context
3495 * @doc: a document instance
3496 * @elem: an element instance
3497 *
3498 * Try to validate a single element and it's attributes,
3499 * basically it does the following checks as described by the
3500 * XML-1.0 recommendation:
3501 * - [ VC: Element Valid ]
3502 * - [ VC: Required Attribute ]
3503 * Then call xmlValidateOneAttribute() for each attribute present.
3504 *
3505 * The ID/IDREF checkings are done separately
3506 *
3507 * returns 1 if valid or 0 otherwise
3508 */
3509
3510int
3511xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3512 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003513 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003514 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003515 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003516 xmlNodePtr child;
3517 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003518 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003519
3520 CHECK_DTD;
3521
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003522 if (elem == NULL) return(0);
3523 if (elem->type == XML_TEXT_NODE) {
3524 }
3525 switch (elem->type) {
3526 case XML_ATTRIBUTE_NODE:
3527 VERROR(ctxt->userData,
3528 "Attribute element not expected here\n");
3529 return(0);
3530 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003531 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003532 VERROR(ctxt->userData, "Text element has childs !\n");
3533 return(0);
3534 }
3535 if (elem->properties != NULL) {
3536 VERROR(ctxt->userData, "Text element has attributes !\n");
3537 return(0);
3538 }
3539 if (elem->ns != NULL) {
3540 VERROR(ctxt->userData, "Text element has namespace !\n");
3541 return(0);
3542 }
3543 if (elem->ns != NULL) {
3544 VERROR(ctxt->userData,
3545 "Text element carries namespace definitions !\n");
3546 return(0);
3547 }
3548 if (elem->content == NULL) {
3549 VERROR(ctxt->userData,
3550 "Text element has no content !\n");
3551 return(0);
3552 }
3553 return(1);
3554 case XML_CDATA_SECTION_NODE:
3555 case XML_ENTITY_REF_NODE:
3556 case XML_PI_NODE:
3557 case XML_COMMENT_NODE:
3558 return(1);
3559 case XML_ENTITY_NODE:
3560 VERROR(ctxt->userData,
3561 "Entity element not expected here\n");
3562 return(0);
3563 case XML_NOTATION_NODE:
3564 VERROR(ctxt->userData,
3565 "Notation element not expected here\n");
3566 return(0);
3567 case XML_DOCUMENT_NODE:
3568 case XML_DOCUMENT_TYPE_NODE:
3569 case XML_DOCUMENT_FRAG_NODE:
3570 VERROR(ctxt->userData,
3571 "Document element not expected here\n");
3572 return(0);
3573 case XML_HTML_DOCUMENT_NODE:
3574 VERROR(ctxt->userData,
3575 "\n");
3576 return(0);
3577 case XML_ELEMENT_NODE:
3578 break;
3579 default:
3580 VERROR(ctxt->userData,
3581 "unknown element type %d\n", elem->type);
3582 return(0);
3583 }
3584 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003585
Daniel Veillardbe803962000-06-28 23:40:59 +00003586 /*
3587 * Fetch the declaration for the qualified name
3588 */
3589 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3590 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3591 elem->name, elem->ns->prefix);
3592 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3593 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3594 elem->name, elem->ns->prefix);
3595 }
3596
3597 /*
3598 * Fetch the declaration for the non qualified name
3599 */
3600 if (elemDecl == NULL) {
3601 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3602 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3603 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3604 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003605 if (elemDecl == NULL) {
3606 VERROR(ctxt->userData, "No declaration for element %s\n",
3607 elem->name);
3608 return(0);
3609 }
3610
3611 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003612 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003613 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003614 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003615 VERROR(ctxt->userData,
3616 "Element %s was declared EMPTY this one has content\n",
3617 elem->name);
3618 ret = 0;
3619 }
3620 break;
3621 case XML_ELEMENT_TYPE_ANY:
3622 /* I don't think anything is required then */
3623 break;
3624 case XML_ELEMENT_TYPE_MIXED:
3625 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003626 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003627 while (child != NULL) {
3628 if (child->type == XML_ELEMENT_NODE) {
3629 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003630 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3631 xmlChar qname[500];
3632#ifdef HAVE_SNPRINTF
3633 snprintf((char *) qname, sizeof(qname), "%s:%s",
3634 child->ns->prefix, child->name);
3635#else
3636 sprintf(qname, "%s:%s", child->name, child->ns->prefix);
3637#endif
3638 cont = elemDecl->content;
3639 while (cont != NULL) {
3640 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3641 if (!xmlStrcmp(cont->name, qname)) break;
3642 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3643 (cont->c1 != NULL) &&
3644 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
3645 if (!xmlStrcmp(cont->c1->name, qname)) break;
3646 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3647 (cont->c1 == NULL) ||
3648 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3649 /* Internal error !!! */
3650 fprintf(stderr, "Internal: MIXED struct bad\n");
3651 break;
3652 }
3653 cont = cont->c2;
3654 }
3655 if (cont != NULL)
3656 goto child_ok;
3657 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003658 cont = elemDecl->content;
3659 while (cont != NULL) {
3660 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3661 if (!xmlStrcmp(cont->name, name)) break;
3662 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3663 (cont->c1 != NULL) &&
3664 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3665 if (!xmlStrcmp(cont->c1->name, name)) break;
3666 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3667 (cont->c1 == NULL) ||
3668 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3669 /* Internal error !!! */
3670 fprintf(stderr, "Internal: MIXED struct bad\n");
3671 break;
3672 }
3673 cont = cont->c2;
3674 }
3675 if (cont == NULL) {
3676 VERROR(ctxt->userData,
3677 "Element %s is not declared in %s list of possible childs\n",
3678 name, elem->name);
3679 ret = 0;
3680 }
3681 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003682child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003683 child = child->next;
3684 }
3685 break;
3686 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003687 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003688 cont = elemDecl->content;
3689 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3690 if ((ret == 0) || (child != NULL)) {
3691 char expr[1000];
3692 char list[2000];
3693
3694 expr[0] = 0;
3695 xmlSprintfElementContent(expr, cont, 1);
3696 list[0] = 0;
3697 xmlSprintfElementChilds(list, elem, 1);
3698
3699 VERROR(ctxt->userData,
3700 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3701 elem->name, expr, list);
3702 ret = 0;
3703 }
3704 break;
3705 }
3706
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003707 /* [ VC: Required Attribute ] */
3708 attr = elemDecl->attributes;
3709 while (attr != NULL) {
3710 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3711 xmlAttrPtr attrib;
3712 int qualified = -1;
3713
3714 attrib = elem->properties;
3715 while (attrib != NULL) {
3716 if (!xmlStrcmp(attrib->name, attr->name)) {
3717 if (attr->prefix != NULL) {
3718 xmlNsPtr nameSpace = attrib->ns;
3719
3720 if (nameSpace == NULL)
3721 nameSpace = elem->ns;
3722 /*
3723 * qualified names handling is problematic, having a
3724 * different prefix should be possible but DTDs don't
3725 * allow to define the URI instead of the prefix :-(
3726 */
3727 if (nameSpace == NULL) {
3728 if (qualified < 0)
3729 qualified = 0;
3730 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3731 if (qualified < 1)
3732 qualified = 1;
3733 } else
3734 goto found;
3735 } else {
3736 /*
3737 * We should allow applications to define namespaces
3738 * for their application even if the DTD doesn't
3739 * carry one, otherwise, basically we would always
3740 * break.
3741 */
3742 goto found;
3743 }
3744 }
3745 attrib = attrib->next;
3746 }
3747 if (qualified == -1) {
3748 if (attr->prefix == NULL) {
3749 VERROR(ctxt->userData,
3750 "Element %s doesn't carry attribute %s\n",
3751 elem->name, attr->name);
3752 } else {
3753 VERROR(ctxt->userData,
3754 "Element %s doesn't carry attribute %s:%s\n",
3755 elem->name, attr->prefix,attr->name);
3756 }
3757 } else if (qualified == 0) {
3758 VWARNING(ctxt->userData,
3759 "Element %s required attribute %s:%s has no prefix\n",
3760 elem->name, attr->prefix,attr->name);
3761 } else if (qualified == 1) {
3762 VWARNING(ctxt->userData,
3763 "Element %s required attribute %s:%s has different prefix\n",
3764 elem->name, attr->prefix,attr->name);
3765 }
3766 }
3767found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003768 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003769 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003770 return(ret);
3771}
3772
3773/**
3774 * xmlValidateRoot:
3775 * @ctxt: the validation context
3776 * @doc: a document instance
3777 *
3778 * Try to validate a the root element
3779 * basically it does the following check as described by the
3780 * XML-1.0 recommendation:
3781 * - [ VC: Root Element Type ]
3782 * it doesn't try to recurse or apply other check to the element
3783 *
3784 * returns 1 if valid or 0 otherwise
3785 */
3786
3787int
3788xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003789 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003790 if (doc == NULL) return(0);
3791
3792 if ((doc->intSubset == NULL) ||
3793 (doc->intSubset->name == NULL)) {
3794 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3795 return(0);
3796 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003797 root = xmlDocGetRootElement(doc);
3798 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003799 VERROR(ctxt->userData, "Not valid: no root element\n");
3800 return(0);
3801 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003802
3803 /*
3804 * Check first the document root against the NQName
3805 */
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003806 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003807 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3808 xmlChar qname[500];
3809#ifdef HAVE_SNPRINTF
3810 snprintf((char *) qname, sizeof(qname), "%s:%s",
3811 root->ns->prefix, root->name);
3812#else
3813 sprintf(qname, "%s:%s", root->name, root->ns->prefix);
3814#endif
3815 if (!xmlStrcmp(doc->intSubset->name, qname))
3816 goto name_ok;
3817 }
3818 if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
3819 (!xmlStrcmp(root->name, BAD_CAST "html")))
3820 goto name_ok;
3821 VERROR(ctxt->userData,
3822 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3823 root->name, doc->intSubset->name);
3824 return(0);
3825
Daniel Veillardb05deb71999-08-10 19:04:08 +00003826 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003827name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003828 return(1);
3829}
3830
3831
3832/**
3833 * xmlValidateElement:
3834 * @ctxt: the validation context
3835 * @doc: a document instance
3836 * @elem: an element instance
3837 *
3838 * Try to validate the subtree under an element
3839 *
3840 * returns 1 if valid or 0 otherwise
3841 */
3842
3843int
3844xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003845 xmlNodePtr child;
3846 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003847 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003848 int ret = 1;
3849
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003850 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003851 CHECK_DTD;
3852
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003853 ret &= xmlValidateOneElement(ctxt, doc, elem);
3854 attr = elem->properties;
3855 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003856 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003857 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3858 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003859 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003860 attr= attr->next;
3861 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003862 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003863 while (child != NULL) {
3864 ret &= xmlValidateElement(ctxt, doc, child);
3865 child = child->next;
3866 }
3867
3868 return(ret);
3869}
3870
3871/**
3872 * xmlValidateDocumentFinal:
3873 * @ctxt: the validation context
3874 * @doc: a document instance
3875 *
3876 * Does the final step for the document validation once all the
3877 * incremental validation steps have been completed
3878 *
3879 * basically it does the following checks described by the XML Rec
3880 *
3881 *
3882 * returns 1 if valid or 0 otherwise
3883 */
3884
3885int
3886xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3887 int ret = 1, i;
3888 xmlRefTablePtr table;
3889 xmlAttrPtr id;
3890
3891 if (doc == NULL) {
3892 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3893 return(0);
3894 }
3895
3896 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003897 * Check all the NOTATION/NOTATIONS attributes
3898 */
3899 /*
3900 * Check all the ENTITY/ENTITIES attributes definition for validity
3901 */
3902 /*
3903 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003904 */
3905 table = doc->refs;
3906 if (table != NULL) {
3907 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003908 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3909 id = xmlGetID(doc, table->table[i]->value);
3910 if (id == NULL) {
3911 VERROR(ctxt->userData,
3912 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3913 table->table[i]->attr->name, table->table[i]->value);
3914 ret = 0;
3915 }
3916 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
3917 xmlChar *dup, *name = NULL, *cur, save;
3918
3919 dup = xmlStrdup(table->table[i]->value);
3920 if (dup == NULL)
3921 return(0);
3922 cur = dup;
3923 while (*cur != 0) {
3924 name = cur;
3925 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3926 save = *cur;
3927 *cur = 0;
3928 id = xmlGetID(doc, name);
3929 if (id == NULL) {
3930 VERROR(ctxt->userData,
3931 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3932 table->table[i]->attr->name, name);
3933 ret = 0;
3934 }
3935 if (save == 0)
3936 break;
3937 *cur = save;
3938 while (IS_BLANK(*cur)) cur++;
3939 }
3940 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003941 }
3942 }
3943 }
3944 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003945}
3946
3947/**
3948 * xmlValidateDtd:
3949 * @ctxt: the validation context
3950 * @doc: a document instance
3951 * @dtd: a dtd instance
3952 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003953 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003954 *
3955 * basically it does check all the definitions in the DtD.
3956 *
3957 * returns 1 if valid or 0 otherwise
3958 */
3959
3960int
3961xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003962 int ret;
3963 xmlDtdPtr oldExt;
3964 xmlNodePtr root;
3965
3966 if (dtd == NULL) return(0);
3967 if (doc == NULL) return(0);
3968 oldExt = doc->extSubset;
3969 doc->extSubset = dtd;
3970 ret = xmlValidateRoot(ctxt, doc);
3971 if (ret == 0) {
3972 doc->extSubset = oldExt;
3973 return(ret);
3974 }
3975 root = xmlDocGetRootElement(doc);
3976 ret = xmlValidateElement(ctxt, doc, root);
3977 ret &= xmlValidateDocumentFinal(ctxt, doc);
3978 doc->extSubset = oldExt;
3979 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003980}
3981
3982/**
Daniel Veillardcf461992000-03-14 18:30:20 +00003983 * xmlValidateDtdFinal:
3984 * @ctxt: the validation context
3985 * @doc: a document instance
3986 *
3987 * Does the final step for the dtds validation once all the
3988 * subsets have been parsed
3989 *
3990 * basically it does the following checks described by the XML Rec
3991 * - check that ENTITY and ENTITIES type attributes default or
3992 * possible values matches one of the defined entities.
3993 * - check that NOTATION type attributes default or
3994 * possible values matches one of the defined notations.
3995 *
3996 * returns 1 if valid or 0 otherwise
3997 */
3998
3999int
4000xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4001 int ret = 1, i;
4002 xmlDtdPtr dtd;
4003 xmlAttributeTablePtr table;
4004 xmlAttributePtr cur;
4005
4006 if (doc == NULL) return(0);
4007 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4008 return(0);
4009 dtd = doc->intSubset;
4010 if ((dtd != NULL) && (dtd->attributes != NULL)) {
4011 table = dtd->attributes;
4012
4013 for (i = 0;i < table->nb_attributes;i++) {
4014 cur = table->table[i];
4015 switch (cur->atype) {
4016 case XML_ATTRIBUTE_CDATA:
4017 case XML_ATTRIBUTE_ID:
4018 case XML_ATTRIBUTE_IDREF :
4019 case XML_ATTRIBUTE_IDREFS:
4020 case XML_ATTRIBUTE_NMTOKEN:
4021 case XML_ATTRIBUTE_NMTOKENS:
4022 case XML_ATTRIBUTE_ENUMERATION:
4023 break;
4024 case XML_ATTRIBUTE_ENTITY:
4025 case XML_ATTRIBUTE_ENTITIES:
4026 case XML_ATTRIBUTE_NOTATION:
4027 if (cur->defaultValue != NULL) {
4028 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4029 cur->atype, cur->defaultValue);
4030 }
4031 if (cur->tree != NULL) {
4032 xmlEnumerationPtr tree = cur->tree;
4033 while (tree != NULL) {
4034 ret &= xmlValidateAttributeValue2(ctxt, doc,
4035 cur->name, cur->atype, tree->name);
4036 tree = tree->next;
4037 }
4038 }
4039 }
4040 }
4041 }
4042 dtd = doc->extSubset;
4043 if ((dtd != NULL) && (dtd->attributes != NULL)) {
4044 table = dtd->attributes;
4045
4046 for (i = 0;i < table->nb_attributes;i++) {
4047 cur = table->table[i];
4048 switch (cur->atype) {
4049 case XML_ATTRIBUTE_CDATA:
4050 case XML_ATTRIBUTE_ID:
4051 case XML_ATTRIBUTE_IDREF :
4052 case XML_ATTRIBUTE_IDREFS:
4053 case XML_ATTRIBUTE_NMTOKEN:
4054 case XML_ATTRIBUTE_NMTOKENS:
4055 case XML_ATTRIBUTE_ENUMERATION:
4056 break;
4057 case XML_ATTRIBUTE_ENTITY:
4058 case XML_ATTRIBUTE_ENTITIES:
4059 case XML_ATTRIBUTE_NOTATION:
4060 if (cur->defaultValue != NULL) {
4061 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4062 cur->atype, cur->defaultValue);
4063 }
4064 if (cur->tree != NULL) {
4065 xmlEnumerationPtr tree = cur->tree;
4066 while (tree != NULL) {
4067 ret &= xmlValidateAttributeValue2(ctxt, doc,
4068 cur->name, cur->atype, tree->name);
4069 tree = tree->next;
4070 }
4071 }
4072 }
4073 }
4074 }
4075 return(ret);
4076}
4077
4078/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00004079 * xmlValidateDocument:
4080 * @ctxt: the validation context
4081 * @doc: a document instance
4082 *
4083 * Try to validate the document instance
4084 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004085 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00004086 * i.e. validates the internal and external subset (if present)
4087 * and validate the document tree.
4088 *
4089 * returns 1 if valid or 0 otherwise
4090 */
4091
4092int
4093xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004094 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004095 xmlNodePtr root;
4096
4097 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4098 return(0);
4099 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4100 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4101 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4102 doc->intSubset->SystemID);
4103 if (doc->extSubset == NULL) {
4104 if (doc->intSubset->SystemID != NULL) {
4105 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004106 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004107 doc->intSubset->SystemID);
4108 } else {
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->ExternalID);
4112 }
4113 return(0);
4114 }
4115 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004116
Daniel Veillardcf461992000-03-14 18:30:20 +00004117 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004118 if (!xmlValidateRoot(ctxt, doc)) return(0);
4119
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004120 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00004121 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004122 ret &= xmlValidateDocumentFinal(ctxt, doc);
4123 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004124}
4125
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004126
4127/************************************************************************
4128 * *
4129 * Routines for dynamic validation editing *
4130 * *
4131 ************************************************************************/
4132
4133/**
4134 * xmlValidGetPotentialChildren:
4135 * @ctree: an element content tree
4136 * @list: an array to store the list of child names
4137 * @len: a pointer to the number of element in the list
4138 * @max: the size of the array
4139 *
4140 * Build/extend a list of potential children allowed by the content tree
4141 *
4142 * returns the number of element in the list, or -1 in case of error.
4143 */
4144
4145int
4146xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4147 int *len, int max) {
4148 int i;
4149
4150 if ((ctree == NULL) || (list == NULL) || (len == NULL))
4151 return(-1);
4152 if (*len >= max) return(*len);
4153
4154 switch (ctree->type) {
4155 case XML_ELEMENT_CONTENT_PCDATA:
4156 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00004157 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
4158 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004159 break;
4160 case XML_ELEMENT_CONTENT_ELEMENT:
4161 for (i = 0; i < *len;i++)
4162 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
4163 list[(*len)++] = ctree->name;
4164 break;
4165 case XML_ELEMENT_CONTENT_SEQ:
4166 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4167 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4168 break;
4169 case XML_ELEMENT_CONTENT_OR:
4170 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4171 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4172 break;
4173 }
4174
4175 return(*len);
4176}
4177
4178/**
4179 * xmlValidGetValidElements:
4180 * @prev: an element to insert after
4181 * @next: an element to insert next
4182 * @list: an array to store the list of child names
4183 * @max: the size of the array
4184 *
4185 * This function returns the list of authorized children to insert
4186 * within an existing tree while respecting the validity constraints
4187 * forced by the Dtd. The insertion point is defined using @prev and
4188 * @next in the following ways:
4189 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4190 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4191 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4192 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4193 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4194 *
4195 * pointers to the element names are inserted at the beginning of the array
4196 * and do not need to be freed.
4197 *
4198 * returns the number of element in the list, or -1 in case of error. If
4199 * the function returns the value @max the caller is invited to grow the
4200 * receiving array and retry.
4201 */
4202
4203int
4204xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4205 int max) {
4206 int nb_valid_elements = 0;
4207 const xmlChar *elements[256];
4208 int nb_elements = 0, i;
4209
4210 xmlNode *ref_node;
4211 xmlNode *parent;
4212 xmlNode *test_node;
4213
4214 xmlNode *prev_next;
4215 xmlNode *next_prev;
4216 xmlNode *parent_childs;
4217 xmlNode *parent_last;
4218
4219 xmlElement *element_desc;
4220
4221 if (prev == NULL && next == NULL)
4222 return(-1);
4223
4224 if (list == NULL) return(-1);
4225 if (max <= 0) return(-1);
4226
4227 nb_valid_elements = 0;
4228 ref_node = prev ? prev : next;
4229 parent = ref_node->parent;
4230
4231 /*
4232 * Retrieves the parent element declaration
4233 */
4234 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4235 parent->name);
4236 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4237 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4238 parent->name);
4239 if (element_desc == NULL) return(-1);
4240
4241 /*
4242 * Do a backup of the current tree structure
4243 */
4244 prev_next = prev ? prev->next : NULL;
4245 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004246 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004247 parent_last = parent->last;
4248
4249 /*
4250 * Creates a dummy node and insert it into the tree
4251 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004252 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004253 test_node->doc = ref_node->doc;
4254 test_node->parent = parent;
4255 test_node->prev = prev;
4256 test_node->next = next;
4257
4258 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00004259 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004260
4261 if (next) next->prev = test_node;
4262 else parent->last = test_node;
4263
4264 /*
4265 * Insert each potential child node and check if the parent is
4266 * still valid
4267 */
4268 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4269 elements, &nb_elements, 256);
4270
4271 for (i = 0;i < nb_elements;i++) {
4272 test_node->name = elements[i];
4273 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4274 int j;
4275
4276 for (j = 0; j < nb_valid_elements;j++)
4277 if (!xmlStrcmp(elements[i], list[j])) break;
4278 list[nb_valid_elements++] = elements[i];
4279 if (nb_valid_elements >= max) break;
4280 }
4281 }
4282
4283 /*
4284 * Restore the tree structure
4285 */
4286 if (prev) prev->next = prev_next;
4287 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004288 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004289 parent->last = parent_last;
4290
4291 return(nb_valid_elements);
4292}