blob: 5dc37edf90a5bb74a841e3a6e755e693339d8d4a [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 *******************/
2034 } else {
2035 xmlAttributePtr attrDecl;
2036
2037 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2038 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2039 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2040 attr->name);
2041
Daniel Veillardcf461992000-03-14 18:30:20 +00002042 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002043 return(1);
2044 }
2045 return(0);
2046}
2047
2048/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00002049 * xmlRemoveRef
2050 * @doc: the document
2051 * @attr: the attribute
2052 *
2053 * Remove the given attribute from the Ref table maintained internally.
2054 *
2055 * Returns -1 if the lookup failed and 0 otherwise
2056 */
2057int
2058xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2059 xmlRefPtr cur;
2060 xmlRefTablePtr table;
2061 int i;
2062
2063 if (doc == NULL) return(-1);
2064 if (attr == NULL) return(-1);
2065 table = doc->refs;
2066 if (table == NULL)
2067 return(-1);
2068
2069 /*
2070 * Search the Ref list.
2071 */
2072 for (i = 0;i < table->nb_refs;i++) {
2073 cur = table->table[i];
2074 if (cur->attr == attr) {
2075 table->nb_refs--;
2076 memmove(&table->table[i], &table->table[i+1],
2077 (table->nb_refs - i) * sizeof(xmlRefPtr));
2078 return(0);
2079 }
2080 }
2081 return(-1);
2082}
2083
2084/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002085 * xmlGetRef:
2086 * @doc: pointer to the document
2087 * @Ref: the Ref value
2088 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00002089 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002090 *
2091 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
2092 */
2093xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002094xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002095 xmlRefPtr cur;
2096 xmlRefTablePtr table;
2097 int i;
2098
2099 if (doc == NULL) {
2100 fprintf(stderr, "xmlGetRef: doc == NULL\n");
2101 return(NULL);
2102 }
2103
2104 if (Ref == NULL) {
2105 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
2106 return(NULL);
2107 }
2108
2109 table = doc->refs;
2110 if (table == NULL)
2111 return(NULL);
2112
2113 /*
2114 * Search the Ref list.
2115 */
2116 for (i = 0;i < table->nb_refs;i++) {
2117 cur = table->table[i];
2118 if (!xmlStrcmp(cur->value, Ref)) {
2119 return(cur->attr);
2120 }
2121 }
2122 return(NULL);
2123}
2124
2125/************************************************************************
2126 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00002127 * Routines for validity checking *
2128 * *
2129 ************************************************************************/
2130
2131/**
2132 * xmlGetDtdElementDesc:
2133 * @dtd: a pointer to the DtD to search
2134 * @name: the element name
2135 *
2136 * Search the Dtd for the description of this element
2137 *
2138 * returns the xmlElementPtr if found or NULL
2139 */
2140
2141xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002142xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002143 xmlElementTablePtr table;
2144 xmlElementPtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002145 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002146 int i;
2147
2148 if (dtd == NULL) return(NULL);
2149 if (dtd->elements == NULL) return(NULL);
2150 table = dtd->elements;
2151
2152 for (i = 0;i < table->nb_elements;i++) {
2153 cur = table->table[i];
2154 if (!xmlStrcmp(cur->name, name))
2155 return(cur);
2156 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002157
2158 /*
2159 * Specific case if name is a QName.
2160 */
2161 uqname = xmlSplitQName2(name, &prefix);
2162 if (uqname == NULL) return(NULL);
2163
2164 for (i = 0;i < table->nb_elements;i++) {
2165 cur = table->table[i];
2166 if ((!xmlStrcmp(cur->name, uqname)) &&
2167 ((prefix == cur->prefix) ||
2168 ((prefix != NULL) && (cur->prefix != NULL) &&
2169 (!xmlStrcmp(cur->prefix, prefix))))) {
2170 if (prefix != NULL) xmlFree(prefix);
2171 if (uqname != NULL) xmlFree(uqname);
2172 return(cur);
2173 }
2174 }
2175 if (prefix != NULL) xmlFree(prefix);
2176 if (uqname != NULL) xmlFree(uqname);
2177 return(NULL);
2178}
2179
2180/**
2181 * xmlGetDtdQElementDesc:
2182 * @dtd: a pointer to the DtD to search
2183 * @name: the element name
2184 * @prefix: the element namespace prefix
2185 *
2186 * Search the Dtd for the description of this element
2187 *
2188 * returns the xmlElementPtr if found or NULL
2189 */
2190
2191xmlElementPtr
2192xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2193 const xmlChar *prefix) {
2194 xmlElementTablePtr table;
2195 xmlElementPtr cur;
2196 int i;
2197
2198 if (dtd == NULL) return(NULL);
2199 if (dtd->elements == NULL) return(NULL);
2200 table = dtd->elements;
2201
2202 for (i = 0;i < table->nb_elements;i++) {
2203 cur = table->table[i];
2204 if (!xmlStrcmp(cur->name, name) &&
2205 ((prefix == cur->prefix) ||
2206 ((prefix != NULL) && (cur->prefix != NULL) &&
2207 (!xmlStrcmp(cur->prefix, prefix)))))
2208 return(cur);
2209 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002210 return(NULL);
2211}
2212
2213/**
2214 * xmlGetDtdAttrDesc:
2215 * @dtd: a pointer to the DtD to search
2216 * @elem: the element name
2217 * @name: the attribute name
2218 *
2219 * Search the Dtd for the description of this attribute on
2220 * this element.
2221 *
2222 * returns the xmlAttributePtr if found or NULL
2223 */
2224
2225xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002226xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002227 xmlAttributeTablePtr table;
2228 xmlAttributePtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00002229 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002230 int i;
2231
2232 if (dtd == NULL) return(NULL);
2233 if (dtd->attributes == NULL) return(NULL);
2234 table = dtd->attributes;
2235
2236 for (i = 0;i < table->nb_attributes;i++) {
2237 cur = table->table[i];
2238 if ((!xmlStrcmp(cur->name, name)) &&
2239 (!xmlStrcmp(cur->elem, elem)))
2240 return(cur);
2241 }
Daniel Veillardbe803962000-06-28 23:40:59 +00002242
2243 /*
2244 * Specific case if name is a QName.
2245 */
2246 uqname = xmlSplitQName2(name, &prefix);
2247 if (uqname == NULL) return(NULL);
2248
2249 for (i = 0;i < table->nb_attributes;i++) {
2250 cur = table->table[i];
2251 if ((!xmlStrcmp(cur->name, uqname)) &&
2252 (!xmlStrcmp(cur->elem, elem)) &&
2253 ((prefix == cur->prefix) ||
2254 ((prefix != NULL) && (cur->prefix != NULL) &&
2255 (!xmlStrcmp(cur->prefix, prefix))))) {
2256 if (prefix != NULL) xmlFree(prefix);
2257 if (uqname != NULL) xmlFree(uqname);
2258 return(cur);
2259 }
2260 }
2261 if (prefix != NULL) xmlFree(prefix);
2262 if (uqname != NULL) xmlFree(uqname);
2263 return(NULL);
2264}
2265
2266/**
2267 * xmlGetDtdQAttrDesc:
2268 * @dtd: a pointer to the DtD to search
2269 * @elem: the element name
2270 * @name: the attribute name
2271 * @prefix: the attribute namespace prefix
2272 *
2273 * Search the Dtd for the description of this qualified attribute on
2274 * this element.
2275 *
2276 * returns the xmlAttributePtr if found or NULL
2277 */
2278
2279xmlAttributePtr
2280xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2281 const xmlChar *prefix) {
2282 xmlAttributeTablePtr table;
2283 xmlAttributePtr cur;
2284 int i;
2285
2286 if (dtd == NULL) return(NULL);
2287 if (dtd->attributes == NULL) return(NULL);
2288 table = dtd->attributes;
2289
2290 for (i = 0;i < table->nb_attributes;i++) {
2291 cur = table->table[i];
2292 if ((!xmlStrcmp(cur->name, name)) &&
2293 (!xmlStrcmp(cur->elem, elem)) &&
2294 ((prefix == cur->prefix) ||
2295 ((prefix != NULL) && (cur->prefix != NULL) &&
2296 (!xmlStrcmp(cur->prefix, prefix)))))
2297 return(cur);
2298 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002299 return(NULL);
2300}
2301
2302/**
2303 * xmlGetDtdNotationDesc:
2304 * @dtd: a pointer to the DtD to search
2305 * @name: the notation name
2306 *
2307 * Search the Dtd for the description of this notation
2308 *
2309 * returns the xmlNotationPtr if found or NULL
2310 */
2311
2312xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002313xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002314 xmlNotationTablePtr table;
2315 xmlNotationPtr cur;
2316 int i;
2317
2318 if (dtd == NULL) return(NULL);
2319 if (dtd->notations == NULL) return(NULL);
2320 table = dtd->notations;
2321
2322 for (i = 0;i < table->nb_notations;i++) {
2323 cur = table->table[i];
2324 if (!xmlStrcmp(cur->name, name))
2325 return(cur);
2326 }
2327 return(NULL);
2328}
2329
2330/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002331 * xmlValidateNotationUse:
2332 * @ctxt: the validation context
2333 * @doc: the document
2334 * @notationName: the notation name to check
2335 *
2336 * Validate that the given mame match a notation declaration.
2337 * - [ VC: Notation Declared ]
2338 *
2339 * returns 1 if valid or 0 otherwise
2340 */
2341
2342int
2343xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002344 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002345 xmlNotationPtr notaDecl;
2346 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2347
2348 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2349 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2350 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2351
2352 if (notaDecl == NULL) {
2353 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2354 notationName);
2355 return(0);
2356 }
2357 return(1);
2358}
2359
2360/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002361 * xmlIsMixedElement
2362 * @doc: the document
2363 * @name: the element name
2364 *
2365 * Search in the DtDs whether an element accept Mixed content (or ANY)
2366 * basically if it is supposed to accept text childs
2367 *
2368 * returns 0 if no, 1 if yes, and -1 if no element description is available
2369 */
2370
2371int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002372xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002373 xmlElementPtr elemDecl;
2374
2375 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2376
2377 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2378 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2379 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2380 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002381 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002382 case XML_ELEMENT_TYPE_ELEMENT:
2383 return(0);
2384 case XML_ELEMENT_TYPE_EMPTY:
2385 /*
2386 * return 1 for EMPTY since we want VC error to pop up
2387 * on <empty> </empty> for example
2388 */
2389 case XML_ELEMENT_TYPE_ANY:
2390 case XML_ELEMENT_TYPE_MIXED:
2391 return(1);
2392 }
2393 return(1);
2394}
2395
2396/**
2397 * xmlValidateNameValue:
2398 * @value: an Name value
2399 *
2400 * Validate that the given value match Name production
2401 *
2402 * returns 1 if valid or 0 otherwise
2403 */
2404
2405int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002406xmlValidateNameValue(const xmlChar *value) {
2407 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002408
2409 if (value == NULL) return(0);
2410 cur = value;
2411
2412 if (!IS_LETTER(*cur) && (*cur != '_') &&
2413 (*cur != ':')) {
2414 return(0);
2415 }
2416
2417 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2418 (*cur == '.') || (*cur == '-') ||
2419 (*cur == '_') || (*cur == ':') ||
2420 (IS_COMBINING(*cur)) ||
2421 (IS_EXTENDER(*cur)))
2422 cur++;
2423
2424 if (*cur != 0) return(0);
2425
2426 return(1);
2427}
2428
2429/**
2430 * xmlValidateNamesValue:
2431 * @value: an Names value
2432 *
2433 * Validate that the given value match Names production
2434 *
2435 * returns 1 if valid or 0 otherwise
2436 */
2437
2438int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002439xmlValidateNamesValue(const xmlChar *value) {
2440 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002441
2442 if (value == NULL) return(0);
2443 cur = value;
2444
2445 if (!IS_LETTER(*cur) && (*cur != '_') &&
2446 (*cur != ':')) {
2447 return(0);
2448 }
2449
2450 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2451 (*cur == '.') || (*cur == '-') ||
2452 (*cur == '_') || (*cur == ':') ||
2453 (IS_COMBINING(*cur)) ||
2454 (IS_EXTENDER(*cur)))
2455 cur++;
2456
2457 while (IS_BLANK(*cur)) {
2458 while (IS_BLANK(*cur)) cur++;
2459
2460 if (!IS_LETTER(*cur) && (*cur != '_') &&
2461 (*cur != ':')) {
2462 return(0);
2463 }
2464
2465 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2466 (*cur == '.') || (*cur == '-') ||
2467 (*cur == '_') || (*cur == ':') ||
2468 (IS_COMBINING(*cur)) ||
2469 (IS_EXTENDER(*cur)))
2470 cur++;
2471 }
2472
2473 if (*cur != 0) return(0);
2474
2475 return(1);
2476}
2477
2478/**
2479 * xmlValidateNmtokenValue:
2480 * @value: an Mntoken value
2481 *
2482 * Validate that the given value match Nmtoken production
2483 *
2484 * [ VC: Name Token ]
2485 *
2486 * returns 1 if valid or 0 otherwise
2487 */
2488
2489int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002490xmlValidateNmtokenValue(const xmlChar *value) {
2491 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002492
2493 if (value == NULL) return(0);
2494 cur = value;
2495
2496 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2497 (*cur != '.') && (*cur != '-') &&
2498 (*cur != '_') && (*cur != ':') &&
2499 (!IS_COMBINING(*cur)) &&
2500 (!IS_EXTENDER(*cur)))
2501 return(0);
2502
2503 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2504 (*cur == '.') || (*cur == '-') ||
2505 (*cur == '_') || (*cur == ':') ||
2506 (IS_COMBINING(*cur)) ||
2507 (IS_EXTENDER(*cur)))
2508 cur++;
2509
2510 if (*cur != 0) return(0);
2511
2512 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002513}
2514
2515/**
2516 * xmlValidateNmtokensValue:
2517 * @value: an Mntokens value
2518 *
2519 * Validate that the given value match Nmtokens production
2520 *
2521 * [ VC: Name Token ]
2522 *
2523 * returns 1 if valid or 0 otherwise
2524 */
2525
2526int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002527xmlValidateNmtokensValue(const xmlChar *value) {
2528 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002529
2530 if (value == NULL) return(0);
2531 cur = value;
2532
Daniel Veillardcf461992000-03-14 18:30:20 +00002533 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002534 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2535 (*cur != '.') && (*cur != '-') &&
2536 (*cur != '_') && (*cur != ':') &&
2537 (!IS_COMBINING(*cur)) &&
2538 (!IS_EXTENDER(*cur)))
2539 return(0);
2540
2541 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2542 (*cur == '.') || (*cur == '-') ||
2543 (*cur == '_') || (*cur == ':') ||
2544 (IS_COMBINING(*cur)) ||
2545 (IS_EXTENDER(*cur)))
2546 cur++;
2547
2548 while (IS_BLANK(*cur)) {
2549 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002550 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002551
2552 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2553 (*cur != '.') && (*cur != '-') &&
2554 (*cur != '_') && (*cur != ':') &&
2555 (!IS_COMBINING(*cur)) &&
2556 (!IS_EXTENDER(*cur)))
2557 return(0);
2558
2559 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2560 (*cur == '.') || (*cur == '-') ||
2561 (*cur == '_') || (*cur == ':') ||
2562 (IS_COMBINING(*cur)) ||
2563 (IS_EXTENDER(*cur)))
2564 cur++;
2565 }
2566
2567 if (*cur != 0) return(0);
2568
2569 return(1);
2570}
2571
2572/**
2573 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002574 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002575 * @doc: a document instance
2576 * @nota: a notation definition
2577 *
2578 * Try to validate a single notation definition
2579 * basically it does the following checks as described by the
2580 * XML-1.0 recommendation:
2581 * - it seems that no validity constraing exist on notation declarations
2582 * But this function get called anyway ...
2583 *
2584 * returns 1 if valid or 0 otherwise
2585 */
2586
2587int
2588xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2589 xmlNotationPtr nota) {
2590 int ret = 1;
2591
2592 return(ret);
2593}
2594
2595/**
2596 * xmlValidateAttributeValue:
2597 * @type: an attribute type
2598 * @value: an attribute value
2599 *
2600 * Validate that the given attribute value match the proper production
2601 *
2602 * [ VC: ID ]
2603 * Values of type ID must match the Name production....
2604 *
2605 * [ VC: IDREF ]
2606 * Values of type IDREF must match the Name production, and values
2607 * of type IDREFS must match Names ...
2608 *
2609 * [ VC: Entity Name ]
2610 * Values of type ENTITY must match the Name production, values
2611 * of type ENTITIES must match Names ...
2612 *
2613 * [ VC: Name Token ]
2614 * Values of type NMTOKEN must match the Nmtoken production; values
2615 * of type NMTOKENS must match Nmtokens.
2616 *
2617 * returns 1 if valid or 0 otherwise
2618 */
2619
2620int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002621xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002622 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002623 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002624 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002625 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002626 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002627 case XML_ATTRIBUTE_IDREF:
2628 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002629 case XML_ATTRIBUTE_NOTATION:
2630 return(xmlValidateNameValue(value));
2631 case XML_ATTRIBUTE_NMTOKENS:
2632 case XML_ATTRIBUTE_ENUMERATION:
2633 return(xmlValidateNmtokensValue(value));
2634 case XML_ATTRIBUTE_NMTOKEN:
2635 return(xmlValidateNmtokenValue(value));
2636 case XML_ATTRIBUTE_CDATA:
2637 break;
2638 }
2639 return(1);
2640}
2641
2642/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002643 * xmlValidateAttributeValue2:
2644 * @ctxt: the validation context
2645 * @doc: the document
2646 * @name: the attribute name (used for error reporting only)
2647 * @type: the attribute type
2648 * @value: the attribute value
2649 *
2650 * Validate that the given attribute value match a given type.
2651 * This typically cannot be done before having finished parsing
2652 * the subsets.
2653 *
2654 * [ VC: IDREF ]
2655 * Values of type IDREF must match one of the declared IDs
2656 * Values of type IDREFS must match a sequence of the declared IDs
2657 * each Name must match the value of an ID attribute on some element
2658 * in the XML document; i.e. IDREF values must match the value of
2659 * some ID attribute
2660 *
2661 * [ VC: Entity Name ]
2662 * Values of type ENTITY must match one declared entity
2663 * Values of type ENTITIES must match a sequence of declared entities
2664 *
2665 * [ VC: Notation Attributes ]
2666 * all notation names in the declaration must be declared.
2667 *
2668 * returns 1 if valid or 0 otherwise
2669 */
2670
2671int
2672xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2673 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2674 int ret = 1;
2675 switch (type) {
2676 case XML_ATTRIBUTE_IDREFS:
2677 case XML_ATTRIBUTE_IDREF:
2678 case XML_ATTRIBUTE_ID:
2679 case XML_ATTRIBUTE_NMTOKENS:
2680 case XML_ATTRIBUTE_ENUMERATION:
2681 case XML_ATTRIBUTE_NMTOKEN:
2682 case XML_ATTRIBUTE_CDATA:
2683 break;
2684 case XML_ATTRIBUTE_ENTITY: {
2685 xmlEntityPtr ent;
2686
2687 ent = xmlGetDocEntity(doc, value);
2688 if (ent == NULL) {
2689 VERROR(ctxt->userData,
2690 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2691 name, value);
2692 ret = 0;
2693 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2694 VERROR(ctxt->userData,
2695 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2696 name, value);
2697 ret = 0;
2698 }
2699 break;
2700 }
2701 case XML_ATTRIBUTE_ENTITIES: {
2702 xmlChar *dup, *nam = NULL, *cur, save;
2703 xmlEntityPtr ent;
2704
2705 dup = xmlStrdup(value);
2706 if (dup == NULL)
2707 return(0);
2708 cur = dup;
2709 while (*cur != 0) {
2710 nam = cur;
2711 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2712 save = *cur;
2713 *cur = 0;
2714 ent = xmlGetDocEntity(doc, nam);
2715 if (ent == NULL) {
2716 VERROR(ctxt->userData,
2717 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2718 name, nam);
2719 ret = 0;
2720 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2721 VERROR(ctxt->userData,
2722 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2723 name, nam);
2724 ret = 0;
2725 }
2726 if (save == 0)
2727 break;
2728 *cur = save;
2729 while (IS_BLANK(*cur)) cur++;
2730 }
2731 xmlFree(dup);
2732 break;
2733 }
2734 case XML_ATTRIBUTE_NOTATION: {
2735 xmlNotationPtr nota;
2736
2737 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2738 if ((nota == NULL) && (doc->extSubset != NULL))
2739 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2740
2741 if (nota == NULL) {
2742 VERROR(ctxt->userData,
2743 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2744 name, value);
2745 ret = 0;
2746 }
2747 break;
2748 }
2749 }
2750 return(ret);
2751}
2752
2753/**
2754 * xmlValidNormalizeAttributeValue:
2755 * @doc: the document
2756 * @elem: the parent
2757 * @name: the attribute name
2758 * @value: the attribute value
2759 *
2760 * Does the validation related extra step of the normalization of attribute
2761 * values:
2762 *
2763 * If the declared value is not CDATA, then the XML processor must further
2764 * process the normalized attribute value by discarding any leading and
2765 * trailing space (#x20) characters, and by replacing sequences of space
2766 * (#x20) characters by single space (#x20) character.
2767 *
2768 * returns a new normalized string if normalization is needed, NULL otherwise
2769 * the caller must free the returned value.
2770 */
2771
2772xmlChar *
2773xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2774 const xmlChar *name, const xmlChar *value) {
2775 xmlChar *ret, *dst;
2776 const xmlChar *src;
Daniel Veillardbe803962000-06-28 23:40:59 +00002777 xmlAttributePtr attrDecl = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002778
2779 if (doc == NULL) return(NULL);
2780 if (elem == NULL) return(NULL);
2781 if (name == NULL) return(NULL);
2782 if (value == NULL) return(NULL);
2783
Daniel Veillardbe803962000-06-28 23:40:59 +00002784 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2785 xmlChar qname[500];
2786#ifdef HAVE_SNPRINTF
2787 snprintf((char *) qname, sizeof(qname), "%s:%s",
2788 elem->ns->prefix, elem->name);
2789#else
2790 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
2791#endif
2792 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2793 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2794 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2795 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002796 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2797 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2798 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2799
2800 if (attrDecl == NULL)
2801 return(NULL);
2802 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2803 return(NULL);
2804
2805 ret = xmlStrdup(value);
2806 if (ret == NULL)
2807 return(NULL);
2808 src = value;
2809 dst = ret;
2810 while (*src == 0x20) src++;
2811 while (*src != 0) {
2812 if (*src == 0x20) {
2813 while (*src == 0x20) src++;
2814 if (*src != 0)
2815 *dst++ = 0x20;
2816 } else {
2817 *dst++ = *src++;
2818 }
2819 }
2820 *dst = 0;
2821 return(ret);
2822}
2823
2824/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002825 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002826 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002827 * @doc: a document instance
2828 * @attr: an attribute definition
2829 *
2830 * Try to validate a single attribute definition
2831 * basically it does the following checks as described by the
2832 * XML-1.0 recommendation:
2833 * - [ VC: Attribute Default Legal ]
2834 * - [ VC: Enumeration ]
2835 * - [ VC: ID Attribute Default ]
2836 *
2837 * The ID/IDREF uniqueness and matching are done separately
2838 *
2839 * returns 1 if valid or 0 otherwise
2840 */
2841
2842int
2843xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2844 xmlAttributePtr attr) {
2845 int ret = 1;
2846 int val;
2847 CHECK_DTD;
2848 if(attr == NULL) return(1);
2849
2850 /* Attribute Default Legal */
2851 /* Enumeration */
2852 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002853 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002854 if (val == 0) {
2855 VERROR(ctxt->userData,
2856 "Syntax of default value for attribute %s on %s is not valid\n",
2857 attr->name, attr->elem);
2858 }
2859 ret &= val;
2860 }
2861
2862 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002863 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002864 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2865 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2866 VERROR(ctxt->userData,
2867 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2868 attr->name, attr->elem);
2869 ret = 0;
2870 }
2871
Daniel Veillardb96e6431999-08-29 21:02:19 +00002872 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002873 if (attr->atype == XML_ATTRIBUTE_ID) {
2874 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002875
2876 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002877 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002878 attr->elem);
2879 if (elem != NULL) {
2880 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002881 } else {
2882 xmlAttributeTablePtr table;
2883 int i;
2884
2885 /*
2886 * The attribute may be declared in the internal subset and the
2887 * element in the external subset.
2888 */
2889 nbId = 0;
2890 table = doc->intSubset->attributes;
2891 if (table != NULL) {
2892 for (i = 0;i < table->nb_attributes;i++) {
2893 if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2894 (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2895 nbId++;
2896 }
2897 }
2898 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002899 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002900 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002901 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002902 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2903 attr->elem, nbId, attr->name);
2904 } else if (doc->extSubset != NULL) {
2905 int extId = 0;
2906 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2907 if (elem != NULL) {
2908 extId = xmlScanIDAttributeDecl(NULL, elem);
2909 }
2910 if (extId > 1) {
2911 VERROR(ctxt->userData,
2912 "Element %s has %d ID attribute defined in the external subset : %s\n",
2913 attr->elem, extId, attr->name);
2914 } else if (extId + nbId > 1) {
2915 VERROR(ctxt->userData,
2916"Element %s has ID attributes defined in the internal and external subset : %s\n",
2917 attr->elem, attr->name);
2918 }
2919 }
2920 }
2921
2922 /* Validity Constraint: Enumeration */
2923 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2924 xmlEnumerationPtr tree = attr->tree;
2925 while (tree != NULL) {
2926 if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2927 tree = tree->next;
2928 }
2929 if (tree == NULL) {
2930 VERROR(ctxt->userData,
2931"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2932 attr->defaultValue, attr->name, attr->elem);
2933 ret = 0;
2934 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002935 }
2936
2937 return(ret);
2938}
2939
2940/**
2941 * xmlValidateElementDecl:
2942 * @ctxt: the validation context
2943 * @doc: a document instance
2944 * @elem: an element definition
2945 *
2946 * Try to validate a single element definition
2947 * basically it does the following checks as described by the
2948 * XML-1.0 recommendation:
2949 * - [ VC: One ID per Element Type ]
2950 * - [ VC: No Duplicate Types ]
2951 * - [ VC: Unique Element Type Declaration ]
2952 *
2953 * returns 1 if valid or 0 otherwise
2954 */
2955
2956int
2957xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2958 xmlElementPtr elem) {
2959 int ret = 1;
2960 xmlElementPtr tst;
2961
2962 CHECK_DTD;
2963
2964 if (elem == NULL) return(1);
2965
2966 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00002967 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002968 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002969 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002970
2971 cur = elem->content;
2972 while (cur != NULL) {
2973 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2974 if (cur->c1 == NULL) break;
2975 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2976 name = cur->c1->name;
2977 next = cur->c2;
2978 while (next != NULL) {
2979 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2980 if (!xmlStrcmp(next->name, name)) {
2981 VERROR(ctxt->userData,
2982 "Definition of %s has duplicate references of %s\n",
2983 elem->name, name);
2984 ret = 0;
2985 }
2986 break;
2987 }
2988 if (next->c1 == NULL) break;
2989 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2990 if (!xmlStrcmp(next->c1->name, name)) {
2991 VERROR(ctxt->userData,
2992 "Definition of %s has duplicate references of %s\n",
2993 elem->name, name);
2994 ret = 0;
2995 }
2996 next = next->c2;
2997 }
2998 }
2999 cur = cur->c2;
3000 }
3001 }
3002
3003 /* VC: Unique Element Type Declaration */
3004 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3005 if ((tst != NULL ) && (tst != elem)) {
3006 VERROR(ctxt->userData, "Redefinition of element %s\n",
3007 elem->name);
3008 ret = 0;
3009 }
3010 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3011 if ((tst != NULL ) && (tst != elem)) {
3012 VERROR(ctxt->userData, "Redefinition of element %s\n",
3013 elem->name);
3014 ret = 0;
3015 }
3016
3017 /* One ID per Element Type */
3018 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3019 ret = 0;
3020 }
3021 return(ret);
3022}
3023
3024/**
3025 * xmlValidateOneAttribute:
3026 * @ctxt: the validation context
3027 * @doc: a document instance
3028 * @elem: an element instance
3029 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00003030 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003031 *
3032 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00003033 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00003034 * XML-1.0 recommendation:
3035 * - [ VC: Attribute Value Type ]
3036 * - [ VC: Fixed Attribute Default ]
3037 * - [ VC: Entity Name ]
3038 * - [ VC: Name Token ]
3039 * - [ VC: ID ]
3040 * - [ VC: IDREF ]
3041 * - [ VC: Entity Name ]
3042 * - [ VC: Notation Attributes ]
3043 *
3044 * The ID/IDREF uniqueness and matching are done separately
3045 *
3046 * returns 1 if valid or 0 otherwise
3047 */
3048
3049int
3050xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003051 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003052 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00003053 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003054 int val;
3055 int ret = 1;
3056
3057 CHECK_DTD;
3058 if ((elem == NULL) || (elem->name == NULL)) return(0);
3059 if ((attr == NULL) || (attr->name == NULL)) return(0);
3060
Daniel Veillardbe803962000-06-28 23:40:59 +00003061 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3062 xmlChar qname[500];
3063#ifdef HAVE_SNPRINTF
3064 snprintf((char *) qname, sizeof(qname), "%s:%s",
3065 elem->ns->prefix, elem->name);
3066#else
3067 sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
3068#endif
3069 if (attr->ns != NULL) {
3070 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3071 attr->name, attr->ns->prefix);
3072 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3073 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3074 attr->name, attr->ns->prefix);
3075 } else {
3076 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3077 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3078 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3079 qname, attr->name);
3080 }
3081 }
3082 if (attrDecl == NULL) {
3083 if (attr->ns != NULL) {
3084 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3085 attr->name, attr->ns->prefix);
3086 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3087 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3088 attr->name, attr->ns->prefix);
3089 } else {
3090 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3091 elem->name, attr->name);
3092 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3093 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3094 elem->name, attr->name);
3095 }
3096 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003097
3098
3099 /* Validity Constraint: Attribute Value Type */
3100 if (attrDecl == NULL) {
3101 VERROR(ctxt->userData,
3102 "No declaration for attribute %s on element %s\n",
3103 attr->name, elem->name);
3104 return(0);
3105 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003106 attr->atype = attrDecl->atype;
3107
3108 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003109 if (val == 0) {
3110 VERROR(ctxt->userData,
3111 "Syntax of value for attribute %s on %s is not valid\n",
3112 attr->name, elem->name);
3113 ret = 0;
3114 }
3115
Daniel Veillardcf461992000-03-14 18:30:20 +00003116 /* Validity constraint: Fixed Attribute Default */
3117 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3118 if (xmlStrcmp(value, attrDecl->defaultValue)) {
3119 VERROR(ctxt->userData,
3120 "Value for attribute %s on %s is differnt from default \"%s\"\n",
3121 attr->name, elem->name, attrDecl->defaultValue);
3122 ret = 0;
3123 }
3124 }
3125
Daniel Veillardb96e6431999-08-29 21:02:19 +00003126 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00003127 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003128 xmlAddID(ctxt, doc, value, attr);
3129 }
3130
Daniel Veillardcf461992000-03-14 18:30:20 +00003131 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3132 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003133 xmlAddRef(ctxt, doc, value, attr);
3134 }
3135
Daniel Veillardb05deb71999-08-10 19:04:08 +00003136 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00003137 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003138 xmlEnumerationPtr tree = attrDecl->tree;
3139 xmlNotationPtr nota;
3140
3141 /* First check that the given NOTATION was declared */
3142 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3143 if (nota == NULL)
3144 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3145
3146 if (nota == NULL) {
3147 VERROR(ctxt->userData,
3148 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3149 value, attr->name, elem->name);
3150 ret = 0;
3151 }
3152
3153 /* Second, verify that it's among the list */
3154 while (tree != NULL) {
3155 if (!xmlStrcmp(tree->name, value)) break;
3156 tree = tree->next;
3157 }
3158 if (tree == NULL) {
3159 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003160"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003161 value, attr->name, elem->name);
3162 ret = 0;
3163 }
3164 }
3165
3166 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00003167 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003168 xmlEnumerationPtr tree = attrDecl->tree;
3169 while (tree != NULL) {
3170 if (!xmlStrcmp(tree->name, value)) break;
3171 tree = tree->next;
3172 }
3173 if (tree == NULL) {
3174 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003175 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00003176 value, attr->name, elem->name);
3177 ret = 0;
3178 }
3179 }
3180
3181 /* Fixed Attribute Default */
3182 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3183 (xmlStrcmp(attrDecl->defaultValue, value))) {
3184 VERROR(ctxt->userData,
3185 "Value for attribute %s on %s must be \"%s\"\n",
3186 attr->name, elem->name, attrDecl->defaultValue);
3187 ret = 0;
3188 }
3189
Daniel Veillardcf461992000-03-14 18:30:20 +00003190 /* Extra check for the attribute value */
3191 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3192 attrDecl->atype, value);
3193
Daniel Veillardb05deb71999-08-10 19:04:08 +00003194 return(ret);
3195}
3196
3197int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3198 xmlElementContentPtr cont);
3199
3200/**
3201 * xmlValidateElementTypeExpr:
3202 * @ctxt: the validation context
3203 * @child: pointer to the child list
3204 * @cont: pointer to the content declaration
3205 *
3206 * Try to validate the content of an element of type element
3207 * but don't handle the occurence factor
3208 *
3209 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3210 * also update child value in-situ.
3211 */
3212
3213int
3214xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3215 xmlElementContentPtr cont) {
3216 xmlNodePtr cur;
3217 int ret = 1;
3218
3219 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003220 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003221 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003222 if ((*child)->type == XML_ENTITY_REF_NODE) {
3223 /*
3224 * If there is an entity declared an it's not empty
3225 * Push the current node on the stack and process with the
3226 * entity content.
3227 */
3228 if (((*child)->children != NULL) &&
3229 ((*child)->children->children != NULL)) {
3230 nodeVPush(ctxt, *child);
3231 *child = (*child)->children->children;
3232 } else
3233 *child = (*child)->next;
3234 continue;
3235 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003236 if ((*child)->type == XML_PI_NODE) {
3237 *child = (*child)->next;
3238 continue;
3239 }
3240 if ((*child)->type == XML_COMMENT_NODE) {
3241 *child = (*child)->next;
3242 continue;
3243 }
3244 else if ((*child)->type != XML_ELEMENT_NODE) {
3245 return(-1);
3246 }
3247 break;
3248 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003249 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003250 switch (cont->type) {
3251 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00003252 if (*child == NULL) return(0);
3253 if ((*child)->type == XML_TEXT_NODE) return(1);
3254 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003255 case XML_ELEMENT_CONTENT_ELEMENT:
3256 if (*child == NULL) return(0);
3257 ret = (!xmlStrcmp((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00003258 if (ret == 1) {
3259 while ((*child)->next == NULL) {
3260 if (((*child)->parent != NULL) &&
3261 ((*child)->parent->type == XML_ENTITY_DECL)) {
3262 *child = nodeVPop(ctxt);
3263 } else
3264 break;
3265 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003266 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003267 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003268 return(ret);
3269 case XML_ELEMENT_CONTENT_OR:
3270 cur = *child;
3271 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3272 if (ret == -1) return(-1);
3273 if (ret == 1) {
3274 return(1);
3275 }
3276 /* rollback and retry the other path */
3277 *child = cur;
3278 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3279 if (ret == -1) return(-1);
3280 if (ret == 0) {
3281 *child = cur;
3282 return(0);
3283 }
3284 return(1);
3285 case XML_ELEMENT_CONTENT_SEQ:
3286 cur = *child;
3287 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3288 if (ret == -1) return(-1);
3289 if (ret == 0) {
3290 *child = cur;
3291 return(0);
3292 }
3293 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3294 if (ret == -1) return(-1);
3295 if (ret == 0) {
3296 *child = cur;
3297 return(0);
3298 }
3299 return(1);
3300 }
3301 return(ret);
3302}
3303
3304/**
3305 * xmlValidateElementTypeElement:
3306 * @ctxt: the validation context
3307 * @child: pointer to the child list
3308 * @cont: pointer to the content declaration
3309 *
3310 * Try to validate the content of an element of type element
3311 * yeah, Yet Another Regexp Implementation, and recursive
3312 *
3313 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3314 * also update child and content values in-situ.
3315 */
3316
3317int
3318xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3319 xmlElementContentPtr cont) {
3320 xmlNodePtr cur;
3321 int ret = 1;
3322
3323 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003324
3325 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003326 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003327 if ((*child)->type == XML_ENTITY_REF_NODE) {
3328 /*
3329 * If there is an entity declared an it's not empty
3330 * Push the current node on the stack and process with the
3331 * entity content.
3332 */
3333 if (((*child)->children != NULL) &&
3334 ((*child)->children->children != NULL)) {
3335 nodeVPush(ctxt, *child);
3336 *child = (*child)->children->children;
3337 } else
3338 *child = (*child)->next;
3339 continue;
3340 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003341 if ((*child)->type == XML_PI_NODE) {
3342 *child = (*child)->next;
3343 continue;
3344 }
3345 if ((*child)->type == XML_COMMENT_NODE) {
3346 *child = (*child)->next;
3347 continue;
3348 }
3349 else if ((*child)->type != XML_ELEMENT_NODE) {
3350 return(-1);
3351 }
3352 break;
3353 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003354 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003355 cur = *child;
3356 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3357 if (ret == -1) return(-1);
3358 switch (cont->ocur) {
3359 case XML_ELEMENT_CONTENT_ONCE:
3360 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003361 /* skip ignorable elems */
3362 while ((*child != NULL) &&
3363 (((*child)->type == XML_PI_NODE) ||
3364 ((*child)->type == XML_COMMENT_NODE))) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003365 while ((*child)->next == NULL) {
3366 if (((*child)->parent != NULL) &&
3367 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3368 *child = (*child)->parent;
3369 } else
3370 break;
3371 }
3372 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003373 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003374 return(1);
3375 }
3376 *child = cur;
3377 return(0);
3378 case XML_ELEMENT_CONTENT_OPT:
3379 if (ret == 0) {
3380 *child = cur;
3381 return(1);
3382 }
3383 break;
3384 case XML_ELEMENT_CONTENT_MULT:
3385 if (ret == 0) {
3386 *child = cur;
3387 break;
3388 }
3389 /* no break on purpose */
3390 case XML_ELEMENT_CONTENT_PLUS:
3391 if (ret == 0) {
3392 *child = cur;
3393 return(0);
3394 }
3395 do {
3396 cur = *child;
3397 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3398 } while (ret == 1);
3399 if (ret == -1) return(-1);
3400 *child = cur;
3401 break;
3402 }
3403 while (*child != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003404 if ((*child)->type == XML_ENTITY_REF_NODE) {
3405 /*
3406 * If there is an entity declared an it's not empty
3407 * Push the current node on the stack and process with the
3408 * entity content.
3409 */
3410 if (((*child)->children != NULL) &&
3411 ((*child)->children->children != NULL)) {
3412 nodeVPush(ctxt, *child);
3413 *child = (*child)->children->children;
3414 } else
3415 *child = (*child)->next;
3416 continue;
3417 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003418 if ((*child)->type == XML_PI_NODE) {
3419 *child = (*child)->next;
3420 continue;
3421 }
3422 if ((*child)->type == XML_COMMENT_NODE) {
3423 *child = (*child)->next;
3424 continue;
3425 }
3426 else if ((*child)->type != XML_ELEMENT_NODE) {
3427 return(-1);
3428 }
3429 break;
3430 }
3431 return(1);
3432}
3433
3434/**
3435 * xmlSprintfElementChilds:
3436 * @buf: an output buffer
3437 * @content: An element
3438 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3439 *
3440 * This will dump the list of childs to the buffer
3441 * Intended just for the debug routine
3442 */
3443void
3444xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3445 xmlNodePtr cur;
3446
3447 if (node == NULL) return;
3448 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003449 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003450 while (cur != NULL) {
3451 switch (cur->type) {
3452 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003453 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003454 if (cur->next != NULL)
3455 strcat(buf, " ");
3456 break;
3457 case XML_TEXT_NODE:
3458 case XML_CDATA_SECTION_NODE:
3459 case XML_ENTITY_REF_NODE:
3460 strcat(buf, "CDATA");
3461 if (cur->next != NULL)
3462 strcat(buf, " ");
3463 break;
3464 case XML_ATTRIBUTE_NODE:
3465 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003466 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003467 case XML_DOCUMENT_TYPE_NODE:
3468 case XML_DOCUMENT_FRAG_NODE:
3469 case XML_NOTATION_NODE:
3470 strcat(buf, "???");
3471 if (cur->next != NULL)
3472 strcat(buf, " ");
3473 break;
3474 case XML_ENTITY_NODE:
3475 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003476 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003477 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003478 case XML_ELEMENT_DECL:
3479 case XML_ATTRIBUTE_DECL:
3480 case XML_ENTITY_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003481 break;
3482 }
3483 cur = cur->next;
3484 }
3485 if (glob) strcat(buf, ")");
3486}
3487
3488
3489/**
3490 * xmlValidateOneElement:
3491 * @ctxt: the validation context
3492 * @doc: a document instance
3493 * @elem: an element instance
3494 *
3495 * Try to validate a single element and it's attributes,
3496 * basically it does the following checks as described by the
3497 * XML-1.0 recommendation:
3498 * - [ VC: Element Valid ]
3499 * - [ VC: Required Attribute ]
3500 * Then call xmlValidateOneAttribute() for each attribute present.
3501 *
3502 * The ID/IDREF checkings are done separately
3503 *
3504 * returns 1 if valid or 0 otherwise
3505 */
3506
3507int
3508xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3509 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003510 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003511 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003512 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003513 xmlNodePtr child;
3514 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003515 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003516
3517 CHECK_DTD;
3518
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003519 if (elem == NULL) return(0);
3520 if (elem->type == XML_TEXT_NODE) {
3521 }
3522 switch (elem->type) {
3523 case XML_ATTRIBUTE_NODE:
3524 VERROR(ctxt->userData,
3525 "Attribute element not expected here\n");
3526 return(0);
3527 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003528 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003529 VERROR(ctxt->userData, "Text element has childs !\n");
3530 return(0);
3531 }
3532 if (elem->properties != NULL) {
3533 VERROR(ctxt->userData, "Text element has attributes !\n");
3534 return(0);
3535 }
3536 if (elem->ns != NULL) {
3537 VERROR(ctxt->userData, "Text element has namespace !\n");
3538 return(0);
3539 }
3540 if (elem->ns != NULL) {
3541 VERROR(ctxt->userData,
3542 "Text element carries namespace definitions !\n");
3543 return(0);
3544 }
3545 if (elem->content == NULL) {
3546 VERROR(ctxt->userData,
3547 "Text element has no content !\n");
3548 return(0);
3549 }
3550 return(1);
3551 case XML_CDATA_SECTION_NODE:
3552 case XML_ENTITY_REF_NODE:
3553 case XML_PI_NODE:
3554 case XML_COMMENT_NODE:
3555 return(1);
3556 case XML_ENTITY_NODE:
3557 VERROR(ctxt->userData,
3558 "Entity element not expected here\n");
3559 return(0);
3560 case XML_NOTATION_NODE:
3561 VERROR(ctxt->userData,
3562 "Notation element not expected here\n");
3563 return(0);
3564 case XML_DOCUMENT_NODE:
3565 case XML_DOCUMENT_TYPE_NODE:
3566 case XML_DOCUMENT_FRAG_NODE:
3567 VERROR(ctxt->userData,
3568 "Document element not expected here\n");
3569 return(0);
3570 case XML_HTML_DOCUMENT_NODE:
3571 VERROR(ctxt->userData,
3572 "\n");
3573 return(0);
3574 case XML_ELEMENT_NODE:
3575 break;
3576 default:
3577 VERROR(ctxt->userData,
3578 "unknown element type %d\n", elem->type);
3579 return(0);
3580 }
3581 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003582
Daniel Veillardbe803962000-06-28 23:40:59 +00003583 /*
3584 * Fetch the declaration for the qualified name
3585 */
3586 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3587 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3588 elem->name, elem->ns->prefix);
3589 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3590 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3591 elem->name, elem->ns->prefix);
3592 }
3593
3594 /*
3595 * Fetch the declaration for the non qualified name
3596 */
3597 if (elemDecl == NULL) {
3598 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3599 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3600 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3601 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003602 if (elemDecl == NULL) {
3603 VERROR(ctxt->userData, "No declaration for element %s\n",
3604 elem->name);
3605 return(0);
3606 }
3607
3608 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003609 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003610 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003611 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003612 VERROR(ctxt->userData,
3613 "Element %s was declared EMPTY this one has content\n",
3614 elem->name);
3615 ret = 0;
3616 }
3617 break;
3618 case XML_ELEMENT_TYPE_ANY:
3619 /* I don't think anything is required then */
3620 break;
3621 case XML_ELEMENT_TYPE_MIXED:
3622 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003623 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003624 while (child != NULL) {
3625 if (child->type == XML_ELEMENT_NODE) {
3626 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003627 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3628 xmlChar qname[500];
3629#ifdef HAVE_SNPRINTF
3630 snprintf((char *) qname, sizeof(qname), "%s:%s",
3631 child->ns->prefix, child->name);
3632#else
3633 sprintf(qname, "%s:%s", child->name, child->ns->prefix);
3634#endif
3635 cont = elemDecl->content;
3636 while (cont != NULL) {
3637 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3638 if (!xmlStrcmp(cont->name, qname)) break;
3639 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3640 (cont->c1 != NULL) &&
3641 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
3642 if (!xmlStrcmp(cont->c1->name, qname)) break;
3643 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3644 (cont->c1 == NULL) ||
3645 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3646 /* Internal error !!! */
3647 fprintf(stderr, "Internal: MIXED struct bad\n");
3648 break;
3649 }
3650 cont = cont->c2;
3651 }
3652 if (cont != NULL)
3653 goto child_ok;
3654 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003655 cont = elemDecl->content;
3656 while (cont != NULL) {
3657 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3658 if (!xmlStrcmp(cont->name, name)) break;
3659 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3660 (cont->c1 != NULL) &&
3661 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3662 if (!xmlStrcmp(cont->c1->name, name)) break;
3663 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3664 (cont->c1 == NULL) ||
3665 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3666 /* Internal error !!! */
3667 fprintf(stderr, "Internal: MIXED struct bad\n");
3668 break;
3669 }
3670 cont = cont->c2;
3671 }
3672 if (cont == NULL) {
3673 VERROR(ctxt->userData,
3674 "Element %s is not declared in %s list of possible childs\n",
3675 name, elem->name);
3676 ret = 0;
3677 }
3678 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003679child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003680 child = child->next;
3681 }
3682 break;
3683 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003684 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003685 cont = elemDecl->content;
3686 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3687 if ((ret == 0) || (child != NULL)) {
3688 char expr[1000];
3689 char list[2000];
3690
3691 expr[0] = 0;
3692 xmlSprintfElementContent(expr, cont, 1);
3693 list[0] = 0;
3694 xmlSprintfElementChilds(list, elem, 1);
3695
3696 VERROR(ctxt->userData,
3697 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3698 elem->name, expr, list);
3699 ret = 0;
3700 }
3701 break;
3702 }
3703
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003704 /* [ VC: Required Attribute ] */
3705 attr = elemDecl->attributes;
3706 while (attr != NULL) {
3707 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3708 xmlAttrPtr attrib;
3709 int qualified = -1;
3710
3711 attrib = elem->properties;
3712 while (attrib != NULL) {
3713 if (!xmlStrcmp(attrib->name, attr->name)) {
3714 if (attr->prefix != NULL) {
3715 xmlNsPtr nameSpace = attrib->ns;
3716
3717 if (nameSpace == NULL)
3718 nameSpace = elem->ns;
3719 /*
3720 * qualified names handling is problematic, having a
3721 * different prefix should be possible but DTDs don't
3722 * allow to define the URI instead of the prefix :-(
3723 */
3724 if (nameSpace == NULL) {
3725 if (qualified < 0)
3726 qualified = 0;
3727 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3728 if (qualified < 1)
3729 qualified = 1;
3730 } else
3731 goto found;
3732 } else {
3733 /*
3734 * We should allow applications to define namespaces
3735 * for their application even if the DTD doesn't
3736 * carry one, otherwise, basically we would always
3737 * break.
3738 */
3739 goto found;
3740 }
3741 }
3742 attrib = attrib->next;
3743 }
3744 if (qualified == -1) {
3745 if (attr->prefix == NULL) {
3746 VERROR(ctxt->userData,
3747 "Element %s doesn't carry attribute %s\n",
3748 elem->name, attr->name);
3749 } else {
3750 VERROR(ctxt->userData,
3751 "Element %s doesn't carry attribute %s:%s\n",
3752 elem->name, attr->prefix,attr->name);
3753 }
3754 } else if (qualified == 0) {
3755 VWARNING(ctxt->userData,
3756 "Element %s required attribute %s:%s has no prefix\n",
3757 elem->name, attr->prefix,attr->name);
3758 } else if (qualified == 1) {
3759 VWARNING(ctxt->userData,
3760 "Element %s required attribute %s:%s has different prefix\n",
3761 elem->name, attr->prefix,attr->name);
3762 }
3763 }
3764found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003765 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003766 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003767 return(ret);
3768}
3769
3770/**
3771 * xmlValidateRoot:
3772 * @ctxt: the validation context
3773 * @doc: a document instance
3774 *
3775 * Try to validate a the root element
3776 * basically it does the following check as described by the
3777 * XML-1.0 recommendation:
3778 * - [ VC: Root Element Type ]
3779 * it doesn't try to recurse or apply other check to the element
3780 *
3781 * returns 1 if valid or 0 otherwise
3782 */
3783
3784int
3785xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003786 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003787 if (doc == NULL) return(0);
3788
3789 if ((doc->intSubset == NULL) ||
3790 (doc->intSubset->name == NULL)) {
3791 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3792 return(0);
3793 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003794 root = xmlDocGetRootElement(doc);
3795 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003796 VERROR(ctxt->userData, "Not valid: no root element\n");
3797 return(0);
3798 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003799
3800 /*
3801 * Check first the document root against the NQName
3802 */
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003803 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003804 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3805 xmlChar qname[500];
3806#ifdef HAVE_SNPRINTF
3807 snprintf((char *) qname, sizeof(qname), "%s:%s",
3808 root->ns->prefix, root->name);
3809#else
3810 sprintf(qname, "%s:%s", root->name, root->ns->prefix);
3811#endif
3812 if (!xmlStrcmp(doc->intSubset->name, qname))
3813 goto name_ok;
3814 }
3815 if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
3816 (!xmlStrcmp(root->name, BAD_CAST "html")))
3817 goto name_ok;
3818 VERROR(ctxt->userData,
3819 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3820 root->name, doc->intSubset->name);
3821 return(0);
3822
Daniel Veillardb05deb71999-08-10 19:04:08 +00003823 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003824name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003825 return(1);
3826}
3827
3828
3829/**
3830 * xmlValidateElement:
3831 * @ctxt: the validation context
3832 * @doc: a document instance
3833 * @elem: an element instance
3834 *
3835 * Try to validate the subtree under an element
3836 *
3837 * returns 1 if valid or 0 otherwise
3838 */
3839
3840int
3841xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003842 xmlNodePtr child;
3843 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003844 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003845 int ret = 1;
3846
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003847 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003848 CHECK_DTD;
3849
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003850 ret &= xmlValidateOneElement(ctxt, doc, elem);
3851 attr = elem->properties;
3852 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003853 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003854 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3855 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003856 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003857 attr= attr->next;
3858 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003859 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003860 while (child != NULL) {
3861 ret &= xmlValidateElement(ctxt, doc, child);
3862 child = child->next;
3863 }
3864
3865 return(ret);
3866}
3867
3868/**
3869 * xmlValidateDocumentFinal:
3870 * @ctxt: the validation context
3871 * @doc: a document instance
3872 *
3873 * Does the final step for the document validation once all the
3874 * incremental validation steps have been completed
3875 *
3876 * basically it does the following checks described by the XML Rec
3877 *
3878 *
3879 * returns 1 if valid or 0 otherwise
3880 */
3881
3882int
3883xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3884 int ret = 1, i;
3885 xmlRefTablePtr table;
3886 xmlAttrPtr id;
3887
3888 if (doc == NULL) {
3889 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3890 return(0);
3891 }
3892
3893 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003894 * Check all the NOTATION/NOTATIONS attributes
3895 */
3896 /*
3897 * Check all the ENTITY/ENTITIES attributes definition for validity
3898 */
3899 /*
3900 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003901 */
3902 table = doc->refs;
3903 if (table != NULL) {
3904 for (i = 0; i < table->nb_refs; i++) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003905 if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3906 id = xmlGetID(doc, table->table[i]->value);
3907 if (id == NULL) {
3908 VERROR(ctxt->userData,
3909 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3910 table->table[i]->attr->name, table->table[i]->value);
3911 ret = 0;
3912 }
3913 } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
3914 xmlChar *dup, *name = NULL, *cur, save;
3915
3916 dup = xmlStrdup(table->table[i]->value);
3917 if (dup == NULL)
3918 return(0);
3919 cur = dup;
3920 while (*cur != 0) {
3921 name = cur;
3922 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3923 save = *cur;
3924 *cur = 0;
3925 id = xmlGetID(doc, name);
3926 if (id == NULL) {
3927 VERROR(ctxt->userData,
3928 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3929 table->table[i]->attr->name, name);
3930 ret = 0;
3931 }
3932 if (save == 0)
3933 break;
3934 *cur = save;
3935 while (IS_BLANK(*cur)) cur++;
3936 }
3937 xmlFree(dup);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003938 }
3939 }
3940 }
3941 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003942}
3943
3944/**
3945 * xmlValidateDtd:
3946 * @ctxt: the validation context
3947 * @doc: a document instance
3948 * @dtd: a dtd instance
3949 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003950 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003951 *
3952 * basically it does check all the definitions in the DtD.
3953 *
3954 * returns 1 if valid or 0 otherwise
3955 */
3956
3957int
3958xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003959 int ret;
3960 xmlDtdPtr oldExt;
3961 xmlNodePtr root;
3962
3963 if (dtd == NULL) return(0);
3964 if (doc == NULL) return(0);
3965 oldExt = doc->extSubset;
3966 doc->extSubset = dtd;
3967 ret = xmlValidateRoot(ctxt, doc);
3968 if (ret == 0) {
3969 doc->extSubset = oldExt;
3970 return(ret);
3971 }
3972 root = xmlDocGetRootElement(doc);
3973 ret = xmlValidateElement(ctxt, doc, root);
3974 ret &= xmlValidateDocumentFinal(ctxt, doc);
3975 doc->extSubset = oldExt;
3976 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003977}
3978
3979/**
Daniel Veillardcf461992000-03-14 18:30:20 +00003980 * xmlValidateDtdFinal:
3981 * @ctxt: the validation context
3982 * @doc: a document instance
3983 *
3984 * Does the final step for the dtds validation once all the
3985 * subsets have been parsed
3986 *
3987 * basically it does the following checks described by the XML Rec
3988 * - check that ENTITY and ENTITIES type attributes default or
3989 * possible values matches one of the defined entities.
3990 * - check that NOTATION type attributes default or
3991 * possible values matches one of the defined notations.
3992 *
3993 * returns 1 if valid or 0 otherwise
3994 */
3995
3996int
3997xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3998 int ret = 1, i;
3999 xmlDtdPtr dtd;
4000 xmlAttributeTablePtr table;
4001 xmlAttributePtr cur;
4002
4003 if (doc == NULL) return(0);
4004 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4005 return(0);
4006 dtd = doc->intSubset;
4007 if ((dtd != NULL) && (dtd->attributes != NULL)) {
4008 table = dtd->attributes;
4009
4010 for (i = 0;i < table->nb_attributes;i++) {
4011 cur = table->table[i];
4012 switch (cur->atype) {
4013 case XML_ATTRIBUTE_CDATA:
4014 case XML_ATTRIBUTE_ID:
4015 case XML_ATTRIBUTE_IDREF :
4016 case XML_ATTRIBUTE_IDREFS:
4017 case XML_ATTRIBUTE_NMTOKEN:
4018 case XML_ATTRIBUTE_NMTOKENS:
4019 case XML_ATTRIBUTE_ENUMERATION:
4020 break;
4021 case XML_ATTRIBUTE_ENTITY:
4022 case XML_ATTRIBUTE_ENTITIES:
4023 case XML_ATTRIBUTE_NOTATION:
4024 if (cur->defaultValue != NULL) {
4025 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4026 cur->atype, cur->defaultValue);
4027 }
4028 if (cur->tree != NULL) {
4029 xmlEnumerationPtr tree = cur->tree;
4030 while (tree != NULL) {
4031 ret &= xmlValidateAttributeValue2(ctxt, doc,
4032 cur->name, cur->atype, tree->name);
4033 tree = tree->next;
4034 }
4035 }
4036 }
4037 }
4038 }
4039 dtd = doc->extSubset;
4040 if ((dtd != NULL) && (dtd->attributes != NULL)) {
4041 table = dtd->attributes;
4042
4043 for (i = 0;i < table->nb_attributes;i++) {
4044 cur = table->table[i];
4045 switch (cur->atype) {
4046 case XML_ATTRIBUTE_CDATA:
4047 case XML_ATTRIBUTE_ID:
4048 case XML_ATTRIBUTE_IDREF :
4049 case XML_ATTRIBUTE_IDREFS:
4050 case XML_ATTRIBUTE_NMTOKEN:
4051 case XML_ATTRIBUTE_NMTOKENS:
4052 case XML_ATTRIBUTE_ENUMERATION:
4053 break;
4054 case XML_ATTRIBUTE_ENTITY:
4055 case XML_ATTRIBUTE_ENTITIES:
4056 case XML_ATTRIBUTE_NOTATION:
4057 if (cur->defaultValue != NULL) {
4058 ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4059 cur->atype, cur->defaultValue);
4060 }
4061 if (cur->tree != NULL) {
4062 xmlEnumerationPtr tree = cur->tree;
4063 while (tree != NULL) {
4064 ret &= xmlValidateAttributeValue2(ctxt, doc,
4065 cur->name, cur->atype, tree->name);
4066 tree = tree->next;
4067 }
4068 }
4069 }
4070 }
4071 }
4072 return(ret);
4073}
4074
4075/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00004076 * xmlValidateDocument:
4077 * @ctxt: the validation context
4078 * @doc: a document instance
4079 *
4080 * Try to validate the document instance
4081 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004082 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00004083 * i.e. validates the internal and external subset (if present)
4084 * and validate the document tree.
4085 *
4086 * returns 1 if valid or 0 otherwise
4087 */
4088
4089int
4090xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004091 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004092 xmlNodePtr root;
4093
4094 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4095 return(0);
4096 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4097 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4098 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4099 doc->intSubset->SystemID);
4100 if (doc->extSubset == NULL) {
4101 if (doc->intSubset->SystemID != NULL) {
4102 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004103 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004104 doc->intSubset->SystemID);
4105 } else {
4106 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00004107 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004108 doc->intSubset->ExternalID);
4109 }
4110 return(0);
4111 }
4112 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004113
Daniel Veillardcf461992000-03-14 18:30:20 +00004114 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004115 if (!xmlValidateRoot(ctxt, doc)) return(0);
4116
Daniel Veillard944b5ff1999-12-15 19:08:24 +00004117 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00004118 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00004119 ret &= xmlValidateDocumentFinal(ctxt, doc);
4120 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004121}
4122
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004123
4124/************************************************************************
4125 * *
4126 * Routines for dynamic validation editing *
4127 * *
4128 ************************************************************************/
4129
4130/**
4131 * xmlValidGetPotentialChildren:
4132 * @ctree: an element content tree
4133 * @list: an array to store the list of child names
4134 * @len: a pointer to the number of element in the list
4135 * @max: the size of the array
4136 *
4137 * Build/extend a list of potential children allowed by the content tree
4138 *
4139 * returns the number of element in the list, or -1 in case of error.
4140 */
4141
4142int
4143xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4144 int *len, int max) {
4145 int i;
4146
4147 if ((ctree == NULL) || (list == NULL) || (len == NULL))
4148 return(-1);
4149 if (*len >= max) return(*len);
4150
4151 switch (ctree->type) {
4152 case XML_ELEMENT_CONTENT_PCDATA:
4153 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00004154 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
4155 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004156 break;
4157 case XML_ELEMENT_CONTENT_ELEMENT:
4158 for (i = 0; i < *len;i++)
4159 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
4160 list[(*len)++] = ctree->name;
4161 break;
4162 case XML_ELEMENT_CONTENT_SEQ:
4163 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4164 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4165 break;
4166 case XML_ELEMENT_CONTENT_OR:
4167 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4168 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4169 break;
4170 }
4171
4172 return(*len);
4173}
4174
4175/**
4176 * xmlValidGetValidElements:
4177 * @prev: an element to insert after
4178 * @next: an element to insert next
4179 * @list: an array to store the list of child names
4180 * @max: the size of the array
4181 *
4182 * This function returns the list of authorized children to insert
4183 * within an existing tree while respecting the validity constraints
4184 * forced by the Dtd. The insertion point is defined using @prev and
4185 * @next in the following ways:
4186 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4187 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4188 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4189 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4190 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4191 *
4192 * pointers to the element names are inserted at the beginning of the array
4193 * and do not need to be freed.
4194 *
4195 * returns the number of element in the list, or -1 in case of error. If
4196 * the function returns the value @max the caller is invited to grow the
4197 * receiving array and retry.
4198 */
4199
4200int
4201xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4202 int max) {
4203 int nb_valid_elements = 0;
4204 const xmlChar *elements[256];
4205 int nb_elements = 0, i;
4206
4207 xmlNode *ref_node;
4208 xmlNode *parent;
4209 xmlNode *test_node;
4210
4211 xmlNode *prev_next;
4212 xmlNode *next_prev;
4213 xmlNode *parent_childs;
4214 xmlNode *parent_last;
4215
4216 xmlElement *element_desc;
4217
4218 if (prev == NULL && next == NULL)
4219 return(-1);
4220
4221 if (list == NULL) return(-1);
4222 if (max <= 0) return(-1);
4223
4224 nb_valid_elements = 0;
4225 ref_node = prev ? prev : next;
4226 parent = ref_node->parent;
4227
4228 /*
4229 * Retrieves the parent element declaration
4230 */
4231 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4232 parent->name);
4233 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4234 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4235 parent->name);
4236 if (element_desc == NULL) return(-1);
4237
4238 /*
4239 * Do a backup of the current tree structure
4240 */
4241 prev_next = prev ? prev->next : NULL;
4242 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00004243 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004244 parent_last = parent->last;
4245
4246 /*
4247 * Creates a dummy node and insert it into the tree
4248 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00004249 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004250 test_node->doc = ref_node->doc;
4251 test_node->parent = parent;
4252 test_node->prev = prev;
4253 test_node->next = next;
4254
4255 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00004256 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004257
4258 if (next) next->prev = test_node;
4259 else parent->last = test_node;
4260
4261 /*
4262 * Insert each potential child node and check if the parent is
4263 * still valid
4264 */
4265 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4266 elements, &nb_elements, 256);
4267
4268 for (i = 0;i < nb_elements;i++) {
4269 test_node->name = elements[i];
4270 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4271 int j;
4272
4273 for (j = 0; j < nb_valid_elements;j++)
4274 if (!xmlStrcmp(elements[i], list[j])) break;
4275 list[nb_valid_elements++] = elements[i];
4276 if (nb_valid_elements >= max) break;
4277 }
4278 }
4279
4280 /*
4281 * Restore the tree structure
4282 */
4283 if (prev) prev->next = prev_next;
4284 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004285 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004286 parent->last = parent_last;
4287
4288 return(nb_valid_elements);
4289}